package com.github.mikephil.charting.charts;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.RectF;
import android.util.AttributeSet;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.components.YAxis.AxisDependency;
import com.github.mikephil.charting.data.RadarData;
import com.github.mikephil.charting.highlight.RadarHighlighter;
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;
/**
* modulus that determines how many labels and web-lines are skipped before the next is drawn
*/
private int mSkipWebLineCount = 0;
/**
* the object reprsenting the y-axis labels
*/
private YAxis mYAxis;
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);
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);
mHighlighter = new RadarHighlighter(this);
}
@Override
protected void calcMinMax() {
super.calcMinMax();
mYAxis.calculate(mData.getYMin(AxisDependency.LEFT), mData.getYMax(AxisDependency.LEFT));
mXAxis.calculate(0, mData.getMaxEntryCountSet().getEntryCount());
}
@Override
public void notifyDataSetChanged() {
if (mData == null)
return;
calcMinMax();
mYAxisRenderer.computeAxis(mYAxis.mAxisMinimum, mYAxis.mAxisMaximum, mYAxis.isInverted());
mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false);
if (mLegend != null && !mLegend.isLegendCustom())
mLegendRenderer.computeLegend(mData);
calculateOffsets();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mData == null)
return;
// if (mYAxis.isEnabled())
// mYAxisRenderer.computeAxis(mYAxis.mAxisMinimum, mYAxis.mAxisMaximum, mYAxis.isInverted());
if (mXAxis.isEnabled())
mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false);
mXAxisRenderer.renderAxisLabels(canvas);
if (mDrawWeb)
mRenderer.drawExtras(canvas);
if (mYAxis.isEnabled() && mYAxis.isDrawLimitLinesBehindDataEnabled())
mYAxisRenderer.renderLimitLines(canvas);
mRenderer.drawData(canvas);
if (valuesToHighlight())
mRenderer.drawHighlighted(canvas, mIndicesToHighlight);
if (mYAxis.isEnabled() && !mYAxis.isDrawLimitLinesBehindDataEnabled())
mYAxisRenderer.renderLimitLines(canvas);
mYAxisRenderer.renderAxisLabels(canvas);
mRenderer.drawValues(canvas);
mLegendRenderer.renderLegend(canvas);
drawDescription(canvas);
drawMarkers(canvas);
}
/**
* Returns the factor that is needed to transform values into pixels.
*
* @return
*/
public float getFactor() {
RectF content = mViewPortHandler.getContentRect();
return 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.getMaxEntryCountSet().getEntryCount();
}
@Override
public int getIndexForAngle(float angle) {
// take the current angle of the chart into consideration
float a = Utils.getNormalizedAngle(angle - getRotationAngle());
float sliceangle = getSliceAngle();
int max = mData.getMaxEntryCountSet().getEntryCount();
int index = 0;
for (int i = 0; i < max; i++) {
float referenceAngle = sliceangle * (i + 1) - sliceangle / 2f;
if (referenceAngle > a) {
index = i;
break;
}
}
return index;
}
/**
* Returns the object that represents all y-labels of the RadarChart.
*
* @return
*/
public YAxis getYAxis() {
return mYAxis;
}
/**
* 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;
}
/**
* Sets the number of web-lines that should be skipped on chart web before the
* next one is drawn. This targets the lines that come from the center of the RadarChart.
*
* @param count if count = 1 -> 1 line is skipped in between
*/
public void setSkipWebLineCount(int count) {
mSkipWebLineCount = Math.max(0, count);
}
/**
* Returns the modulus that is used for skipping web-lines.
*
* @return
*/
public int getSkipWebLineCount() {
return mSkipWebLineCount;
}
@Override
protected float getRequiredLegendOffset() {
return mLegendRenderer.getLabelPaint().getTextSize() * 4.f;
}
@Override
protected float getRequiredBaseOffset() {
return mXAxis.isEnabled() && mXAxis.isDrawLabelsEnabled() ?
mXAxis.mLabelRotatedWidth :
Utils.convertDpToPixel(10f);
}
@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;
}
}