package com.github.mikephil.charting.charts; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.PointF; import android.graphics.RectF; import android.util.AttributeSet; import com.github.mikephil.charting.components.XAxis; import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.components.YAxis.AxisDependency; import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.RadarData; import com.github.mikephil.charting.renderer.RadarChartRenderer; import com.github.mikephil.charting.renderer.XAxisRendererRadarChart; import com.github.mikephil.charting.renderer.YAxisRendererRadarChart; import com.github.mikephil.charting.utils.Utils; /** * Implementation of the RadarChart, a "spidernet"-like chart. It works best * when displaying 5-10 entries per DataSet. * * @author Philipp Jahoda */ public class RadarChart extends PieRadarChartBase<RadarData> { /** width of the main web lines */ private float mWebLineWidth = 2.5f; /** width of the inner web lines */ private float mInnerWebLineWidth = 1.5f; /** color for the main web lines */ private int mWebColor = Color.rgb(122, 122, 122); /** color for the inner web */ private int mWebColorInner = Color.rgb(122, 122, 122); /** transparency the grid is drawn with (0-255) */ private int mWebAlpha = 150; /** flag indicating if the web lines should be drawn or not */ private boolean mDrawWeb = true; /** the object reprsenting the y-axis labels */ private YAxis mYAxis; /** the object representing the x-axis labels */ private XAxis mXAxis; protected YAxisRendererRadarChart mYAxisRenderer; protected XAxisRendererRadarChart mXAxisRenderer; public RadarChart(Context context) { super(context); } public RadarChart(Context context, AttributeSet attrs) { super(context, attrs); } public RadarChart(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void init() { super.init(); mYAxis = new YAxis(AxisDependency.LEFT); mXAxis = new XAxis(); mXAxis.setSpaceBetweenLabels(0); mWebLineWidth = Utils.convertDpToPixel(1.5f); mInnerWebLineWidth = Utils.convertDpToPixel(0.75f); mRenderer = new RadarChartRenderer(this, mAnimator, mViewPortHandler); mYAxisRenderer = new YAxisRendererRadarChart(mViewPortHandler, mYAxis, this); mXAxisRenderer = new XAxisRendererRadarChart(mViewPortHandler, mXAxis, this); } @Override protected void calcMinMax() { super.calcMinMax(); float minLeft = mData.getYMin(AxisDependency.LEFT); float maxLeft = mData.getYMax(AxisDependency.LEFT); mXChartMax = mData.getXVals().size() - 1; mDeltaX = Math.abs(mXChartMax - mXChartMin); float leftRange = Math.abs(maxLeft - (mYAxis.isStartAtZeroEnabled() ? 0 : minLeft)); float topSpaceLeft = leftRange / 100f * mYAxis.getSpaceTop(); float bottomSpaceLeft = leftRange / 100f * mYAxis.getSpaceBottom(); mXChartMax = mData.getXVals().size() - 1; mDeltaX = Math.abs(mXChartMax - mXChartMin); mYAxis.mAxisMaximum = !Float.isNaN(mYAxis.getAxisMaxValue()) ? mYAxis .getAxisMaxValue() : maxLeft + topSpaceLeft; mYAxis.mAxisMinimum = !Float.isNaN(mYAxis.getAxisMinValue()) ? mYAxis .getAxisMinValue() : minLeft - bottomSpaceLeft; // consider starting at zero (0) if (mYAxis.isStartAtZeroEnabled()) mYAxis.mAxisMinimum = 0f; mYAxis.mAxisRange = Math.abs(mYAxis.mAxisMaximum - mYAxis.mAxisMinimum); } @Override protected float[] getMarkerPosition(Entry e, int dataSetIndex) { float angle = getSliceAngle() * e.getXIndex() + getRotationAngle(); float val = e.getVal() * getFactor(); PointF c = getCenterOffsets(); PointF p = new PointF((float) (c.x + val * Math.cos(Math.toRadians(angle))), (float) (c.y + val * Math.sin(Math.toRadians(angle)))); return new float[] { p.x, p.y }; } @Override public void notifyDataSetChanged() { if (mDataNotSet) return; calcMinMax(); if (mYAxis.needsDefaultFormatter()) { mYAxis.setValueFormatter(mDefaultFormatter); } mYAxisRenderer.computeAxis(mYAxis.mAxisMinimum, mYAxis.mAxisMaximum); mXAxisRenderer.computeAxis(mData.getXValAverageLength(), mData.getXVals()); mLegendRenderer.computeLegend(mData); calculateOffsets(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mDataNotSet) return; mXAxisRenderer.renderAxisLabels(canvas); if (mDrawWeb) mRenderer.drawExtras(canvas); mYAxisRenderer.renderLimitLines(canvas); mRenderer.drawData(canvas); if (mHighlightEnabled && valuesToHighlight()) mRenderer.drawHighlighted(canvas, mIndicesToHightlight); mYAxisRenderer.renderAxisLabels(canvas); mRenderer.drawValues(canvas); mLegendRenderer.renderLegend(canvas); drawDescription(canvas); drawMarkers(canvas); // canvas.drawBitmap(mDrawBitmap, 0, 0, mDrawPaint); } /** * Returns the factor that is needed to transform values into pixels. * * @return */ public float getFactor() { RectF content = mViewPortHandler.getContentRect(); return (float) Math.min(content.width() / 2f, content.height() / 2f) / mYAxis.mAxisRange; } /** * Returns the angle that each slice in the radar chart occupies. * * @return */ public float getSliceAngle() { return 360f / (float) mData.getXValCount(); } @Override public int getIndexForAngle(float angle) { // take the current angle of the chart into consideration float a = (angle - mRotationAngle + 360) % 360f; float sliceangle = getSliceAngle(); for (int i = 0; i < mData.getXValCount(); i++) { if (sliceangle * (i + 1) - sliceangle / 2f > a) return i; } return 0; } /** * Returns the object that represents all y-labels of the RadarChart. * * @return */ public YAxis getYAxis() { return mYAxis; } /** * Returns the object that represents all x-labels that are placed around * the RadarChart. * * @return */ public XAxis getXAxis() { return mXAxis; } /** * Sets the width of the web lines that come from the center. * * @param width */ public void setWebLineWidth(float width) { mWebLineWidth = Utils.convertDpToPixel(width); } public float getWebLineWidth() { return mWebLineWidth; } /** * Sets the width of the web lines that are in between the lines coming from * the center. * * @param width */ public void setWebLineWidthInner(float width) { mInnerWebLineWidth = Utils.convertDpToPixel(width); } public float getWebLineWidthInner() { return mInnerWebLineWidth; } /** * Sets the transparency (alpha) value for all web lines, default: 150, 255 * = 100% opaque, 0 = 100% transparent * * @param alpha */ public void setWebAlpha(int alpha) { mWebAlpha = alpha; } /** * Returns the alpha value for all web lines. * * @return */ public int getWebAlpha() { return mWebAlpha; } /** * Sets the color for the web lines that come from the center. Don't forget * to use getResources().getColor(...) when loading a color from the * resources. Default: Color.rgb(122, 122, 122) * * @param color */ public void setWebColor(int color) { mWebColor = color; } public int getWebColor() { return mWebColor; } /** * Sets the color for the web lines in between the lines that come from the * center. Don't forget to use getResources().getColor(...) when loading a * color from the resources. Default: Color.rgb(122, 122, 122) * * @param color */ public void setWebColorInner(int color) { mWebColorInner = color; } public int getWebColorInner() { return mWebColorInner; } /** * If set to true, drawing the web is enabled, if set to false, drawing the * whole web is disabled. Default: true * * @param enabled */ public void setDrawWeb(boolean enabled) { mDrawWeb = enabled; } @Override protected float getRequiredBottomOffset() { return mLegendRenderer.getLabelPaint().getTextSize() * 6.5f; } @Override protected float getRequiredBaseOffset() { return mXAxis.mLabelWidth; } @Override public float getRadius() { RectF content = mViewPortHandler.getContentRect(); return Math.min(content.width() / 2f, content.height() / 2f); } /** * Returns the maximum value this chart can display on it's y-axis. */ public float getYChartMax() { return mYAxis.mAxisMaximum; } /** * Returns the minimum value this chart can display on it's y-axis. */ public float getYChartMin() { return mYAxis.mAxisMinimum; } /** * Returns the range of y-values this chart can display. * * @return */ public float getYRange() { return mYAxis.mAxisRange; } }