雷达区域控件

自定义雷达图

参考:

http://blog.csdn.net/crazy__chen/article/details/50163693
http://blog.csdn.net/lehtoon_1992/article/details/51036409
http://blog.csdn.net/wangchangshuai0010/article/details/7336435 Path相关
http://blog.csdn.net/sirnuo/article/details/21165665 Paint.drawText()相关

效果图

属性视图

思路

得到中心点,然后根据角度和半径计算出各个坐标点,使用Path画线,drawText画文本

代码

public class RadarChartView extends View {


    private int count = 5;                //数据个数
    private float angle = (float) (Math.PI * 2 / count);    //多边形的角度
    private float radius;                   //多边形最大半径
    private int centerX;                  //中心X
    private int centerY;                  //中心Y
    private double[] data = {2,3,1,5,2}; //各维度的值
    private String[] dataValue = {"攻击", "速度", "防御", "血量", "魔法"}; //各属性名称
    private float maxValue = 5;             //数据最大值
    private Paint mainPaint;               //边线画的笔
    private Paint valuePaint;               //中心点到数据点的画笔
    private Paint textPaint;               //文字画笔


    public RadarChartView(Context context) {
        super(context);
        init();
    }

    public RadarChartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }


    /**
     * 初始化画笔工具
     */
    private void init() {
        mainPaint = new Paint();
        mainPaint.setColor(Color.parseColor("#000000"));
        mainPaint.setStrokeWidth(1);
        mainPaint.setAntiAlias(true);
        mainPaint.setStyle(Paint.Style.STROKE);

        valuePaint = new Paint();
        valuePaint.setColor(Color.parseColor("#000000"));
        valuePaint.setStrokeWidth(1);
        valuePaint.setAntiAlias(true);
        valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);

        textPaint = new Paint();
        textPaint.setColor(Color.parseColor("#000000"));
        textPaint.setStrokeWidth(1); // 设置空心线宽
        textPaint.setAntiAlias(true); // 设置抗锯齿
        textPaint.setStyle(Paint.Style.STROKE);

    }


    /**
     * 根据View的长宽,获取整个布局的中心坐标
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w / 2;
        centerY = h / 2;
        radius = Math.min(w,h) / 2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawLines(canvas);
        drawRegion(canvas);
    }

    /**
     * 绘制从中心到末端的直线,同样根据半径,计算出每个末端坐标
     */
    private void drawLines(Canvas canvas) {
        Path path = new Path();
        path.reset();
        float r = radius / (count + 2);//r是蜘蛛丝之间的间距
        float curR = (float) (r * data[0]);//当前半径
        float x = (float) (centerX + curR * Math.sin(angle));
        float y = (float) (centerY - curR * Math.cos(angle));
        path.moveTo(x, y);
        path.lineTo(centerX, centerY);
        curR = (float) (r * data[1]);//当前半径
        float x1 = (float) (centerX + curR * Math.sin(angle / 2));
        float y1 = (float) (centerY + curR * Math.cos(angle / 2));
        path.moveTo(x1, y1);
        path.lineTo(centerX, centerY);
        curR = (float) (r * data[2]);//当前半径
        float x2 = (float) (centerX - curR * Math.sin(angle / 2));
        float y2 = (float) (centerY + curR * Math.cos(angle / 2));
        path.moveTo(x2, y2);
        path.lineTo(centerX, centerY);
        curR = (float) (r * data[3]);//当前半径
        float x3 = (float) (centerX - curR * Math.sin(angle));
        float y3 = (float) (centerY - curR * Math.cos(angle));
        path.moveTo(x3, y3);
        path.lineTo(centerX, centerY);
        curR = (float) (r * data[4]);//当前半径
        float x4 = (float) (centerX);
        float y4 = (float) (centerY - curR);
        path.moveTo(x4, y4);
        path.lineTo(centerX, centerY);
        path.close();
        canvas.drawPath(path, mainPaint);
    }

    /**
     * 绘制覆盖区域,覆盖区域,只要使用path记录下坐标点,然后设
     *
     * valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);使path包围区域被填充
     * @param canvas
     */
    private void drawRegion(Canvas canvas) {
        Path path = new Path();
        valuePaint.setAlpha(255);
        float pointR = 4;// 小圆点半径
        float r = radius / (count + 2);//r是蜘蛛丝之间的间距
        double percent1 = getPercent(data[0], maxValue);
        float x1 = (float) (centerX + r * percent1 * Math.sin(angle));
        float y1 = (float) (centerY - r * percent1 * Math.cos(angle));
        //绘制小圆点
        path.moveTo(x1, y1);// 移动画笔
        canvas.drawCircle(x1, y1, pointR, valuePaint); // 画圆点
        drawText(canvas,dataValue[0],x1,y1,0); // 画文本
        double percent2 = getPercent(data[1], maxValue);
        float x2 = (float) (centerX + r * percent2 * Math.sin(angle / 2));
        float y2 = (float) (centerY + r * percent2 * Math.cos(angle / 2));
        //绘制小圆点
        path.lineTo(x2, y2); // 画线
        canvas.drawCircle(x2, y2, pointR, valuePaint);
        drawText(canvas,dataValue[1],x2,y2,1);
        double percent3 = getPercent(data[2], maxValue);
        float x3 = (float) (centerX - r * percent3 * Math.sin(angle / 2));
        float y3 = (float) (centerY + r * percent3 * Math.cos(angle / 2));
        //绘制小圆点
        path.lineTo(x3, y3);
        canvas.drawCircle(x3, y3, pointR, valuePaint);
        drawText(canvas,dataValue[2],x3,y3,2);
        double percent4 = getPercent(data[3], maxValue);
        float x4 = (float) (centerX - r * percent4 * Math.sin(angle));
        float y4 = (float) (centerY - r * percent4 * Math.cos(angle));
        //绘制小圆点
        path.lineTo(x4, y4);
        canvas.drawCircle(x4, y4, pointR, valuePaint);
        drawText(canvas,dataValue[3],x4,y4,3);
        double percent5 = getPercent(data[4], maxValue);
        float x5 = (float) (centerX);
        float y5 = (float) (centerY - r * percent5);
        //绘制小圆点
        path.lineTo(x5, y5);
        canvas.drawCircle(x5, y5, pointR, valuePaint);
        drawText(canvas,dataValue[4],x5,y5,4);
        path.lineTo(x1, y1);
        path.close();
        // 链接各个顶点
        valuePaint.setStyle(Paint.Style.STROKE);// 设置镂空
        canvas.drawPath(path, valuePaint);
        //绘制填充区域
//        valuePaint.setAlpha(90);
//        valuePaint.setStyle(Paint.Style.FILL_AND_STROKE);
//        canvas.drawPath(path, valuePaint);
    }

    /**
     * 对数据校验
     * @param data
     * @param maxValue
     * @return
     */
    private static double getPercent(double data, float maxValue) {
        double percent1;
        if (data != maxValue) {
            percent1 = data % maxValue;
        } else {
            percent1 = maxValue;
        }
        return percent1;
    }

    /**
     * 绘制文本
     */
    private void drawText(Canvas canvas , String text, float x,float y,int index){
        float textSize = radius / (count + 6);
        switch (index){
            case 0:
                x += textSize*2;
                break;
            case 1:
                x += textSize*2;
                y += textSize/2;
                break;
            case 2:
                y += textSize*2;
                break;
            case 3:
                x -= textSize*2;
                break;
            case 4:
                y -= textSize;
                break;
        }

        textPaint.setTextSize(textSize);
        textPaint.setTextAlign(Paint.Align.CENTER);// x代表文字中心
        canvas.drawText(text,x,y,textPaint);
    }

    /**
     * 设置各个维度的值范围[0,5] , 数组长度5
     *
     * 分别对应{"态度", "设施", "专业", "效率", "环境"}
     * @param data
     */
    public void setData(double[] data) {
        if (data.length != 5){
            throw new IllegalArgumentException("传入数组长度必须是 : " + count);
        }
        this.data = data;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值