uni-app使用canvas绘制时间刻度以及不显示问题处理
2023-03-28 本文已影响0人
hao_developer
image.png
405da8af391e8ab3d1d8c356a2e4325.jpg
image.png
为了减少性能消耗,把底部半透明圆环、刻度、数字、图标、字符串作为一个canvas
有色进度圆环作为一个canvas,避免重复的进行画,需要用定位进行叠加
有更好的方法欢迎在下方留下宝贵的ideal
修改前
ctx.draw()
修改后
setTimeout(()=>{// uni-app必须加上延迟,不然显示不出来, 亲测
ctx.draw()
}, 100)
项目的构思
canvas中圆的起点都是从三点钟顺时针方向开始的,后面需要用到旋转来调整到快要到九点钟开始画圆ctx.rotate(旋转角度 * Math.PI / 180)
405da8af391e8ab3d1d8c356a2e4325.jpg
image.png
全部代码
<template>
<view>
<view class="content" style="position: relative;width:70vw;height:70vw">
<canvas id="circle" canvas-id="circle" style="width:70vw;height:70vw;"></canvas>
<canvas canvas-id="circlePro"
style="width:70vw;height:70vw;border: 1rpx solid green;position: absolute;left: 0;top: 0;right: 0;bottom: 0;"></canvas>
</view>
<view style="color: white;text-align: center;margin-top: 50rpx;">
{{time}} min
</view>
<view style="display: flex;flex-direction: row;justify-content: space-evenly;margin-top: 50rpx;">
<button @click="clickHandler(1)" @longpress="longHandler(1)" @touchend="endHandler" type="default" style="width: 300rpx;">+1</button>
<button @click="clickHandler(2)" @longpress="longHandler(2)" @touchend="endHandler" type="default" style="width: 300rpx;">-1</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
value: 0, //当前角度对应值
time: 0, //当前角度对应时间
addId: null, //循环增加标识
reduceId: null, //循环减少标识
}
},
onLoad() {
this.drawCircle();
},
methods: {
clickHandler(operation) {//+,-点击事件处理
let value = this.value;
if (operation == 1) {
value++;
if (value > 8) return;
} else {
value--;
if (value < 0) return;
}
this.value = value;
this.drawPro();
this.valueToMin();
},
valueToMin() { //value转化为时间min
const value = this.value;
let time = 0;
switch (value) {
case 0:
time = 0;
break;
case 1:
time = 5;
break;
case 2:
time = 10;
break;
case 3:
time = 15;
break;
case 4:
time = 20;
break;
case 5:
time = 25;
break;
case 6:
time = 30;
break;
case 7:
time = 35;
break;
case 8:
time = 40;
break;
}
this.time = time;
},
longHandler(operation) { //+,-长按事件处理
let value = this.value;
if (operation == 1) {
this.addId = setInterval(() => {
value++;
if (value > 8) return;
this.value = value;
this.drawPro();
this.valueToMin();
}, 200);
} else {
this.reduceId = setInterval(() => {
value--;
if (value < 0) return;
this.value = value;
this.drawPro();
this.valueToMin();
}, 200);
}
},
endHandler() { //+,-短或长按事件处理
clearInterval(this.addId);
clearInterval(this.reduceId);
},
drawPro() { //画白色进度
//定义画图大小
const windowWidth = uni.getSystemInfoSync().windowWidth; //获取屏幕的宽度
let width = windowWidth * 0.7; //canvas宽
let height = windowWidth * 0.7; //canvas高
//获取中心坐标
let centerPoint = {
x: width / 2,
y: height / 2
}
const radius = width / 2;
const ringHD = radius * 0.06;
const ringRadius = radius * 0.8;
let ctx = uni.createCanvasContext('circlePro', this);
ctx.save();
ctx.translate(centerPoint.x, centerPoint.y); //移动中心点到centerPoint点上
ctx.rotate(157.5 * Math.PI / 180); //顺时针旋转角度 90 + 45 + 45 / 2
const value = this.value;
const eachMark = 1 / 8; //0.125 一半 0.0625
ctx.beginPath();
ctx.setStrokeStyle('white');
ctx.setLineCap('round');
ctx.setLineWidth(ringHD);
//0~5和40~45 每一各占有 eachMark / 2
//5~40 每一各占有 eachMark / 5
if (value == 1) {
ctx.arc(0, 0, ringRadius, 0, value * (eachMark / 2) * (1.25 * Math.PI));
} else if (value > 1 && value <= 7) {
ctx.arc(0, 0, ringRadius, 0, (eachMark / 2 + (value - 1) * eachMark) * (1.25 * Math.PI));
} else if (value == 8) {
ctx.arc(0, 0, ringRadius, 0, (eachMark * 8 + (value - 8) * eachMark / 2) * (1.25 * Math.PI));
}
ctx.stroke();
setTimeout(() => {//需要做延迟处理才能够渲染出来
ctx.draw();
}, 50)
},
drawCircle() {//画底部半透明进度背景
//定义画图大小
const windowWidth = uni.getSystemInfoSync().windowWidth; //获取屏幕宽度
let width = windowWidth * 0.7; //canvas宽
let height = windowWidth * 0.7; //canvas高
//获取中心坐标
let centerPoint = {
x: width / 2,
y: height / 2
}
const radius = width / 2;
const ringHD = radius * 0.06;
const ringRadius = radius * 0.8;
const ctx = uni.createCanvasContext('circle', this);
ctx.save();
ctx.translate(centerPoint.x, centerPoint.y); //把中心点移动到centerPoint点上
ctx.rotate(157.5 * Math.PI / 180); //顺时针旋转 90 + 45 + 45 / 2
//画中心圆点
// ctx.beginPath();
// ctx.setStrokeStyle('red');
// ctx.arc(0, 0, 5, 0, 2 * Math.PI);
// ctx.stroke();
ctx.beginPath();
ctx.setStrokeStyle('#66bffa');
ctx.setLineWidth(ringHD);
ctx.setLineCap('round');
ctx.arc(0, 0, ringRadius, 0, 1.25 * Math.PI);
ctx.stroke();
ctx.rotate(-157.5 * Math.PI / 180); //顺时针旋转角度 90 + 45 + 45 / 2
//画小短线
const each = 225 / 8; //225 整个圆弧的角度是225°
for (let index = 0; index < 8; index++) {
ctx.rotate(((index == 0) ? (90 - 45 / 2 + each / 2) : each) * Math.PI / 180); //每个小短线的顺时针旋转角度
ctx.beginPath();
ctx.setLineWidth(1);
ctx.setStrokeStyle('white');
ctx.moveTo(0, radius * 0.765);
ctx.lineTo(0, radius * 0.68);
ctx.stroke();
}
ctx.rotate(-(each * 7 + ((90 - 45 / 2 + each / 2))) * Math.PI / 180); //恢复到画小短线之前的角度
const textRadius = radius * 0.6
//5
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(12);
ctx.fillText('5', -Math.cos(45 / 4 * Math.PI / 180) * textRadius * 1.08, Math.sin(45 / 4 * Math.PI / 180) *
textRadius);
ctx.fill();
//10
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(12);
ctx.fillText('10', -Math.cos(45 / 2 * Math.PI / 180) * textRadius * 1.1, -Math.sin(45 / 2 * Math.PI /
180) * textRadius * 0.8);
ctx.fill();
//15
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(12);
ctx.fillText('15', -Math.cos(45 * Math.PI / 180) * textRadius, -Math.sin(45 * Math.PI / 180) * textRadius);
ctx.fill();
//20
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(12);
ctx.fillText('20', -Math.cos((90 - each / 2) * Math.PI / 180) * textRadius * 1.4, -Math.sin((90 - each /
2) * Math.PI / 180) * textRadius * 0.9);
ctx.fill();
//25
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(12);
ctx.fillText('25', Math.cos((90 - each / 2) * Math.PI / 180) * textRadius * 0.8, -Math.sin((90 - each /
2) * Math.PI / 180) * textRadius * 0.9);
ctx.fill();
//30
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(12);
ctx.fillText('30', Math.cos(45 * Math.PI / 180) * textRadius * 0.8, -Math.sin(45 * Math.PI / 180) *
textRadius * 0.9);
ctx.fill();
//35
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(12);
ctx.fillText('35', Math.cos(45 / 4 * Math.PI / 180) * textRadius * 0.8, -Math.sin(45 / 4 * Math.PI / 180) *
textRadius * 1.4);
ctx.fill();
//40
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(12);
ctx.fillText('40', Math.cos(45 / 4 * Math.PI / 180) * textRadius * 0.85, Math.sin(45 / 4 * Math.PI / 180) *
textRadius);
ctx.fill();
//画中心的图标
const imgWidth = radius * 0.6; //图标的宽
ctx.beginPath();
ctx.drawImage('../../static/su.png', -imgWidth / 2, -imgWidth / 2, imgWidth, imgWidth);
ctx.stroke();
//画图标下的提示字符串
const txtStr = '定时运动';
ctx.beginPath();
ctx.setFillStyle('white');
ctx.setFontSize(15);
const txtWidth = ctx.measureText(txtStr).width;
ctx.fillText(txtStr, -txtWidth / 2, radius * 0.45);
ctx.fill();
setTimeout(() => {//需要做延迟处理才能够渲染出来
ctx.draw();
}, 50)
}
}
}
</script>
<style>
page {
background: #00a8ff;
padding-top: 100rpx;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #00a8ff;
margin: auto;
}
</style>