效果图如下:
html:
<canvas id="myCanvas" width="500" height="500"></canvas>
js:
toCanvas(arr) { let canvas = document.getElementById('myCanvas');//获取canvas let ctx = canvas.getContext('2d');//通过getContext获取画图的环境 let cont = 0; //总数 let start = 0; //起始弧度 let x = 250, y = 250; //圆点坐标 let startCoordinate = { start: 200, end: 100 }; //绘制起点坐标 arr.forEach((item) => { cont += item.number; }); //获取number之和 arr.forEach((item) => { ctx.beginPath(); //初始化路径 let prop = item.number / cont; //计算比例 let radian = prop * (Math.PI * 2); //计算弧度 ctx.arc(x, y, 100, start, start + radian, false);//根据比例和弧度画圆 ctx.lineTo(x, y); //连接圆心画线 ctx.fillStyle = item.color; //设置圆弧颜色 ctx.fill(); //填充样式 let x1 = x + Math.cos(radian / 2 + start) * 100;//获取圆弧中间点X坐标 let y1 = y + Math.sin(radian / 2 + start) * 100;//获取圆弧中间点y坐标 ctx.moveTo(x1, y1);//画笔移动到圆弧中点 ctx.lineTo(x1 + 30 * Math.cos(radian / 2 + start), y1 + 30 * Math.sin(radian / 2 + start));//在圆弧中点和圆心的连线上画30单位长度的线 let proNumber = null; if (Math.cos(radian / 2 + start) > 0) { proNumber = 1 } else { proNumber = -1 }//判断起点半径与当前圆弧线所成角的余弦值是为负数/正数 ctx.lineTo(x1 + 30 * Math.cos(radian / 2 + start) + proNumber * 30, y1 + 30 * Math.sin(radian / 2 + start));//在之前线的基础上画一条30单位长度的水平线 ctx.fillText(item.name, x1 + 30 * Math.cos(radian / 2 + start) + proNumber * 20, y1 + 30 * Math.sin(radian / 2 + start) - 5, 30);//在线上填充字体,设置字体的坐标,最大长度 ctx.strokeStyle = item.color;//设置线条和字体的颜色 ctx.font = "bold 10px consolas";//设置字体的样式 start += radian;//每次圆弧渲染完成将弧度累加作为下个圆弧的初始弧度 ctx.stroke();//渲染线条 }) let small = new Path2D(ctx);//创建新的一个路径 small.arc(x, y, 60, 0, Math.PI * 2, false);//画圆 ctx.fillStyle = "#fff";//设置圆的颜色 ctx.fill(small);//填充small },
let arrs = [{ name: '1号', color: '#CD853F', number: 500 }, { name: '2号', color: '#FFA500', number: 500 }, { name: '3号', color: '#FF4500', number: 200 }, { name: '4号', color: '#8B0000', number: 300 }, { name: '5号', color: '#DAA520', number: 50 }, ] this.toCanvas(arrs);
有些不满意的是文字没有和底下的线条保持一致的margin,也找了很多方法依然没有成功。有大神看到了麻烦指点一下。万分感谢。