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

目录

思路

实现


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

效果是这样子的:

思路

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

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

实现

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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添加三个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
    }

    ........
}

自己项目中应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  @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")
        });
 
    }