雷达图(蜘蛛网)的实现

2018-01-18  本文已影响0人  木小伍
废话不多说,先直接上最终的效果图(完整代码在底部)
最后完成图.png

实现思路

首先,我们将效果图实现的过程,拆分:
1,将6边形画出来
2,将对角线连接
3,在6个角上面添加上文字(我默认为右上角的为起始位置)
4,按照百分比,标出红点的位子,并连接,最后实现最终的效果
上面四点就是主要思路,现在思路有了就开始动手撸代码了。

    private Paint mPaint = new Paint(); //画6边形的笔
    private float mHeight, mWidth; //圆心
    private float mRadius = 180;
    private int count = 4; //蜘蛛网的层数为4
    private Paint textPaint = new Paint(); //画文字的笔
    private String[] titles = {"A", "B", "C", "D", "E", "F"}; //6个顶点的名称
    private float[] pcent = {0.8f, 0.6f, 0.2f, 0.9f, 0.5f, 0.7f};
    //   private float[] pcent = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
    private Paint shadePaint = new Paint(); //阴影图的画笔

这些是定义的成员变量,下面进入正题。

Step 1. 画6边形 (需要先将canvas的原点,移到屏幕中心)

  //画6边形在ondraw方法中,
        float x_off = 0; //层数递减,横坐标相对应的递减值
        float y_off = 0; //层数递减,纵坐标相对应的递减值
      //  canvas.drawCircle(0, 0, mRadius, mPaint); //画出内切圆
        for (int i = 0; i < count; i++) {  //控制蜘蛛网的层数
            x_off = (mRadius / 2) - (i * mRadius / count / 2);
            y_off = (mRadius - (i * mRadius / count)) * (float) Math.sqrt(3) / 2;

            for (int j = 0; j < 6; j++) {  //画6边形
                canvas.drawLine(-x_off,
                        y_off,
                        x_off,
                        y_off, mPaint);
                canvas.rotate(60);
            }
        }

这段代码跑完之后就是这个图了


六边形.png
image.png

这里只要理解清楚了,每一层递减的时候,x坐标与y坐标的变化关系,就一切了然了。
强烈建议理解的时候,顺便画个三角形,然后里面画几道杠杠。通过一系列的sin,cos我们就可以得到以下的规律:
x轴递减规律为:每缩小一层,x轴的坐标,就减少 半径 除以 总共的层数 乘以 sin30(也就是二分之一)的长度。也就是上述代码 x_off代码表示计算方法。
y轴递减规律为:每缩小一层,y轴的坐标,就减少 半径 除以 总共的层数 乘以 cos30(也就是 二分之根号三)的长度。业绩宿舍上述代码 y_off 表示的计算方法。
因为只要画6边形,我们只需要每次画完一边,就旋转60度即可。

Step 2. 连接对角线

 //将对角线连接
        canvas.drawLine(-mRadius, 0, mRadius, 0, mPaint);
        canvas.drawLine(-mRadius / 2, (float) Math.sqrt(3) * mRadius / 2,
                mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2, mPaint);
        canvas.drawLine(-mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2,
                mRadius / 2, (float) Math.sqrt(3) * mRadius / 2, mPaint);
我们只关心,最外面的6个点的坐标,只要画出了6变形,那6个点的坐标就很容易得到了。效果图如下 连接对角线.png

Step 3.填加文字到6个点上面

        //在6个角画上文字
        canvas.drawText(titles[0], mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2 - 5, textPaint);
        canvas.drawText(titles[1], mRadius + 5, 0, textPaint);
        canvas.drawText(titles[2], mRadius / 2, (float) Math.sqrt(3) * mRadius / 2 + 15, textPaint);
        canvas.drawText(titles[3], -mRadius / 2, (float) Math.sqrt(3) * mRadius / 2 + 15, textPaint);
        canvas.drawText(titles[4], -mRadius - 15, 0, textPaint);
        canvas.drawText(titles[5], -mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2 - 5, textPaint);

为了更美观,我并没有直接把文字画在6个点上,而是朝外面移动了部分距离,(呃....左边的”小周“要按照实际的情况再把横坐标朝向左边移动。这里仅仅作为展示效果,就不要在意这些细节了。。。)

效果如下: 在6个角上面添加文字.png

Step 4.画阴影图了

   //画阴影部分

        ArrayList<PointF> pointFs = new ArrayList<>();
        pointFs.add(new PointF(mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2));
        pointFs.add(new PointF(mRadius, 0));
        pointFs.add(new PointF(mRadius / 2, (float) Math.sqrt(3) * mRadius / 2));
        pointFs.add(new PointF(-mRadius / 2, (float) Math.sqrt(3) * mRadius / 2));
        pointFs.add(new PointF(-mRadius, 0));
        pointFs.add(new PointF(-mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2));

        Path path = new Path();
        float x, y;
        for (int i = 0; i < pointFs.size(); i++) {  //获取百分比之后的点
            x = pointFs.get(i).x * pcent[i];
            y = pointFs.get(i).y * pcent[i];
            if (i == 0) {
                path.moveTo(x, y);  //路线起点移动到第一个点的位置
            } else {
                path.lineTo(x, y);
            }
            canvas.drawCircle(x, y, 4, textPaint); //画出小红点
        }
        canvas.drawPath(path, shadePaint);

