Android-MPAndroidChart:RadarChart(雷达蜘蛛图)绘制圆点

    技术2022-07-15  85

    目录

    思路

    实现


    思路来源于Homilier,感谢博主!

    效果是这样子的:

    思路

    从RadarChart类中我们可以看到init()方法中的内容,可以看出来自定义了绘制类。仅从字面我们就可以看出RadarChartRenderer是绘制雷达的,YAxisRendererRadarChart和XAxisRendererRadarChart是绘制x轴/y轴相关内容的,既然这样那我们就清楚了,进RadarChartRenderer看看里面的实现;

     从方法名上就可以看出端倪,drawValues(Canvas c) 是咱重点关注的内容。所以在这开造。

    实现

     直接贴代码,很基础的绘制代码,就不做介绍了。代码过长,没必要的就直接用省略号了,对比下RadarChartRenderer即可

    public class RadarChartRenderer extends LineRadarRenderer { protected RadarChart mChart; /** * paint for drawing the web */ protected Paint mWebPaint; protected Paint mHighlightCirclePaint; public RadarChartRenderer(RadarChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler) { super(animator, viewPortHandler); mChart = chart; mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mHighlightPaint.setStyle(Paint.Style.STROKE); mHighlightPaint.setStrokeWidth(2f); mHighlightPaint.setColor(Color.rgb(255, 187, 115)); mWebPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mWebPaint.setStyle(Paint.Style.STROKE); mHighlightCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mValueCirclePaint = new Paint(); } protected Path mDrawDataSetSurfacePathBuffer = new Path(); ......... /** * 绘制RadarDataSet * * @param c * @param dataSet * @param mostEntries 条目最多的数据集的条目计数 */ protected void drawDataSet(Canvas c, IRadarDataSet dataSet, int mostEntries) { float phaseX = mAnimator.getPhaseX(); float phaseY = mAnimator.getPhaseY(); float sliceangle = mChart.getSliceAngle(); // 计算将值转换为像素所需的因子 float factor = mChart.getFactor(); MPPointF center = mChart.getCenterOffsets(); MPPointF pOut = MPPointF.getInstance(0, 0); Path surface = mDrawDataSetSurfacePathBuffer; surface.reset(); boolean hasMovedToPoint = false; for (int j = 0; j < dataSet.getEntryCount(); j++) { mRenderPaint.setColor(dataSet.getColor(j)); RadarEntry e = dataSet.getEntryForIndex(j); Utils.getPosition(center, (e.getY() - mChart.getYChartMin()) * factor * phaseY, sliceangle * j * phaseX + mChart.getRotationAngle(), pOut); if (Float.isNaN(pOut.x)) { continue; } if (!hasMovedToPoint) { surface.moveTo(pOut.x, pOut.y); hasMovedToPoint = true; } else { surface.lineTo(pOut.x, pOut.y); } } if (dataSet.getEntryCount() > mostEntries) { // if this is not the largest set, draw a line to the center before closing surface.lineTo(center.x, center.y); } surface.close(); if (dataSet.isDrawFilledEnabled()) { final Drawable drawable = dataSet.getFillDrawable(); if (drawable != null) { drawFilledPath(c, surface, drawable); } else { drawFilledPath(c, surface, dataSet.getFillColor(), dataSet.getFillAlpha()); } } mRenderPaint.setStrokeWidth(dataSet.getLineWidth()); mRenderPaint.setStyle(Paint.Style.STROKE); // 画线(仅当禁用填充或alpha小于255时) if (!dataSet.isDrawFilledEnabled() || dataSet.getFillAlpha() < 255) { c.drawPath(surface, mRenderPaint); } MPPointF.recycleInstance(center); MPPointF.recycleInstance(pOut); } private Paint mValueCirclePaint; private float mValueCircleRadius = Utils.convertDpToPixel(5f); private int[] mValueCircleColors; private boolean mDrawValueCircle = false; private float mValueCircleRadiusUp = Utils.convertDpToPixel(3f); private int[] mValueCircleColorsUp; private boolean mDrawValueCircleUp = false; /** * 绘制数值-也就是和数值相关的位置 * * @param c */ @Override public void drawValues(Canvas c) { float phaseX = mAnimator.getPhaseX(); float phaseY = mAnimator.getPhaseY(); float sliceangle = mChart.getSliceAngle(); // 计算将值转换为像素所需的因子 float factor = mChart.getFactor(); MPPointF center = mChart.getCenterOffsets(); MPPointF pOut = MPPointF.getInstance(0, 0); MPPointF pIcon = MPPointF.getInstance(0, 0); float yoffset = Utils.convertDpToPixel(5f); for (int i = 0; i < mChart.getData().getDataSetCount(); i++) { IRadarDataSet dataSet = mChart.getData().getDataSetByIndex(i); if (!shouldDrawValues(dataSet)) { continue; } // 应用数据集定义的文本样式 applyValueTextStyle(dataSet); ValueFormatter formatter = dataSet.getValueFormatter(); MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset()); iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x); iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y); for (int j = 0; j < dataSet.getEntryCount(); j++) { RadarEntry entry = dataSet.getEntryForIndex(j); Utils.getPosition(center, (entry.getY() - mChart.getYChartMin()) * factor * phaseY, sliceangle * j * phaseX + mChart.getRotationAngle(), pOut); if (dataSet.isDrawValuesEnabled()) { drawValue(c, formatter.getRadarLabel(entry), pOut.x, pOut.y - yoffset, dataSet.getValueTextColor(j)); } if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) { Drawable icon = entry.getIcon(); Utils.getPosition(center, (entry.getY()) * factor * phaseY + iconsOffset.y, sliceangle * j * phaseX + mChart.getRotationAngle(), pIcon); //无检查SuspiciousNameCombination pIcon.y += iconsOffset.x; Utils.drawImage(c, icon, (int) pIcon.x, (int) pIcon.y, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); } if (mDrawValueCircle) { mValueCirclePaint.setColor(mValueCircleColors == null || mValueCircleColors.length == 0 ? Color.BLACK : this.mValueCircleColors[i % mValueCircleColors.length]); c.drawCircle(pOut.x, pOut.y, mValueCircleRadius, mValueCirclePaint); } if (mDrawValueCircleUp) { mValueCirclePaint.setColor(mValueCircleColorsUp == null || mValueCircleColorsUp.length == 0 ? Color.BLACK : this.mValueCircleColorsUp[i % mValueCircleColorsUp.length]); c.drawCircle(pOut.x, pOut.y, mValueCircleRadiusUp, mValueCirclePaint); } // c.drawCircle(center.x, center.y, 8, mWebPaint); } MPPointF.recycleInstance(iconsOffset); } MPPointF.recycleInstance(center); MPPointF.recycleInstance(pOut); MPPointF.recycleInstance(pIcon); } /** * 数值圆点颜色 * * @param colors 颜色 */ public void setValueCircleColor(int[] colors, int[] colorsUp) { this.mValueCircleColors = colors; this.mValueCircleColorsUp = colorsUp; } /** * 数值圆点半径 * * @param radius 半径 */ public void setValueCircleRadius(float radius, float radiusUp) { this.mValueCircleRadius = Utils.convertDpToPixel(radius); this.mValueCircleRadiusUp = Utils.convertDpToPixel(radiusUp); } /** * 是否绘制数值圆点 * * @param draw */ public void setDrawValueCircle(boolean draw, boolean drawUp) { this.mDrawValueCircleUp = drawUp; this.mDrawValueCircle = draw; } ......... }

    RadarChart添加三个方法

    public class RadarChart extends PieRadarChartBase<RadarData> { ........ /** * 顶角圆点颜色 * @param colors 颜色 */ public void setValueCircleColor(int[] colors,int[] colorsUp){ ((RadarChartRenderer) this.mRenderer).setValueCircleColor(colors,colorsUp); } /** * 顶角圆点半径 * @param radius 半径 */ public void setValueCircleRadius(float radius,float radiusUp){ ((RadarChartRenderer) this.mRenderer).setValueCircleRadius(radius,radiusUp); } /** * 是否绘制顶角圆点 * @param draw */ public void setDrawValueCircle(boolean draw,boolean drawUp){ ((RadarChartRenderer) this.mRenderer).setDrawValueCircle(draw,drawUp); } ........ }

    自己项目中应用:

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_radarchart); RadarChart chart = findViewById(R.id.chart1); chart.setWebLineWidth(1f); chart.setWebColor(Color.LTGRAY); chart.setWebLineWidthInner(1f); chart.setWebColorInner(Color.LTGRAY); chart.setWebAlpha(100); // 创建一个自定义MarkerView(扩展MarkerView)并指定布局用它 MarkerView mv = new RadarMarkerView(this, R.layout.radar_markerview); //重点在这 //设置数据圆点 第一个true表示绘制下层圆 第二个true绘制上层圆 形成圆环形式的圆 chart.setDrawValueCircle(true, true); //设置半径 第一个参数大于第二个参数 才会有圆环的那种样子 chart.setValueCircleRadius(6, 4); //可以设置多个颜色,第一个数组是下层圆 第二个数组是下层圆 chart.setValueCircleColor(new int[]{ Color.parseColor("#36a9ce"), Color.parseColor("#33ff66"), }, new int[]{ Color.parseColor("#ffffff"), Color.parseColor("#000000") }); }

     

    Processed: 0.017, SQL: 9