1 2 package com.github.mikephil.charting.charts; 3 4 import android.content.Context; 5 import android.graphics.Canvas; 6 import android.graphics.Color; 7 import android.graphics.RectF; 8 import android.util.AttributeSet; 9 10 import com.github.mikephil.charting.components.YAxis; 11 import com.github.mikephil.charting.components.YAxis.AxisDependency; 12 import com.github.mikephil.charting.data.RadarData; 13 import com.github.mikephil.charting.highlight.RadarHighlighter; 14 import com.github.mikephil.charting.renderer.RadarChartRenderer; 15 import com.github.mikephil.charting.renderer.XAxisRendererRadarChart; 16 import com.github.mikephil.charting.renderer.YAxisRendererRadarChart; 17 import com.github.mikephil.charting.utils.Utils; 18 19 /** 20 * Implementation of the RadarChart, a "spidernet"-like chart. It works best 21 * when displaying 5-10 entries per DataSet. 22 * 23 * @author Philipp Jahoda 24 */ 25 public class RadarChart extends PieRadarChartBase<RadarData> { 26 27 /** 28 * width of the main web lines 29 */ 30 private float mWebLineWidth = 2.5f; 31 32 /** 33 * width of the inner web lines 34 */ 35 private float mInnerWebLineWidth = 1.5f; 36 37 /** 38 * color for the main web lines 39 */ 40 private int mWebColor = Color.rgb(122, 122, 122); 41 42 /** 43 * color for the inner web 44 */ 45 private int mWebColorInner = Color.rgb(122, 122, 122); 46 47 /** 48 * transparency the grid is drawn with (0-255) 49 */ 50 private int mWebAlpha = 150; 51 52 /** 53 * flag indicating if the web lines should be drawn or not 54 */ 55 private boolean mDrawWeb = true; 56 57 /** 58 * modulus that determines how many labels and web-lines are skipped before the next is drawn 59 */ 60 private int mSkipWebLineCount = 0; 61 62 /** 63 * the object reprsenting the y-axis labels 64 */ 65 private YAxis mYAxis; 66 67 protected YAxisRendererRadarChart mYAxisRenderer; 68 protected XAxisRendererRadarChart mXAxisRenderer; 69 RadarChart(Context context)70 public RadarChart(Context context) { 71 super(context); 72 } 73 RadarChart(Context context, AttributeSet attrs)74 public RadarChart(Context context, AttributeSet attrs) { 75 super(context, attrs); 76 } 77 RadarChart(Context context, AttributeSet attrs, int defStyle)78 public RadarChart(Context context, AttributeSet attrs, int defStyle) { 79 super(context, attrs, defStyle); 80 } 81 82 @Override init()83 protected void init() { 84 super.init(); 85 86 mYAxis = new YAxis(AxisDependency.LEFT); 87 mYAxis.setLabelXOffset(10f); 88 89 mWebLineWidth = Utils.convertDpToPixel(1.5f); 90 mInnerWebLineWidth = Utils.convertDpToPixel(0.75f); 91 92 mRenderer = new RadarChartRenderer(this, mAnimator, mViewPortHandler); 93 mYAxisRenderer = new YAxisRendererRadarChart(mViewPortHandler, mYAxis, this); 94 mXAxisRenderer = new XAxisRendererRadarChart(mViewPortHandler, mXAxis, this); 95 96 mHighlighter = new RadarHighlighter(this); 97 } 98 99 @Override calcMinMax()100 protected void calcMinMax() { 101 super.calcMinMax(); 102 103 mYAxis.calculate(mData.getYMin(AxisDependency.LEFT), mData.getYMax(AxisDependency.LEFT)); 104 mXAxis.calculate(0, mData.getMaxEntryCountSet().getEntryCount()); 105 } 106 107 @Override notifyDataSetChanged()108 public void notifyDataSetChanged() { 109 if (mData == null) 110 return; 111 112 calcMinMax(); 113 114 mYAxisRenderer.computeAxis(mYAxis.mAxisMinimum, mYAxis.mAxisMaximum, mYAxis.isInverted()); 115 mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false); 116 117 if (mLegend != null && !mLegend.isLegendCustom()) 118 mLegendRenderer.computeLegend(mData); 119 120 calculateOffsets(); 121 } 122 123 @Override onDraw(Canvas canvas)124 protected void onDraw(Canvas canvas) { 125 super.onDraw(canvas); 126 127 if (mData == null) 128 return; 129 130 // if (mYAxis.isEnabled()) 131 // mYAxisRenderer.computeAxis(mYAxis.mAxisMinimum, mYAxis.mAxisMaximum, mYAxis.isInverted()); 132 133 if (mXAxis.isEnabled()) 134 mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false); 135 136 mXAxisRenderer.renderAxisLabels(canvas); 137 138 if (mDrawWeb) 139 mRenderer.drawExtras(canvas); 140 141 if (mYAxis.isEnabled() && mYAxis.isDrawLimitLinesBehindDataEnabled()) 142 mYAxisRenderer.renderLimitLines(canvas); 143 144 mRenderer.drawData(canvas); 145 146 if (valuesToHighlight()) 147 mRenderer.drawHighlighted(canvas, mIndicesToHighlight); 148 149 if (mYAxis.isEnabled() && !mYAxis.isDrawLimitLinesBehindDataEnabled()) 150 mYAxisRenderer.renderLimitLines(canvas); 151 152 mYAxisRenderer.renderAxisLabels(canvas); 153 154 mRenderer.drawValues(canvas); 155 156 mLegendRenderer.renderLegend(canvas); 157 158 drawDescription(canvas); 159 160 drawMarkers(canvas); 161 } 162 163 /** 164 * Returns the factor that is needed to transform values into pixels. 165 * 166 * @return 167 */ getFactor()168 public float getFactor() { 169 RectF content = mViewPortHandler.getContentRect(); 170 return Math.min(content.width() / 2f, content.height() / 2f) / mYAxis.mAxisRange; 171 } 172 173 /** 174 * Returns the angle that each slice in the radar chart occupies. 175 * 176 * @return 177 */ getSliceAngle()178 public float getSliceAngle() { 179 return 360f / (float) mData.getMaxEntryCountSet().getEntryCount(); 180 } 181 182 @Override getIndexForAngle(float angle)183 public int getIndexForAngle(float angle) { 184 185 // take the current angle of the chart into consideration 186 float a = Utils.getNormalizedAngle(angle - getRotationAngle()); 187 188 float sliceangle = getSliceAngle(); 189 190 int max = mData.getMaxEntryCountSet().getEntryCount(); 191 192 int index = 0; 193 194 for (int i = 0; i < max; i++) { 195 196 float referenceAngle = sliceangle * (i + 1) - sliceangle / 2f; 197 198 if (referenceAngle > a) { 199 index = i; 200 break; 201 } 202 } 203 204 return index; 205 } 206 207 /** 208 * Returns the object that represents all y-labels of the RadarChart. 209 * 210 * @return 211 */ getYAxis()212 public YAxis getYAxis() { 213 return mYAxis; 214 } 215 216 /** 217 * Sets the width of the web lines that come from the center. 218 * 219 * @param width 220 */ setWebLineWidth(float width)221 public void setWebLineWidth(float width) { 222 mWebLineWidth = Utils.convertDpToPixel(width); 223 } 224 getWebLineWidth()225 public float getWebLineWidth() { 226 return mWebLineWidth; 227 } 228 229 /** 230 * Sets the width of the web lines that are in between the lines coming from 231 * the center. 232 * 233 * @param width 234 */ setWebLineWidthInner(float width)235 public void setWebLineWidthInner(float width) { 236 mInnerWebLineWidth = Utils.convertDpToPixel(width); 237 } 238 getWebLineWidthInner()239 public float getWebLineWidthInner() { 240 return mInnerWebLineWidth; 241 } 242 243 /** 244 * Sets the transparency (alpha) value for all web lines, default: 150, 255 245 * = 100% opaque, 0 = 100% transparent 246 * 247 * @param alpha 248 */ setWebAlpha(int alpha)249 public void setWebAlpha(int alpha) { 250 mWebAlpha = alpha; 251 } 252 253 /** 254 * Returns the alpha value for all web lines. 255 * 256 * @return 257 */ getWebAlpha()258 public int getWebAlpha() { 259 return mWebAlpha; 260 } 261 262 /** 263 * Sets the color for the web lines that come from the center. Don't forget 264 * to use getResources().getColor(...) when loading a color from the 265 * resources. Default: Color.rgb(122, 122, 122) 266 * 267 * @param color 268 */ setWebColor(int color)269 public void setWebColor(int color) { 270 mWebColor = color; 271 } 272 getWebColor()273 public int getWebColor() { 274 return mWebColor; 275 } 276 277 /** 278 * Sets the color for the web lines in between the lines that come from the 279 * center. Don't forget to use getResources().getColor(...) when loading a 280 * color from the resources. Default: Color.rgb(122, 122, 122) 281 * 282 * @param color 283 */ setWebColorInner(int color)284 public void setWebColorInner(int color) { 285 mWebColorInner = color; 286 } 287 getWebColorInner()288 public int getWebColorInner() { 289 return mWebColorInner; 290 } 291 292 /** 293 * If set to true, drawing the web is enabled, if set to false, drawing the 294 * whole web is disabled. Default: true 295 * 296 * @param enabled 297 */ setDrawWeb(boolean enabled)298 public void setDrawWeb(boolean enabled) { 299 mDrawWeb = enabled; 300 } 301 302 /** 303 * Sets the number of web-lines that should be skipped on chart web before the 304 * next one is drawn. This targets the lines that come from the center of the RadarChart. 305 * 306 * @param count if count = 1 -> 1 line is skipped in between 307 */ setSkipWebLineCount(int count)308 public void setSkipWebLineCount(int count) { 309 310 mSkipWebLineCount = Math.max(0, count); 311 } 312 313 /** 314 * Returns the modulus that is used for skipping web-lines. 315 * 316 * @return 317 */ getSkipWebLineCount()318 public int getSkipWebLineCount() { 319 return mSkipWebLineCount; 320 } 321 322 @Override getRequiredLegendOffset()323 protected float getRequiredLegendOffset() { 324 return mLegendRenderer.getLabelPaint().getTextSize() * 4.f; 325 } 326 327 @Override getRequiredBaseOffset()328 protected float getRequiredBaseOffset() { 329 return mXAxis.isEnabled() && mXAxis.isDrawLabelsEnabled() ? 330 mXAxis.mLabelRotatedWidth : 331 Utils.convertDpToPixel(10f); 332 } 333 334 @Override getRadius()335 public float getRadius() { 336 RectF content = mViewPortHandler.getContentRect(); 337 return Math.min(content.width() / 2f, content.height() / 2f); 338 } 339 340 /** 341 * Returns the maximum value this chart can display on it's y-axis. 342 */ getYChartMax()343 public float getYChartMax() { 344 return mYAxis.mAxisMaximum; 345 } 346 347 /** 348 * Returns the minimum value this chart can display on it's y-axis. 349 */ getYChartMin()350 public float getYChartMin() { 351 return mYAxis.mAxisMinimum; 352 } 353 354 /** 355 * Returns the range of y-values this chart can display. 356 * 357 * @return 358 */ getYRange()359 public float getYRange() { 360 return mYAxis.mAxisRange; 361 } 362 } 363