这个就是最终的效果图了。

全部代码如下(注意适配问题,需要将px转换成为dp):

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;

import java.util.ArrayList;

/**
 * Created by 伍跃武 on 2018/1/17.
 * 雷达图
 */

public class SpiderView extends View {
    public SpiderView(Context context) {
        this(context, null);
    }

    public SpiderView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SpiderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }


    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public SpiderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    private Paint mPaint = new Paint(); //画6边形的笔
    private float mHeight, mWidth; //圆心
    private float mRadius = 180;
    private int count = 4; //蜘蛛网的层数为4
    private Paint textPaint = new Paint(); //画文字的笔
    private String[] titles = {"A", "B", "C", "D", "E", "F"}; //6个顶点的名称
    private float[] pcent = {0.8f, 0.6f, 0.2f, 0.9f, 0.5f, 0.7f};
    //   private float[] pcent = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
    private Paint shadePaint = new Paint(); //阴影图的画笔


    /**
     * 初始化视图
     */

    private void initView() {
        mPaint.setStrokeWidth(2f);
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.GREEN);

        textPaint.setAntiAlias(true);
        textPaint.setStrokeWidth(1f);
        textPaint.setColor(Color.RED);
        textPaint.setTextSize(16);

        shadePaint.setColor(Color.GRAY);
        shadePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        shadePaint.setAlpha(122);


    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mHeight = h / 2;
        mWidth = w / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.BLACK);
        canvas.translate(mWidth, mHeight); //原点移到中心
        mPaint.setStyle(Paint.Style.STROKE);//不填充颜色
        canvas.drawCircle(0, 0, mRadius, mPaint);
        //   canvas.drawPoint(0,0,mPaint);

        //画6边形
        float x_off = 0; //层数递减,横坐标相对应的递减值
        float y_off = 0; //层数递减,纵坐标相对应的递减值

        for (int i = 0; i < count; i++) {  //控制蜘蛛网的层数
            x_off = (mRadius / 2) - (i * mRadius / count / 2);
            y_off = (mRadius - (i * mRadius / count)) * (float) Math.sqrt(3) / 2;

            for (int j = 0; j < 6; j++) {  //画6边形

                canvas.drawLine(-x_off,
                        y_off,
                        x_off,
                        y_off, mPaint);
                canvas.rotate(60);
            }
        }
        //将对角线连接

        canvas.drawLine(-mRadius, 0, mRadius, 0, mPaint);
        canvas.drawLine(-mRadius / 2, (float) Math.sqrt(3) * mRadius / 2,
                mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2, mPaint);
        canvas.drawLine(-mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2,
                mRadius / 2, (float) Math.sqrt(3) * mRadius / 2, mPaint);


        //在6个角画上文字
        canvas.drawText(titles[0], mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2 - 5, textPaint);
        canvas.drawText(titles[1], mRadius + 5, 0, textPaint);
        canvas.drawText(titles[2], mRadius / 2, (float) Math.sqrt(3) * mRadius / 2 + 15, textPaint);
        canvas.drawText(titles[3], -mRadius / 2, (float) Math.sqrt(3) * mRadius / 2 + 15, textPaint);
        canvas.drawText(titles[4], -mRadius - 15, 0, textPaint);
        canvas.drawText(titles[5], -mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2 - 5, textPaint);

        //画阴影部分

        ArrayList<PointF> pointFs = new ArrayList<>();
        pointFs.add(new PointF(mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2));
        pointFs.add(new PointF(mRadius, 0));
        pointFs.add(new PointF(mRadius / 2, (float) Math.sqrt(3) * mRadius / 2));
        pointFs.add(new PointF(-mRadius / 2, (float) Math.sqrt(3) * mRadius / 2));
        pointFs.add(new PointF(-mRadius, 0));
        pointFs.add(new PointF(-mRadius / 2, -(float) Math.sqrt(3) * mRadius / 2));

        Path path = new Path();
        float x, y;
        for (int i = 0; i < pointFs.size(); i++) {  //获取百分比之后的点
            x = pointFs.get(i).x * pcent[i];
            y = pointFs.get(i).y * pcent[i];
            if (i == 0) {
                path.moveTo(x, y);  //路线起点移动到第一个点的位置
            } else {
                path.lineTo(x, y);
            }
            canvas.drawCircle(x, y, 4, textPaint); //画出小红点
        }
        canvas.drawPath(path, shadePaint);
    }

    public void setTitles(String[] titles) {
        this.titles = titles;
        invalidate();
    }

    public void setPcent(float[] pcent) {
        this.pcent = pcent;
        invalidate();
    }
}

上一篇 下一篇

猜你喜欢

热点阅读