参考文章
1、微信小程序Canvas自绘图表之 仪表图(表盘)
2、canvas 实现环形渐变进度条
效果展示
前言
完整代码可移至参考文章1,若有需要,敬请移步。在此根据需要对样式进行了些修改,在此仅记录绘制表盘的代码。
代码
function drawCircle(item, that) {
//定义画图大小
let width = windowWidth * 0.6;
let height = windowWidth * 0.6;
//获取中心坐标
let centerPoint = {
x: width / 2,
y: height / 2
}
let ctx = wx.createCanvasContext('circle');
ctx.save();
ctx.translate(width / 2, height / 2); //画布移动到中心
let each = 7.7; //每个线之间的间距度数
let len = 270 / each; //总共画270度 每次7.7度 需要画多少条线
let bili = 35 / 27; //比例 每一度代表多少值,用于画值
//最外圈放射性线条
let line = 25; //每根线的长度
let offset = 10; // 特殊度数的额外长度
//最内圈放射性线条
let smallCircleWidth = 6; //内圈线条的长度
let offsetCircle = 15; //内圈线条距离线底部的距离
//颜色
let astart = 77;
let bstart = 188;
let cstart = 27;
let aend = 244;
let bend = 14;
let cend = 14;
let aeach = (aend - astart) / len;
let beach = (bend - bstart) / len;
let ceach = (cend - cstart) / len;
ctx.rotate(45 * Math.PI / 180);
if(!item.curtemp){
item.curtemp = 0;
}
cur = item.curtemp;
let pre = parseInt(item.curtemp / bili / each); //计算当前温度在第几根线
//绘制中间的圆弧
let offsetCircleH = 5;//中间的圆弧距线底部的距离
//圆弧半径
let circleR = centerPoint.y - line - offset;
ctx.beginPath();
//画一条圆弧
// 圆弧起始位置
let startAngle = Math.PI * 0.5;
// 圆弧结束位置,一个整圆(Math.PI*2)乘以比例 + 起始位置
let endAngle = (Math.PI * 2) * (270 / 360) + startAngle;
// 每次绘制的弧度单位,越小颜色分布越均匀,但图形较小时边缘越糙
const unit = 0.13;
// 根据最小弧度单位计算整个圆弧可以切成多少小份
let division = parseInt((endAngle-startAngle)/unit,10);
// 生成渐变色数组
let start = startAngle;
let end = start;
for(let i = 0; i < division; i++){
let color = "rgb(" + (astart + i * aeach) + "," + (bstart + i * beach) + "," + (cstart + i * ceach) + ")";
ctx.beginPath();
ctx.setLineCap("round");
end = start+unit;
ctx.setLineWidth(8);
ctx.setStrokeStyle(color);
ctx.arc(0,0,circleR,start,end);
ctx.stroke();
start+=unit;
}
// ctx.arc(centerPoint.x - (line + offset + offsetCircle + smallCircleWidth * 2) * 2,centerPoint.y -(line + offset + offsetCircle + smallCircleWidth * 2) * 2,circleR,(45 + 45)*Math.PI/180,(45 + 315)*Math.PI/180);
// ctx.setLineWidth(5);
// //线性渲染
// var grad = ctx.createLinearGradient(centerPoint.x - (line + offset + offsetCircle + smallCircleWidth * 2) * 2,centerPoint.y -(line + offset + offsetCircle + smallCircleWidth * 2) * 2, (line + offset + offsetCircle + smallCircleWidth * 2) * 2 - centerPoint.x,centerPoint.y -(line + offset + offsetCircle + smallCircleWidth * 2) * 2);
// for(let i = 0; i < len; i++){
// let color = "rgb(" + (astart + i * aeach) + "," + (bstart + i * beach) + "," + (cstart + i * ceach) + ")";
// grad.addColorStop(((len - i) * each) / 270,color);
// }
// ctx.setStrokeStyle(grad);
// ctx.stroke();
//循环绘制每一根线
for (let i = 0; i < len ; i++) {
if (i > pre) {
ctx.setStrokeStyle("#e0e0e0");
} else {
ctx.setStrokeStyle("rgb(" + (astart + i * aeach) + "," + (bstart + i * beach) + "," + (cstart + i * ceach) + ")");
}
ctx.beginPath();
if(i == pre){
ctx.setLineWidth(6);
}else{
ctx.setLineWidth(5);
}
//设置外圈线条端点样式
ctx.setLineCap("round");
let point = {
x: 0,
y: centerPoint.y
}
let arrivePoint = {
x: 0,
y: point.y - line
}
if (i==pre){
ctx.setStrokeStyle("#149C89");
}
if (i==pre) {
point.y = centerPoint.y - 3;
} else {
point.y = centerPoint.y - offset;
}
ctx.moveTo(point.x, point.y);
ctx.lineTo(arrivePoint.x, arrivePoint.y);
ctx.stroke();
ctx.globalCompositeOperation="source-over";
if (i==pre){
//绘制一个小圆圈
ctx.beginPath();
ctx.setFillStyle('#f2f2f2');
ctx.arc(arrivePoint.x, arrivePoint.y + 2,6,0,2*Math.PI);
ctx.fill();
}
//画内圈线条
ctx.beginPath();
ctx.setStrokeStyle("#f1f1f1");
ctx.setLineWidth(2);
if ( i % 5 == 0){
ctx.setStrokeStyle("#e7e8e9");
}
ctx.moveTo(arrivePoint.x, arrivePoint.y - smallCircleWidth - offsetCircle - offsetCircleH);
ctx.lineTo(arrivePoint.x, arrivePoint.y - offsetCircle - offsetCircleH);
ctx.stroke();
ctx.rotate(each * Math.PI / 180);
}
ctx.restore();
//画中间的数值
let value = (item.curtemp/10 + "") || "0";
let centerFontSize = 35;
ctx.setFontSize(centerFontSize);
ctx.setTextAlign("center");
ctx.setTextBaseline("middle");
//根据数值来判断设置字体颜色
ctx.setFillStyle("rgb(" + (astart + pre * aeach) + "," + (bstart + pre * beach) + "," + (cstart + pre * ceach) + ")");
ctx.fillText(value, centerPoint.x, centerPoint.y);
//画横线
ctx.beginPath(); //创建一条路径
ctx.setStrokeStyle("rgb(" + (astart + pre * aeach) + "," + (bstart + pre * beach) + "," + (cstart + pre * ceach) + ")"); //设置边框为红色
ctx.setLineWidth(3);
ctx.moveTo(centerPoint.x - 30,centerPoint.y + (centerFontSize / 2) ) //描述路径的起点为手指触摸的x轴和y轴
ctx.lineTo(centerPoint.x + 30,centerPoint.y + (centerFontSize / 2) ) //绘制一条直线,终点坐标为手指触摸结束后的x轴和y轴
ctx.stroke()
//画单位
ctx.setFontSize(15);
ctx.setTextAlign("center");
ctx.setTextBaseline("top");
ctx.setFillStyle("#000");
// let unitFontSize = 10;
// ctx.setFontSize(unitFontSize);
// ctx.setTextAlign("left");
// ctx.setTextBaseline("top");
// ctx.setFillStyle("#000");
// ctx.fillText("mmo/L", centerPoint.x + (value.length * centerFontSize / 3.5), centerPoint.y - centerFontSize / 2);
ctx.fillText("mmo/L", centerPoint.x, centerPoint.y + centerFontSize / 2 + 5);
//画刻度单位
let unitFontSize = 10;
ctx.setTextAlign("center");
ctx.setTextBaseline("middle");
ctx.setFillStyle("#666");
//刻度单位圆的半径
let r = centerPoint.x - line - offset - offsetCircle - smallCircleWidth * 2;
//刻度"0"
ctx.setFontSize(unitFontSize);
let xy0 = {
x:centerPoint.x - r * Math.cos(45 * Math.PI / 180),
y:centerPoint.y + r * Math.cos(45 * Math.PI / 180)
}
ctx.fillText(0 + "", xy0.x, xy0.y) ;
//刻度“5”
ctx.setFontSize(unitFontSize);
let xy1 = {
x:centerPoint.x - r * Math.cos((45 - 5 * each) * Math.PI / 180),
y:centerPoint.y + r * Math.cos((45 + 5 * each) * Math.PI / 180)
}
ctx.fillText(5 + "", xy1.x, xy1.y);
//刻度“10”
ctx.setFontSize(unitFontSize);
let xy2 = {
x:centerPoint.x - r * Math.cos((45 - 10 * each) * Math.PI / 180),
y:centerPoint.y + r * Math.cos((45 + 10 * each) * Math.PI / 180)
}
ctx.fillText(10 + "", xy2.x, xy2.y);
//刻度“15”
ctx.setFontSize(unitFontSize);
let xy3 = {
x:centerPoint.x - r * Math.cos((45 - 15 * each) * Math.PI / 180),
y:centerPoint.y + r * Math.cos((45 + 15 * each) * Math.PI / 180)
}
ctx.fillText(15 + "", xy3.x, xy3.y);
//刻度“20”
ctx.setFontSize(unitFontSize);
let xy4 = {
x:centerPoint.x - r * Math.cos((45 - 20 * each) * Math.PI / 180),
y:centerPoint.y + r * Math.cos((45 + 20 * each) * Math.PI / 180)
}
ctx.fillText(20 + "", xy4.x, xy4.y);
//刻度“25”
ctx.setFontSize(unitFontSize);
let xy5 = {
x:centerPoint.x - r * Math.cos((45 - 25 * each) * Math.PI / 180),
y:centerPoint.y + r * Math.cos((45 + 25 * each) * Math.PI / 180)
}
ctx.fillText(25 + "", xy5.x, xy5.y);
//刻度“30”
ctx.setFontSize(unitFontSize);
let xy6 = {
x:centerPoint.x - r * Math.cos((45 - 30 * each) * Math.PI / 180),
y:centerPoint.y + r * Math.cos((45 + 30 * each) * Math.PI / 180)
}
ctx.fillText(30 + "", xy6.x, xy6.y);
//刻度“35”
ctx.setFontSize(unitFontSize);
let xy7 = {
x:centerPoint.x - r * Math.cos((45 - 35 * each) * Math.PI / 180),
y:centerPoint.y + r * Math.cos((45 + 35 * each) * Math.PI / 180)
}
ctx.fillText(35 + "", xy7.x, xy7.y);
ctx.draw();
}