首先需求设计稿如下,其中3个点(箭头指向)需要根据数据分值在实线半径上移动,同时阴影三角形面积随之改变。

1 首先尝试有没有现成的轮子,echarts中找了一下,有相同的,但是改成完全一样,有些麻烦 需要修改源代码,其本身提供的API不满足于需求。 当然如果时间紧急,可以跟产品设计沟通,让他们妥协。

2 自己画,首先我使用了前端canvas. 在html中加入一个dom

<canvas id='radar-img' style="width:170;height:170" />

画布的宽高需要用css定义。
然后就是基本代码,创建canvas,把底部图放上去,然后放点位图,代码我就不写了因为不好使。
缺点1 画布调整和图片原图大小保持一致 , 图片也是模糊的
缺点2 图片的宽高和坐标都不能按照代码上的逻辑保持一致,调试非常困难。
所以没多想,就放弃了,之前也有过html2canvas的bug,在不同设备的兼容性也不好。

最终方案是用node-canvas, 在服务端画图,发接口返回一个base64的图片到前端,前端只需要把数据给接口,接口返回一张画好的图片。在服务端没有设备兼容性的困扰,画图调试也一步到位。
由于固定了3个维度的分值数据,所以地图直接把所有的圆环和120度线直接切好,于是我让设计给我了2张图 (当然一张图不要也能画完,主要是费时间)
如下:

此时我们可以用大一点的图,画布也大一点,这样比较清晰
画之前我已经把实现思路想好了,主要用到了一个数学公式
一个坐标点绕圆点旋转一定角度后的坐标
直角三角形函数在这里居然排上用场
最终代码如下:(代码完整,安装依赖可独立运行)

