示例代码托管在:http://www.github.com/dashnowords/blogs

博客园地址:《大史住在大前端》原创博文目录

华为云社区地址:【你要的前端打怪升级指南】

一. 任务说明

使用原生canvasAPI绘制雷达图。(截图以及数据来自于百度Echarts官方示例库【查看示例链接】)。

二. 重点提示

雷达图绘制的看起来并不复杂,无非就是一些路径点的连线,其中的难点都在于一些细节。

  1. 坐标转换

    为了避免在绘制过程中不断根据夹角来计算某个数据点的坐标,我们可以让坐标系先移动到绘图中心,然后在绘制过程中逐步旋转并使用context.lineTo(x,y)来连线即可,这样做的好处是很明显的。比如在绘制背景六边形的时候,每次旋转后,路径点压根就不需要移动,直接在循环中每次都调用context.lineTo( )方法连线至同一个数据点即可,看起来位移没有变,实际上随着坐标系的旋转,连线绕过的是多边形的轨迹。

  2. 文字的对齐

    为了让文字保持正常的方向,我们需要将坐标系的旋转恢复到初始状态再进行绘制。绘制的过程中可以根据绘制点和中心连线相对于x轴的角度来动态修改其绘制时的相对点(left,right,center),否则就会出现下图的结果,也就是文字区域的中心到图形中心的距离的确是一致的,但这并不是我们想要的效果。

  1. canvas坐标系

    请时刻记得canvas坐标系的初始方向是x轴向右,y轴向下,和普通笛卡尔坐标系是不一样的,尤其是在旋转角度和坐标计算的时候,很容易出现和预期角度不相符的结果。

三. 示例代码

  1. //options数据来自于百度Echarts官方示例库
  2. start(options);
  3. /**
  4. * 绘制图表
  5. */
  6. function start(options) {
  7. drawBg(options);
  8. drawData(options);//绘制雷达图
  9. drawText(options);//绘制文字
  10. }
  11. function drawBg(options) {
  12. let length = options.radar.indicator.length;
  13. let angleStep = -2 * Math.PI / length;
  14. context.strokeStyle="#b2b2b2";
  15. context.lineWidth = 1;
  16. //调整坐标系
  17. //移动中心点
  18. context.translate(500,300);
  19. //将x轴旋转至竖直向上
  20. context.rotate(-90 * 2 * Math.PI / 360);
  21. //每次以不同旋转半径绘制多个由大到小的图形
  22. for(let r = 200; r > 0 ; r -=40){
  23. //移动至第一个绘图点
  24. context.save();
  25. context.beginPath();
  26. context.moveTo(r,0);
  27. //转动坐标系绘制所有点
  28. for(let i = 0; i < length; i++){
  29. context.rotate(angleStep);
  30. context.lineTo(r,0);
  31. }
  32. context.closePath();
  33. context.stroke();
  34. //明暗色替换填充,此处从大到小切换颜色覆盖式绘制即可
  35. context.fillStyle = Math.round(r / 40) % 2 ? 'white':'#eaeaea';
  36. context.fill();
  37. context.restore();
  38. }
  39. }
  40. /**
  41. * 绘制数据
  42. */
  43. function drawData(options) {
  44. //解构赋值拿到数据关键点
  45. let {radar:{indicator:indicators},series:[{data:data}]} = options;
  46. let colors = ['#c43e3a','#364c5a'];
  47. let length = indicators.length;
  48. let angleStep = -2 * Math.PI / length;
  49. for(let i = 0; i < data.length; i++){
  50. context.save();
  51. context.beginPath();
  52. context.moveTo(200 * data[i].value[0] / indicators[0].max,0);
  53. //遍历每组数据
  54. for(let j = 1; j < data[i].value.length; j++){
  55. context.rotate(angleStep);
  56. context.lineTo(200 * data[i].value[j] / indicators[j].max,0);
  57. }
  58. context.restore();
  59. context.lineTo(200 * data[i].value[0] / indicators[0].max,0);
  60. context.strokeStyle = colors[i];
  61. context.lineWidth = 2;
  62. context.stroke();
  63. }
  64. context.restore();
  65. }
  66. //绘制文字
  67. function drawText(options) {
  68. let {radar:{indicator:indicators}} = options;
  69. let length = indicators.length;
  70. let angleStep = 2 * Math.PI / length;
  71. let r = 220;
  72. context.fillStyle = 'black';
  73. context.font = "14px bold 黑体";
  74. context.textAlign = 'center';
  75. context.rotate(90 * Math.PI * 2 / 360);
  76. for(let i = 0; i < indicators.length; i++){
  77. let curAngle = -90*2*Math.PI/360 - angleStep*i;
  78. //根据方向调整文字的对齐点
  79. let cos = Math.cos(curAngle);
  80. if (Math.abs(cos) < 10e-4) {
  81. context.textAlign = 'center';
  82. }else if(cos > 0){
  83. context.textAlign = 'left';
  84. }else{
  85. context.textAlign = 'right';
  86. }
  87. console.log(indicators[i].name, Math.cos(curAngle))
  88. context.fillText(indicators[i].name, r * Math.cos(curAngle), r * Math.sin(curAngle));
  89. }
  90. }

