数据雷达图

作者: 孙静静 | 来源:发表于2018-12-27 19:58 被阅读15次

最近公司项目,需要用到雷达图的效果,echarts的雷达图不太符合公司的需求,所以自己用canvas写了个雷达图的组件。


19-51-37-12-27-25656.gif

奉上代码
html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        body{
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.6);
        }
        #myCanvas{
            position: absolute;
            top: 50px;
            left: 300px;
            background: rgba(0,0,0,0.6);
        }
        img{
            border-radius: 50%;
        }
        .h_box{
            padding: 3px 8px;
            background: #fff;
            color: #333;
            font-size: 12px;
            position: absolute;
            display: none;
        }
    </style>
</head>
<body>
    <canvas id="myCanvas" class="myCanvas">你的浏览器不支持canvas,请升级你的浏览器</canvas>
    <div class="h_box"></div>
</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.js"></script>
<script src="index.js"></script>
<script>
   // 模拟数据
    var data = {
        "list":[
            {
                "name":"业务1",
                "num":30
            },
            {
                "name":"业务2",
                "num":100
            },
            {
                "name":"业务3",
                "num":100
            },
            {
                "name":"业务4",
                "num":85
            },
            {
                "name":"业务5",
                "num":90
            },
            {
                "name":"业务6",
                "num":100
            }
        ]
    }
    var length = data.list.length;
    newCanvas.init({
        length: length,
        data: data.list,
        colorStart: 100,
        colorMiddle: 90,
        colorEnd: 80
    });
</script>
</html>

js

