1、在页面上添加 canvas 元素
<!-- 如果需要在高 dpr(设备像素比) 下取得更细腻的显示,需要先将 canvas 用属性设置放大,再用样式缩写 -->
<canvas id="canvasId" width="{{200 * pixelRatio}}" height="{{200 * pixelRatio}}" style="width:200px;height:200px;background:pink"/>
2、完成绘制圆环
- 代码演示
Page({
data: {
pixelRatio: '',
},
onLoad() {
var _this = this;
// 获取到设备的像素比,并根据像素比设置canvas画布的缩放比例
dd.getSystemInfo({
success: (res) => {
_this.setData({
pixelRatio: res.pixelRatio
})
}
})
},
onReady() {
// 页面加载完成
var _this = this;
// dd.createSelectorQuery() 获取一个节点查询对象 SelectorQuery;
// selectorQuery.select(selector) 选择当前第一个匹配选择器的节点,选择器支持 id 选择器以及 class 选择器
// selectorQuery.boundingClientRect() 将当前所选择节点的位置信息放入查询结果,返回对象包含 width/height/left/top/bottom/right
// selectorQuery.exec(callback) 将查询结果放入 callback 回调中。查询结果为数组,每项为一次查询的结果,如果当前是节点列表,则单次查询结果也为数组。注意 exec 必须放到onReady函数里调用
dd.createSelectorQuery().select("#canvasId").boundingClientRect().exec(res => {
// 环形进度条变量
let canvasWidth = res[0].width; // canvas元素的宽
let canvasHeight = res[0].height; // canvas元素的高
let outerRadius = 180 // 外环半径
let thickness = 40 // 圆环厚度
let innerRadius = outerRadius - thickness // 内环半径
let x = 0 // 圆心x坐标
let y = 0 // 圆心y坐标
let startAngle = -90 //开始角度
let endAngle = 180 //结束角度
// 创建绘图上下文
var ctx = dd.createCanvasContext('canvasId');
// 将绘图原点移到画布中央,注意:移动的距离不是style里宽高的一半,而是属性设置里宽高的一半,所以需要先*设备像素比再/2
ctx.translate(canvasWidth * _this.data.pixelRatio / 2, canvasHeight * _this.data.pixelRatio / 2);
// 开始绘图
ctx.beginPath();
// 步骤1 绘制外环 ctx.arc(绘图原点x坐标, 绘图原点y坐标, 绘图半径, 开始角度, 结束角度)
ctx.arc(x, y, outerRadius, angle2Radian(startAngle), angle2Radian(endAngle))
// 计算外环与内环第一个连接处的中心坐标,(-(innerRadius + thickness / 2), 0)
let oneCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, endAngle)
// 步骤2 绘制外环与内环第一个连接处的圆环,默认为顺时针方向,刚好是一个圆,从什么角度开始,什么角度结束不重要,但是这个角度线条没有交叉
ctx.arc(oneCtrlPoint.x, oneCtrlPoint.y, thickness / 2, angle2Radian(-180), angle2Radian(180))
// 步骤3 绘制内环,从-90度开始 到 +180度结束,顺时针方向绘制,但是图线是交叉的
// ctx.arc(x, y, innerRadius, angle2Radian(startAngle), angle2Radian(endAngle))
// 步骤4 绘制内环,从 +180度开始 到 -90度结束,逆时针方向绘制,图线是连接的,没有交叉
ctx.arc(x, y, innerRadius, angle2Radian(endAngle), angle2Radian(startAngle), true)
// 计算外环与内环第二个连接处的中心坐标,(0, -(innerRadius + thickness / 2))
let twoCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, startAngle)
// 步骤5 绘制外环与内环第二个连接处的圆环,默认为顺时针方向,刚好是一个圆,从什么角度开始,什么角度结束不重要,但是这个角度线条没有交叉
ctx.arc(twoCtrlPoint.x, twoCtrlPoint.y, thickness / 2, angle2Radian(90), angle2Radian(-270))
// 步骤5 线条模式闭合,可以清楚的观察到线条走向
// ctx.stroke();
// // 步骤6 设置进度条的填充颜色为#eee,如果不设置,默认的填充颜色为black
// ctx.setFillStyle('#eee');
// // 步骤6 填充模式闭合
// ctx.fill();
// 步骤7 设置进度条的填充颜色为线性渐变,如果不设置,默认的填充颜色为black
// ctx.createLinearGradient(起点x坐标, 起点y坐标, 终点x坐标, 终点y坐标) 创建一个线性的渐变色
var lingrad = ctx.createLinearGradient(0, 0, 150, 0);
// addColorStop 创建一个颜色的渐变点
lingrad.addColorStop(0, '#00ABEB');
lingrad.addColorStop(1, '#fff');
ctx.setFillStyle(lingrad);
// // 步骤7-1 观察颜色渐变的规律
// ctx.fillRect(0, 0, 200, 200);
// // 步骤7-1 填充模式闭合
// ctx.fill();
// 步骤7-2 填充模式闭合,仅显示圆环
ctx.fill();
// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中
ctx.draw();
//角度转弧度函数
function angle2Radian(angle) {
return angle * Math.PI / 180
}
//计算圆环上点的坐标函数
function calcRingPoint(x, y, radius, angle) {
let res = {}
res.x = x + radius * Math.cos(angle * Math.PI / 180)
res.y = y + radius * Math.sin(angle * Math.PI / 180)
console.log(res)
return res
}
});
},
});
- 步骤1 ~ 步骤6 的效果图
3、根据百分比,动态渲染圆环
- 代码演示
Page({
data: {
// 设备像素比
pixelRatio: '',
},
onLoad() {
var _this = this;
// 获取到设备的像素比,并根据像素比设置canvas画布的缩放比例
dd.getSystemInfo({
success: (res) => {
_this.setData({
pixelRatio: res.pixelRatio
})
}
})
},
onReady() {
// 页面加载完成
var _this = this;
// dd.createSelectorQuery() 获取一个节点查询对象 SelectorQuery;
// selectorQuery.select(selector) 选择当前第一个匹配选择器的节点,选择器支持 id 选择器以及 class 选择器
// selectorQuery.boundingClientRect() 将当前所选择节点的位置信息放入查询结果,返回对象包含 width/height/left/top/bottom/right
// selectorQuery.exec(callback) 将查询结果放入 callback 回调中。查询结果为数组,每项为一次查询的结果,如果当前是节点列表,则单次查询结果也为数组。注意 exec 必须放到onReady函数里调用
dd.createSelectorQuery().select("#canvasId").boundingClientRect().exec(res => {
// 环形进度条变量
let canvasWidth = res[0].width; // canvas元素的宽
let canvasHeight = res[0].height; // canvas元素的高
let outerRadius = 180 // 外环半径
let thickness = 40 // 圆环厚度
let innerRadius = outerRadius - thickness // 内环半径
let x = 0 // 圆心x坐标
let y = 0 // 圆心y坐标
let startAngle = -90 //开始角度
let endAngle = 180 //结束角度
// 创建绘图上下文
var ctx = dd.createCanvasContext('canvasId');
// 将绘图原点移到画布中央,注意:移动的距离不是style里宽高的一半,而是属性设置里宽高的一半,所以需要先*设备像素比再/2
ctx.translate(canvasWidth * _this.data.pixelRatio / 2, canvasHeight * _this.data.pixelRatio / 2);
ctx.rotate(angle2Radian(225)) // 将画布旋转225度,这是最后一步
// 设置进度条的填充颜色为#eee,如果不设置,默认的填充颜色为black
ctx.setFillStyle('#eee');
// 渲染灰色圆环背景
renderRing(startAngle, endAngle);
// 设置进度条的填充颜色为线性渐变,如果不设置,默认的填充颜色为black
// ctx.createLinearGradient(起点x坐标, 起点y坐标, 终点x坐标, 终点y坐标) 创建一个线性的渐变色
var lingrad = ctx.createLinearGradient(0, 0, 150, 0);
// addColorStop 创建一个颜色的渐变点
lingrad.addColorStop(0, '#00ABEB');
lingrad.addColorStop(1, '#000BE0');
ctx.setFillStyle(lingrad);
// 按照百分比,动态渲染颜色为渐变色的圆环
let tempAngle = startAngle // 每次前进结束时的角度
let total = 1000 // 总分
let now = 800 // 当前分数
let percent = now / total // 百分比
let twoEndAngle = percent * 270 + startAngle // 最后结束时的角度,是一个固定值
let step = (twoEndAngle - startAngle) / 80 // 步长,分为80步,是一个固定值
let inter = setInterval(() => { // 设置并开启定时器
if (tempAngle > twoEndAngle) { // 到达目标角度
clearInterval(inter)
} else { // 未到达目标角度
tempAngle += step
}
renderRing(startAngle, tempAngle)
}, 10)
// 圆环渲染函数
function renderRing(startAngle, endAngle) {
// 开始绘图
ctx.beginPath();
// 绘制外环 ctx.arc(绘图原点x坐标, 绘图原点y坐标, 绘图半径, 开始角度, 结束角度)
ctx.arc(x, y, outerRadius, angle2Radian(startAngle), angle2Radian(endAngle))
// 计算外环与内环第一个连接处的中心坐标,(-(innerRadius + thickness / 2), 0)
let oneCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, endAngle)
// 绘制外环与内环第一个连接处的圆环,默认为顺时针方向,刚好是一个圆,从什么角度开始,什么角度结束不重要,但是这个角度线条没有交叉
ctx.arc(oneCtrlPoint.x, oneCtrlPoint.y, thickness / 2, angle2Radian(-180), angle2Radian(180))
// 绘制内环,从 +180度开始 到 -90度结束,逆时针方向绘制,图线是连接的,没有交叉
ctx.arc(x, y, innerRadius, angle2Radian(endAngle), angle2Radian(startAngle), true)
// 计算外环与内环第二个连接处的中心坐标,(0, -(innerRadius + thickness / 2))
let twoCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, startAngle)
// 绘制外环与内环第二个连接处的圆环,默认为顺时针方向,刚好是一个圆,从什么角度开始,什么角度结束不重要,但是这个角度线条没有交叉
ctx.arc(twoCtrlPoint.x, twoCtrlPoint.y, thickness / 2, angle2Radian(90), angle2Radian(-270))
// 填充模式闭合
ctx.fill();
// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中
ctx.draw();
}
//角度转弧度函数
function angle2Radian(angle) {
return angle * Math.PI / 180
}
//计算圆环上点的坐标函数
function calcRingPoint(x, y, radius, angle) {
let res = {}
res.x = x + radius * Math.cos(angle * Math.PI / 180)
res.y = y + radius * Math.sin(angle * Math.PI / 180)
console.log(res)
return res
}
});
},
});
- 效果图
参考文档:https://www.cnblogs.com/sweeeper/p/11580424.html