浏览器中可查看效果:

百度Echarts官方示例库中有这样一个雷达图的示例,展示了在雷达图上表现时间维度的示例,感兴趣的读者可以自行查看。

【带着canvas去流浪(6)】绘制雷达图的更多相关文章

  1. 【带着canvas去流浪】(2)绘制折线图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 3.1 一般折线图 3.2 用贝塞尔曲线绘制平滑折线图 四. 大数据量场景 示例代码托管在:https://github.com/dashnowo ...

  2. 带着canvas去流浪系列之二 绘制折线图

    [摘要] 用canvasAPI实现echarts简易图表 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  3. 带着canvas去流浪系列之六 绘制雷达图

    [摘要] 用canvas原生API实现百度Echarts基本图表. 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvas ...

  4. 【带着canvas去流浪(7)】绘制水球图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 四. 文字淹水效果的实现 五. 关于canvas抗锯齿 六. 小结 示例代码托管在:http://www.github.com/dashnowor ...

  5. 带着canvas去流浪系列之七 绘制水球图

    [摘要] 用原生canvasAPI实现百度echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  6. 【带着canvas去流浪(5)】绘制K线图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:<大史住在大前端>原创博文 ...

  7. 带着canvas去流浪系列之五 绘制K线图

    [摘要] 用canvas原生API实现百度Echarts 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 任务说明 使用原生canvasAPI绘制 ...

  8. 【带着canvas去流浪(4)】绘制散点图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 四.散点hover交互效果的实现 4.1 基本算法 4.2 参考代码 4.3 Demo中的小问题 示例代码托管在:http://www.githu ...

  9. 【带着canvas去流浪】 (3)绘制饼图

    目录 一. 任务说明 二. 重点提示 三. 示例代码 四. hover高亮的实现思路 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址:< ...

随机推荐

  1. Python的list用法笔记

    今天做leetcode的str反转,学到了不少python的用法,这里做个笔记: str和list互相转换 str转list >>> a='apple' >>> l ...

  2. postman-----使用CSV和Json文件实现批量接口测试

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px ".PingFang SC"; color: #454545 } span ...

  3. RPC基于http协议通过netty支持文件上传下载

    本人在中间件研发组(主要开发RPC),近期遇到一个需求:RPC基于http协议通过netty支持文件上传下载 经过一系列的资料查找学习,终于实现了该功能 通过netty实现文件上传下载,主要在编解码时 ...

  4. Netty实现高性能IOT服务器(Groza)之手撕MQTT协议篇上

    前言 诞生及优势 MQTT由Andy Stanford-Clark(IBM)和Arlen Nipper(Eurotech,现为Cirrus Link)于1999年开发,用于监测穿越沙漠的石油管道.目标 ...

  5. 死磕 java集合之LinkedTransferQueue源码分析

    问题 (1)LinkedTransferQueue是什么东东? (2)LinkedTransferQueue是怎么实现阻塞队列的? (3)LinkedTransferQueue是怎么控制并发安全的? ...

  6. eShopOnContainers 知多少[10]:部署到 K8S | AKS

    1. 引言 断断续续,感觉这个系列又要半途而废了.趁着假期,赶紧再更一篇,介绍下如何将eShopOnContainers部署到K8S上,进而实现大家常说的微服务上云. 2. 先了解下 Helm 读过我 ...

  7. 使用Rotativa在ASP.NET Core MVC中创建PDF

    在本文中,我们将学习如何使用Rotativa.AspNetCore工具从ASP.NET Core中的视图创建PDF.如果您使用ASP.NET MVC,那么Rot​​ativa工具已经可用,我们可以使用 ...

  8. No module named MySQLdb

    解决办法 easy_install mysql-python (mix os) pip install mysql-python (mix os/ python 2) pip install mysq ...

  9. SQL 横转竖 、竖专横(转载) 列转行 行转列

    普通行列转换 问题:假设有张学生成绩表(tb)如下: 姓名 课程 分数 张三 语文 张三 数学 张三 物理 李四 语文 李四 数学 李四 物理 想变成(得到如下结果): 姓名 语文 数学 物理 --- ...

  10. JAVA的特性

    JAVA有三大特性:封装,继承和多态 一. 封装 封装就是将类的信息隐藏在类内部,不允许外部程序直接访问,而是通过该类的方法实现对隐藏信息的操作和访问. 封装的实现 a. 需要修改属性的访问控制符(修 ...