var newCanvas = (function(){
    var bWidth = $(".box").width();
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext('2d');
    var self;
    return {
        animID: undefined,
        init:function(config){
            self = this;
            self.hResize(config.length,config.data,config.colorStart,config.colorMiddle,config.colorEnd); //设置自适应窗口大小
        },
        hResize:function(num,data,colorStart,colorMiddle,colorEnd){
            var h = $(window).get(0).innerWidth;
            if(h<1000){                               //在小分辨率下适配
                canvas.width = "300"; 
                canvas.height = "300";
                var cWidth = canvas.width;
                var cHeight = canvas.height;
                console.log(cWidth,cHeight);
                // 中心点
                var centerX = cWidth/2;
                var centerY = cWidth/2;
                // 半径
                var radius = centerX*0.95;
                self.animate(centerX,centerY,radius,cWidth,cHeight,num,data,colorStart,colorMiddle,colorEnd);
            }else{
                canvas.width = "500";
                canvas.height = "500";
                var cWidth = canvas.width;
                var cHeight = canvas.height;
                console.log(cWidth,cHeight);
                // 中心点
                var centerX = cWidth/2;
                var centerY = cWidth/2;
                // 半径
                var radius = centerX*1;
                self.animate(centerX,centerY,radius,cWidth,cHeight,num,data,colorStart,colorMiddle,colorEnd);
                $("#myCanvas").mousemove(function (event) {
                    let e =  event || window.event;
                    let scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
                    let scrollY = document.documentElement.scrollTop || document.body.scrollTop;
                    let x = e.pageX || e.clientX + scrollX;
                    let y = e.pageY || e.clientY + scrollY;
                    var canvasOffset = $("#myCanvas").offset();
                    var offsetX = canvasOffset.left;
                    var offsetY = canvasOffset.top;
                    mouseX =x - offsetX;
                    mouseY = y - offsetY;
                    $(".h_box").css({
                        "display":"none"
                    });
                    for(var i=0,j=1;i<data.length,j<2*num;i++,j+=2){
                        var dx = mouseX - (centerX+centerX/10*(data[i].num/10-1)*Math.sin(Math.PI*j/num));
                        var dy = mouseY - (centerY+centerX/10*(data[i].num/10-1)* Math.cos(Math.PI*j/num));
                        var dz = 6*6;
                        if(dx*dx+dy*dy<dz){
                            var font = data[i].name + '<br/>'+ '业务百分比:' + '<b>' +data[i].num + '</b>';
                            $(".h_box").html(font);
                            $(".h_box").css({
                                "top":y+10,
                                "left":x-30,
                                "display":"block"
                            })
                            // 给tooltip做适配,不超出
                            var b_left = $(".h_box").position().left;
                            var c_left = $("#myCanvas").position().left;
                            var b_top = $(".h_box").position().top;
                            var c_top = $("#myCanvas").position().top;
                            if(b_left+$(".h_box").width()>c_left+$(".myCanvas").width()){
                                console.log(4656);
                                $(".h_box").css({
                                    "left":x-$(".h_box").width()
                                })
                            }
                            if(b_top+$(".h_box").height()>c_top+$(".myCanvas").height()){
                                $(".h_box").css({
                                    "top":y-$(".h_box").height()
                                })
                            }
                        }
                    }
                });
            }
        },
        drawCircle:function(centerX,centerY,r,lineWidth=1,color="#303079"){       //画圆
            ctx.beginPath();
            ctx.arc(centerX,centerY,r,0,2*Math.PI);
            ctx.setLineDash([]);
            ctx.lineWidth = lineWidth;
            ctx.strokeStyle = color;
            ctx.stroke();
        },
        drawCircleZ:function(centerX,centerY,r,lineWidth=1,color="#303079"){       //画最外层的圆
            ctx.beginPath();
            ctx.arc(centerX,centerY,r,0,2*Math.PI);
            ctx.setLineDash([]);
            ctx.lineWidth = lineWidth;
            ctx.strokeStyle = color;
            ctx.stroke();
            var linearGradient = ctx.createRadialGradient(centerX,centerY,r*0.3,centerX,centerY,r);
            linearGradient.addColorStop(0,'rgba(1,1,118,0.9)');
            linearGradient.addColorStop(1,'rgba(2,2,55,0.8)');
            ctx.fillStyle = linearGradient;
            ctx.fill();
        },
        drawDian:function(centerX,centerY,r,lineWidth=1,num,colorStart,colorMiddle,colorEnd){       //画点
            ctx.beginPath();
            ctx.arc(centerX,centerY,r,0,2*Math.PI);
            ctx.setLineDash([]);
            ctx.lineWidth = lineWidth;
            if(num<=colorStart && num>colorMiddle){
                ctx.strokeStyle = "#4ac097";
                ctx.stroke();
                ctx.fillStyle   = "#4ac097";
                ctx.fill();
            }else if(num<colorMiddle&& num>colorEnd){
                ctx.strokeStyle = "#E9AA3D";
                ctx.stroke();
                ctx.fillStyle   = "#E9AA3D";
                ctx.fill();
            }else{
                ctx.strokeStyle = "#fc536c";
                ctx.stroke();
                ctx.fillStyle   = "#fc536c";
                ctx.fill();
            }
        },
        drawFont:function(centerX,centerY,r,font){       //绘制点旁边的文字
            ctx.beginPath();
            ctx.arc(centerX,centerY,r,0,2*Math.PI);
            ctx.font = "normal 12px 微软雅黑";//字体
            ctx.textBaseline = "middle";//竖直对齐
            ctx.textAlign = "center";//水平对齐 
            ctx.fillText(font,centerX,centerY);//绘制文字
            ctx.fillStyle   = "transparent";
            ctx.fill();
        },
        drawPoint:function(centerX,centerY,r,num,colorStart,colorMiddle,colorEnd){       //画点外环动态效果
            ctx.beginPath();
            ctx.arc(centerX,centerY,r,0,2*Math.PI);
            ctx.lineWidth = 0.5;
            if(num<=colorStart && num>colorMiddle){
                ctx.strokeStyle = "#4ac097";
                ctx.stroke();
            }else if(num<colorMiddle&& num>colorEnd){
                ctx.strokeStyle = "#E9AA3D";
                ctx.stroke();
            }else{
                ctx.strokeStyle = "#fc536c";
                ctx.stroke();
            }
        },
        drawCircleNew:function(centerX,centerY,r,lineWidth=1,color="red"){       //画圆
            ctx.beginPath();
            ctx.arc(centerX,centerY,r,0,2*Math.PI);
            ctx.setLineDash([5,3]);
            ctx.lineWidth = lineWidth;
            ctx.strokeStyle = color;
            ctx.stroke();
        },
        drawLine:function (centerX,centerY,x, y, color, lineWidth=1,lineDash=[]) {      //画线
            ctx.beginPath();
            ctx.setLineDash(lineDash);
            ctx.moveTo(centerX,centerY);
            ctx.lineTo(x,y);
            ctx.lineWidth = lineWidth;
            ctx.strokeStyle = color='rgba(6,73,150,0.6)';
            ctx.stroke();
        },
        drawLineZ:function (centerX,centerY,x, y, color, lineWidth=1,lineDash=[]) {      //画边框线
            ctx.beginPath();
            ctx.setLineDash(lineDash);
            ctx.moveTo(centerX,centerY);
            ctx.lineTo(x,y);
            ctx.lineWidth = lineWidth;
            ctx.strokeStyle = color='rgba(6,73,150,1)';
            ctx.stroke();
        },
        drawSector:function (centerX,centerY,radius,sAngle, eAngle) {                      //画扇形
            let blob = 60;
            let increase = 0;
            if(sAngle < eAngle) {
                increase =  (eAngle - sAngle)/blob;
            }
            else if(sAngle > eAngle) {
                increase = (Math.PI*2 - sAngle + eAngle)/blob;
            }
            else {
                return;
            }
            let angle1 = sAngle;
            let angle2 = sAngle + increase;
            for(let i = 0; i < blob; i++){
                ctx.beginPath();
                ctx.moveTo(centerX,centerY);
                ctx.arc(centerX, centerY, radius, angle1, angle2);
                ctx.fillStyle  = "rgba(0,255,255,"+ i/blob +")";
                ctx.fill(); 
                angle1 = angle2;
                angle2 = angle1 + increase;
                if(angle2 >= Math.PI*2){
                    ctx.beginPath();
                    ctx.moveTo(centerX,centerY);
                    ctx.arc(centerX, centerY, radius, angle1, Math.PI*2);
                    ctx.fillStyle  = "rgba(0,255,255,"+ i/blob +")";
                    ctx.fill();
                    angle1 = 0;
                    angle2 = angle1 + increase;
                }
            } 
        },
        drawLastY:function(x,y){           //绘制中间空出来的圆
            ctx.beginPath();
            ctx.arc(x,y,x*0.05,0,2*Math.PI);
            ctx.lineWidth = 0;
            ctx.fillStyle="#333";
            ctx.fill();
        },
        animate:function(x,y,radius,cWidth,cHeight,num,data,colorStart,colorMiddle,colorEnd){

            var aa = window.requestAnimFrame = (function(){     //设置兼容性
                return  window.requestAnimationFrame       ||
                        window.webkitRequestAnimationFrame ||
                        window.mozRequestAnimationFrame    ||
                        window.oRequestAnimationFrame      ||
                        window.msRequestAnimationFrame     ||
                        function(/* function */ callback, /* DOMElement */ element){
                            window.setTimeout(callback, 1000 / 100);
                        };
            })();
            var angle = Math.PI/4;        //画扇形        
            var scanBegin = 0;
            var scanEnd = angle;
            var pointRadius = 0.5;
            function move() {
                ctx.clearRect(0,0,cWidth,cHeight);  // 清除画布
                for(var i=0;i<=100;i++){
                    self.drawLineZ(x,y,x + Math.sin(Math.PI*i/100*2)*(x*0.95), 
                        y + Math.cos(Math.PI*i/100*2)*(x*0.95),1);
                }
                for(var i=0;i<=num;i++){
                    self.drawLine(x,y,x + Math.sin(Math.PI*i/num*2)*(x*0.99), 
                        y + Math.cos(Math.PI*i/num*2)*(x*0.99),4);
                }
                self.drawCircleZ(x,y,x*0.92,3);           //画圆
                self.drawCircle(x,y,x*0.6,3);
                self.drawCircle(x,y,x*0.3,3);
                
                for(var i = 1; i<=num; i++){                  //画线
                    self.drawLine(x,y,x + Math.sin(Math.PI*i/num*2)*radius, 
                        y + Math.cos(Math.PI*i/num*2)*radius);
                } 
                self.drawSector(x,y,radius,scanBegin,scanEnd);      // 绘制扇形扫描区域
                // 改变点的半径以及扇形的角度
                scanBegin += angle/25;
                scanEnd = scanBegin + angle;
                // 超过阈值变为初始值
                if(scanBegin >= Math.PI*2) {
                    scanBegin = 0;
                    scanEnd = scanBegin + angle;
                }
                pointRadius +=0.02;

                self.drawLastY(x,y);               //画最后一个圆
                for(var i=0,j=1;i<data.length,j<2*num;i++,j+=2){
                        self.drawDian(x+x/10*(data[i].num/10-1)*Math.sin(Math.PI*j/num),x/10*(data[i].num/10-1)* Math.cos(Math.PI*j/num)+y,3,1,data[i].num,colorStart,colorMiddle,colorEnd);
                        self.drawPoint(x+x/10*(data[i].num/10-1)*Math.sin(Math.PI*j/num),x/10*(data[i].num/10-1)* Math.cos(Math.PI*j/num)+y,4+pointRadius,data[i].num,colorStart,colorMiddle,colorEnd);
                        self.drawFont(x+x/10*(data[i].num/10-2)*Math.sin(Math.PI*j/num),x/10*(data[i].num/10-2)* Math.cos(Math.PI*j/num)+y,8,data[i].name);
                }
                if(pointRadius >= 5) pointRadius = 0;
                
                // 再次绘制
                window.requestAnimFrame(move);
            }
            animID = window.requestAnimFrame(move);
        }
    }
})()

