美文网首页
雷达图(蜘蛛网)的实现

雷达图(蜘蛛网)的实现

作者: 木小伍 | 来源:发表于2018-01-18 22:22 被阅读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();
        }
    }
    
    

    相关文章

      网友评论

          本文标题:雷达图(蜘蛛网)的实现

          本文链接:https://www.haomeiwen.com/subject/qilgoxtx.html