uni-app使用canvas绘制时间刻度以及不显示问题处理

2023-03-28  本文已影响0人  hao_developer
image.png

为了减少性能消耗,把底部半透明圆环、刻度、数字、图标、字符串作为一个canvas

有色进度圆环作为一个canvas,避免重复的进行画,需要用定位进行叠加

有更好的方法欢迎在下方留下宝贵的ideal

修改前

 ctx.draw()

修改后

setTimeout(()=>{// uni-app必须加上延迟,不然显示不出来, 亲测 
  ctx.draw() 
}, 100)

项目的构思

canvas中圆的起点都是从三点钟顺时针方向开始的,后面需要用到旋转来调整到快要到九点钟开始画圆ctx.rotate(旋转角度 * Math.PI / 180)

image.png
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>
上一篇下一篇

猜你喜欢

热点阅读