var app = express();
const { createCanvas, loadImage } = require('canvas');//使用中间件body-parser获取post参数
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());app.use(function (req, res, next) {res.header("Access-Control-Allow-Origin", req.headers.origin);res.header("Access-Control-Allow-Credentials", "true");res.header("Access-Control-Allow-Methods", "GET, POST, PUT,DELETE,OPTIONS,PATCH");res.header("Access-Control-Allow-Headers", "channel, mch_id, cache-control, authorization, client, x-cookie, content-type");res.header("Access-Control-Request-Headers", "Origin, X-Requested-With, content-Type, Accept, Authorization");res.header("X-Powered-By", ' 3.2.1');res.header("Content-Type", "application/json;charset=utf-8");console.log(req.query.score_1,req.query.score_2,req.query.score_3);var bgImg = 'https://jdxl-img.jdxlt.com/uploads/7f92fb1b31dd45d9aef6892001bae3f4.png';var pointImg = 'https://jdxl-img.jdxlt.com/uploads/cc614fbdd32a49da827cdf201a7f43c7.png';const canvas = createCanvas(680, 680);const ctx = canvas.getContext('2d');var promise_1 = new Promise(function(resolve, reject){loadImage(bgImg).then((image) => {resolve(image);})})var promise_2 = new Promise(function(resolve, reject){loadImage(pointImg).then((image) => {resolve(image);})})const calculateRotate = (point, degree) => {let x = point.x * Math.cos(degree * Math.PI / 180) + point.y * Math.sin(degree * Math.PI / 180);let y = -point.x * Math.sin(degree * Math.PI / 180) + point.y * Math.cos(degree * Math.PI / 180);let relativeOriginPoint = {x: Math.round(x * 100) / 100,y: Math.round(y * 100) / 100};return relativeOriginPoint;};Promise.all([promise_1,promise_2]).then(function(data){var point_2 = calculateRotate({x:0,y:Math.round(340-(340*req.query.score_2/100))},120);var point_3 = calculateRotate({x:0,y:Math.round(340-(340*req.query.score_3/100))},240);// 三角形阴影ctx.beginPath();ctx.moveTo(340,(340-Math.round(340*(100-req.query.score_1)/100))); // 因为圆点1没有旋转度数y轴为正ctx.lineTo(340+point_2.x,340-point_2.y);ctx.lineTo(340+point_3.x,340-point_3.y);ctx.fillStyle='rgba(109, 128, 157, 0.3)';// 透明度填充ctx.globalAlpha=0.5;ctx.fill();// 恢复透明度 画上3个点ctx.globalAlpha=1;ctx.drawImage(data[0],0,0,680,680); // 背景图ctx.drawImage(data[1],(340-24),(340-Math.round(340*(100-req.query.score_1)/100))-24,48,48); // 图像点ctx.drawImage(data[1],(point_2.x+340-24),(340-point_2.y-24),48,48); // 图像点ctx.drawImage(data[1],(point_3.x+340-24),(340-point_3.y-24),48,48); // 图像点let result = {code: 0,msg: '',data:canvas.toDataURL()}res.send(JSON.stringify(result));})})app.listen(1320,function(){console.log('port 1320 is running!');
});

其中需要注意

1 跨域解决方案代码

  res.header("Access-Control-Allow-Origin", req.headers.origin);res.header("Access-Control-Allow-Credentials", "true");res.header("Access-Control-Allow-Methods", "GET, POST, PUT,DELETE,OPTIONS,PATCH");res.header("Access-Control-Allow-Headers", "channel, mch_id, cache-control, authorization, client, x-cookie, content-type");res.header("Access-Control-Request-Headers", "Origin, X-Requested-With, content-Type, Accept, Authorization");res.header("X-Powered-By", ' 3.2.1');res.header("Content-Type", "application/json;charset=utf-8");

2 一个坐标点绕圆点旋转一定角度后的坐标方法(用 0, 90 旋转90度做了验证 ,其后实践也确实好用)

 const calculateRotate = (point, degree) => {let x = point.x * Math.cos(degree * Math.PI / 180) + point.y * Math.sin(degree * Math.PI / 180);let y = -point.x * Math.sin(degree * Math.PI / 180) + point.y * Math.cos(degree * Math.PI / 180);let relativeOriginPoint = {x: Math.round(x * 100) / 100,y: Math.round(y * 100) / 100};return relativeOriginPoint;};

剩下的就是canvas基础功能api,查一查都有:
1 如何画三角形
2 如何设置透明度
3 画图的时候可以定义坐标和宽高
4 左上角是坐标点(0,0)和正常坐标系的y轴是反的,且旋转的点不是原点,是其中一个坐标 所以需要计算一下

最后结果:

用canvas画圆形雷达图相关推荐

  1. canvas 绘制动态雷达图

    canvas 绘制动态雷达图 最近收到一个需求,需要做一个预定的动态雷达图,于是绞尽脑汁,基于canvas 终于实现如图的效果: 图片效果: 我是基于vue 来实现的,现在让我们看看具体是如何实现的: ...

  2. h5页面的雷达图 五边形_konva canvas插件写雷达图示例

    最近,做了一个HTML5的项目,里面涉及到了雷达图效果,这里,我将react实战项目中,用到的雷达图单拎出来写一篇博客,供大家学习. 以下内容涉及的代码在我的gitlab仓库中: Konva canv ...

  3. uni使用echarts自定义图标(圆形雷达图)

    echarts.vue组件 <template><view><view class="echarts" :id="option.id&quo ...

  4. 以二维振动为例展示使用matlab画圆形三维图的偷懒方法

    画图主要是用极坐标,我们使用画复数的函数来画. clc;%清空上次的 %draw_Bessel%画这个东西 a=4;%圆形半径% %定义角向和径向的步长和范围 fai=[-4:0.1:4]; r=[0 ...

  5. 如何用 canvas 画出分形图

    前言 分形是一门以非规则几何形态为研究对象的几何学,由曼德勃 罗(B.B.Mandelbrot)等人创立并命名. 分形图从整体上看,是处处不规律的.但从局部观察,图形的规则性又是相同的,即具有自相似的 ...

  6. Canvas 画占比图 解决canvas锯齿 bug

    案例如图: <section class=" chartWrap"> <div class="chartContent"> <di ...

  7. 微信小程序使用canvas画海报分享图

    项目场景: 很多小程序都会有一些分享海报的需求.因为我这边之前一直都是后端直接生成一张图片然后返回了的,我前端直接把路径放上去就可以了.但是,有时候后端没直接生成海报,而是只生成了一个二维码,这时候就 ...

  8. Canvas画圆形刻度表

    上需求,一个渐变的圆 let go ,尺寸有点大,到项目里面在详细调一下吧 <!DOCTYPE html> <html lang="en"><head ...

  9. 微信小程序canvas 画圆形带刻度进度条

    .canvas_1{ position: absolute; width: 120rpx; height: 120rpx; background: rgba(255, 00, 0, 0.0); } & ...

  10. 微信小程序 使用canvas画圆形倒计时动画

    参考文档:https://www.cnblogs.com/quietxin/p/9418813.html 效果: wxml页面 <view class="container" ...

最新文章

  1. Bert系列(三)——源码解读之Pre-train
  2. 初学者css常见问题_5分钟内学习CSS Grid-初学者教程
  3. switchyomega规则列表备份_求人不如求己,自己动手写一个CSDN博客备份小工具?...
  4. 开发日记-20190914 关键词 汇编语言王爽版 第五章
  5. 曳舞---1、曳舞各个动作要点
  6. DropDownList联动
  7. Python隐藏属性
  8. 2015/Province_C_C++_C/6/奇妙的数字
  9. zabbix解决中文乱码
  10. 字符串和datatime.time类型转为秒
  11. 使用mysqldump备份数据库
  12. 视频会议、视频聊天、手机视频、跨平台视频如何开发之流程篇
  13. linux下升级mysql_linux下mysql升级
  14. WAP PUSH介绍
  15. 51CTO微职位一次通过PMP之经验浅谈
  16. 密码学系列——NTHASH以及MD4算法
  17. 知了课堂 python_知了课堂Python Flask系列(1)-基础篇 flask视频教程下载
  18. 继电保护原理5-变压器保护
  19. 从U盘还原完ghost系统,重启就提示bootmgr is missing
  20. Google推荐的图片加载库Glide介绍

热门文章

  1. 基于二值距离变换的图像细化的代码实现
  2. 移动硬盘写速度不到1M
  3. Ubuntu移动硬盘下载
  4. android读sdcard大文件系统,Android中使用SDcard读取文件
  5. 几行烂代码,用错 Transactional,我赔了16万
  6. 翻译Allegorithmic的文档《THE PBR GUIDE - PART 1》
  7. 剑指offer 数组中出现次数超过一半的数字
  8. 三国志战略版:北定中原剧本个性加点指引
  9. OpenGL(十五)——Qt OpenGL三种不同的纹理滤波方式、光照、物体的移动
  10. 随机密聊 匿名聊天室程序源码