HTML5 Canvas制作雷达图实战

2017年8月4日 422点热度 0人点赞 0条评论

图片

雷达图又叫蜘蛛网图,是一种对各项数据查看很明显的表现图,在很多游戏中,对游戏中的每个角色的分析图一般也用这种图。

下面,用HTML5的Cavas来实现雷达图。

效果 
图片

一、创建Canvas

  1. var mW = 400;

  2. var mH = 400;

  3. var mCtx = null;

  4. var canvas = document.createElement('canvas');

  5. document.body.appendChild(canvas);

  6. canvas.height = mH;

  7. canvas.width = mW;

  8. mCtx = canvas.getContext('2d');

二、制作多边形背景

  1. var mCount = 6; //边数

  2. var mCenter = mW /2; //中心点

  3. var mRadius = mCenter - 50; //半径(减去的值用于给绘制的文本留空间)

  4. var mAngle = Math.PI * 2 / mCount; //角度

  5. var mColorPolygon = '#B8B8B8'; //多边形颜色

  6. // 绘制多边形边

  7. function drawPolygon(ctx){

  8.    ctx.save();

  9.    ctx.strokeStyle = mColorPolygon;

  10.    var r = mRadius/ mCount; //单位半径

  11.    //画6个圈

  12.    for(var i = 0; i < mCount; i ++){

  13.        ctx.beginPath();        

  14.        var currR = r * ( i + 1); //当前半径

  15.        //画6条边

  16.        for(var j = 0; j < mCount; j ++){

  17.            var x = mCenter + currR * Math.cos(mAngle * j);

  18.            var y = mCenter + currR * Math.sin(mAngle * j);

  19.            ctx.lineTo(x, y);

  20.        }

  21.        ctx.closePath()

  22.        ctx.stroke();

  23.    }

  24.    ctx.restore();

  25. }

效果: 
图片