相关文章

  • 需求真伪辨别工具

    1 雷达图 雷达图主要是以二维图像展示多维数据的图形,通过雷达图可以直观看出各维度数据之间的差距,一般用于财务领域...

  • pyecharts--雷达图

    数据准备 普通雷达图 雷达图的基本框架出来以后,就需要精细的调整,包括颜色填充,线条调整,以及字体放大等等 雷达图...

  • 数据雷达图

    最近公司项目,需要用到雷达图的效果,echarts的雷达图不太符合公司的需求,所以自己用canvas写了个雷达图的...

  • openpyxl3.0官方文档(15)—— 雷达图

    在工作表中以列或行排列的数据可以在雷达图中绘制。雷达图比较多个数据序列的总值。它实际上是面积图在x轴上的投影。雷达...

  • 手把手教你 Tableau 绘制雷达图(二十七)

    手把手教你 Tableau 绘制雷达图 雷达图又称为蜘蛛图,适用于多维数据(四维以上),且每个维度必须可以排序。 ...

  • echarts 实现雷达图辅助引导线

    echarts 的雷达图,当显示数据的label时,极易出现文字与标线重合的问题。但是雷达图的label又不支持如...

  • Tableau-雷达图、凹凸图

    一、雷达图 数据源:圆12345是构成雷达图的5圈多边形 1.创建数据透视表:满足统一名称,数据类型也一致的的要求...

  • ROS机器人底盘(30)-laser_filters的使用

    1.雷达数据屏蔽需求 使用激光雷达建图和导航,实际应用中,不可能保证雷达在最上层(即车体不会遮挡雷达),一般应用为...

  • 图表的数据返回格式

    柱状图、折线图、雷达图的数据结构 饼状图、圆环图、漏斗图、仪表盘的数据结构 地图的数据结构 散点图的数据结构 sc...

  • 三种方法绘制雷达图,用最快的时间做出最好看的可视化图表

    雷达图是通过多个离散属性比较对象的最直观工具,掌握绘制雷达图的方法将会为生活和工作带来乐趣。 本例数据来源于网络,...

网友评论

    本文标题:数据雷达图

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