三、连接顶点线

  1. var mColorLines = '#B8B8B8'; //顶点连线颜色

  2. //顶点连线

  3. function drawLines(ctx){

  4.    ctx.save();

  5.    ctx.beginPath();

  6.    ctx.strokeStyle = mColorLines;

  7.    for(var i = 0; i < mCount; i ++){

  8.        var x = mCenter + mRadius * Math.cos(mAngle * i);

  9.        var y = mCenter + mRadius * Math.sin(mAngle * i);

  10.        ctx.moveTo(mCenter, mCenter);

  11.        ctx.lineTo(x, y);

  12.    }

  13.    ctx.stroke();

  14.    ctx.restore();

  15. }

  16. 效果:

  17. ![](http://img.blog.csdn.net/20170305133430976?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVjZXBpbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

  18. ## 四、绘制数据文本

  19. ```javascript

  20. var mData = [['速度', 77],

  21.            ['力量', 72],

  22.            ['防守', 46],

  23.            ['射门', 50],

  24.            ['传球', 80],

  25.            ['耐力', 60]]; //数据

  26. var mColorText = '#000000';

  27. //绘制文本

  28. function drawText(ctx){

  29.    ctx.save();

  30.    var fontSize = mCenter / 12;

  31.    ctx.font = fontSize + 'px Microsoft Yahei';

  32.    ctx.fillStyle = mColorText;

  33.    for(var i = 0; i < mCount; i ++){

  34.        var x = mCenter + mRadius * Math.cos(mAngle * i);

  35.        var y = mCenter + mRadius * Math.sin(mAngle * i);

  36.        //通过不同的位置,调整文本的显示位置

  37.        if( mAngle * i >= 0 && mAngle * i <= Math.PI / 2 ){

  38.            ctx.fillText(mData[i][0], x, y + fontSize);

  39.        }else if(mAngle * i > Math.PI / 2 && mAngle * i <= Math.PI){

  40.            ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y + fontSize);    

  41.        }else if(mAngle * i > Math.PI && mAngle * i <= Math.PI * 3 / 2){

  42.            ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y);  

  43.        }else{

  44.            ctx.fillText(mData[i][0], x, y);

  45.        }

  46.    }

  47.    ctx.restore();

  48. }

  49. <div class="se-section-delimiter"></div>

效果:

图片

五、绘制数据覆盖区域

  1. //绘制数据区域

  2. function drawRegion(ctx){

  3.    ctx.save();

  4.    ctx.beginPath();

  5.    for(var i = 0; i < mCount; i ++){

  6.        var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;

  7.        var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;

  8.        ctx.lineTo(x, y);

  9.    }

  10.    ctx.closePath();

  11.    ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';

  12.    ctx.fill();

  13.    ctx.restore();

  14. }

  15. <div class="se-section-delimiter"></div>

效果: 
图片

六、绘制数据点

把每个数据与线的焦点绘制出来。

  1. //画点

  2. function drawCircle(ctx){

  3.    ctx.save();

  4.    var r = mCenter / 18;

  5.    for(var i = 0; i < mCount; i ++){

  6.        var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;

  7.        var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;

  8.        ctx.beginPath();            

  9.        ctx.arc(x, y, r, 0, Math.PI * 2);

  10.        ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';

  11.        ctx.fill();

  12.    }      

  13.    ctx.restore();

  14. }

  15. <div class="se-section-delimiter"></div>

效果: 
图片

最终代码

  1. <!DOCTYPE html>

  2. <html lang="en">

  3. <head>

  4.  <meta charset="UTF-8">

  5.  <title>Document</title>

  6.  <style type="text/css">

  7.    canvas{

  8.    }

  9.  </style>

  10. </head>

  11. <body>

  12. <script type="text/javascript">

  13.    var mW = 400;

  14.    var mH = 400;

  15.    var mData = [['速度', 77],

  16.                            ['力量', 72],

  17.                            ['防守', 46],

  18.                            ['射门', 50],

  19.                            ['传球', 80],

  20.                            ['耐力', 60]];

  21.    var mCount = mData.length; //边数

  22.    var mCenter = mW /2; //中心点

  23.    var mRadius = mCenter - 50; //半径(减去的值用于给绘制的文本留空间)

  24.    var mAngle = Math.PI * 2 / mCount; //角度

  25.    var mCtx = null;

  26.    var mColorPolygon = '#B8B8B8'; //多边形颜色

  27.    var mColorLines = '#B8B8B8'; //顶点连线颜色

  28.    var mColorText = '#000000';

  29.    //初始化

  30.    (function(){

  31.      var canvas = document.createElement('canvas');

  32.      document.body.appendChild(canvas);

  33.      canvas.height = mH;

  34.      canvas.width = mW;

  35.      mCtx = canvas.getContext('2d');

  36.      drawPolygon(mCtx);

  37.      drawLines(mCtx);

  38.      drawText(mCtx);

  39.      drawRegion(mCtx);

  40.      drawCircle(mCtx);

  41.    })();

  42.      // 绘制多边形边

  43.      function drawPolygon(ctx){

  44.        ctx.save();

  45.        ctx.strokeStyle = mColorPolygon;

  46.        var r = mRadius/ mCount; //单位半径

  47.        //画6个圈

  48.        for(var i = 0; i < mCount; i ++){

  49.            ctx.beginPath();        

  50.            var currR = r * ( i + 1); //当前半径

  51.            //画6条边

  52.            for(var j = 0; j < mCount; j ++){

  53.                var x = mCenter + currR * Math.cos(mAngle * j);

  54.                var y = mCenter + currR * Math.sin(mAngle * j);

  55.                ctx.lineTo(x, y);

  56.            }

  57.            ctx.closePath()

  58.            ctx.stroke();

  59.        }

  60.        ctx.restore();

  61.      }

  62.    //顶点连线

  63.    function drawLines(ctx){

  64.        ctx.save();

  65.        ctx.beginPath();

  66.        ctx.strokeStyle = mColorLines;

  67.        for(var i = 0; i < mCount; i ++){

  68.            var x = mCenter + mRadius * Math.cos(mAngle * i);

  69.            var y = mCenter + mRadius * Math.sin(mAngle * i);

  70.            ctx.moveTo(mCenter, mCenter);

  71.            ctx.lineTo(x, y);

  72.        }

  73.        ctx.stroke();

  74.        ctx.restore();

  75.    }

  76.    //绘制文本

  77.    function drawText(ctx){

  78.        ctx.save();

  79.        var fontSize = mCenter / 12;

  80.        ctx.font = fontSize + 'px Microsoft Yahei';

  81.        ctx.fillStyle = mColorText;

  82.        for(var i = 0; i < mCount; i ++){

  83.            var x = mCenter + mRadius * Math.cos(mAngle * i);

  84.            var y = mCenter + mRadius * Math.sin(mAngle * i);

  85.            if( mAngle * i >= 0 && mAngle * i <= Math.PI / 2 ){

  86.                ctx.fillText(mData[i][0], x, y + fontSize);

  87.            }else if(mAngle * i > Math.PI / 2 && mAngle * i <= Math.PI){

  88.                ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y + fontSize);    

  89.            }else if(mAngle * i > Math.PI && mAngle * i <= Math.PI * 3 / 2){

  90.                ctx.fillText(mData[i][0], x - ctx.measureText(mData[i][0]).width, y);  

  91.            }else{

  92.                ctx.fillText(mData[i][0], x, y);

  93.            }

  94.        }

  95.        ctx.restore();

  96.    }

  97.    //绘制数据区域

  98.    function drawRegion(ctx){

  99.        ctx.save();

  100.        ctx.beginPath();

  101.        for(var i = 0; i < mCount; i ++){

  102.            var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;

  103.            var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;

  104.            ctx.lineTo(x, y);

  105.        }

  106.        ctx.closePath();

  107.        ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';

  108.        ctx.fill();

  109.        ctx.restore();

  110.    }

  111.    //画点

  112.    function drawCircle(ctx){

  113.        ctx.save();

  114.        var r = mCenter / 18;

  115.        for(var i = 0; i < mCount; i ++){

  116.            var x = mCenter + mRadius * Math.cos(mAngle * i) * mData[i][1] / 100;

  117.            var y = mCenter + mRadius * Math.sin(mAngle * i) * mData[i][1] / 100;

  118.            ctx.beginPath();            

  119.            ctx.arc(x, y, r, 0, Math.PI * 2);

  120.            ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';

  121.            ctx.fill();

  122.        }      

  123.        ctx.restore();

  124.    }

  125. </script>

  126. </body>

  127. </html>


往日精选:

2017年 Web 开发趋势

JavaScript 类型的那些事

提高 | 10个JavaScript难点

JavaScript数据结构系列终篇——全系列索引

面向 JavaScript 开发人员的 ECMAScript 6 指南(1 )

面向 JavaScript 开发人员的 ECMAScript 6 指南(2)

面向 JavaScript 开发人员的 ECMAScript 6 指南(3)

如何写好技术简历 —— 实例、模板及工具

29个前端工程师和设计师必备的Chrome插件

陆奇最新演讲:如何成为一个优秀的工程师

这是一个悲伤的程序员爱情故事

WEB缓存探究


小手一抖,资料全有。长按二维码关注京程一灯,阅读更多技术文章和业界动态。

图片

66130HTML5 Canvas制作雷达图实战

这个人很懒,什么都没留下

文章评论