[uni-app] canvas绘制圆环进度条

文章目录

    • 需求
    • 参考链接
    • 基本问题的处理
      • 1:画布旋转的问题
      • 2:注意arc()的起始位置是3点钟方向
      • 3: 如果绘制1.9*Matn.PI的圆环, 要保证其实位置在0点方向?
      • 4:小线段怎么画, 角度怎么处理?
    • 源码

需求

要绘制一个如此的进度条
在这里插入图片描述

参考链接

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

官网api

基本问题的处理

其实基本看参考链接学着搞, 不难的 . 主要是针对一些api的坑,要有了解就可以.

1:画布旋转的问题

在这里插入图片描述

2:注意arc()的起始位置是3点钟方向

在这里插入图片描述

3: 如果绘制1.9*Matn.PI的圆环, 要保证其实位置在0点方向?

在这里插入图片描述

			//0.1把画布先 逆时针旋转90度, 从0点绘制开始绘制baseCtx.rotate(-90 * Math.PI / 180)

梳理一下流程, 如果要画一个圆环, 且要保证起始点是0点方向, 步骤是
1.画布逆时针旋转90度
2.画圆操作
3.恢复画布旋转角度(因为rotate()角度会叠加,为了防止计算混乱, 可以旋转画布)

(有人会问执行第三点,不会把绘制的圆环又逆回去? 这里要明确的是, 画布是画布(即context), 绘制好的图像是绘制好的图像)

在这里插入图片描述

4:小线段怎么画, 角度怎么处理?

首先360°的圆,分成10份, 角度单位是36°
那么处理办法也是一样的
for循环内
1.画布旋转36° / 72° / 108° …
2.绘制小线段
3.画布恢复 36° / 72° / 108° …

在这里插入图片描述
绘制出的10等分小线段已经完成, 想要做到如下图效果. 我们只要在for循环内, 选出i=0,6,8即可
(即 100% 60% 80%进度)
在这里插入图片描述
但是问题来了…
实际效果如下
在这里插入图片描述
好像不对了…

通过控制不同下标的小线段的绘制, 得到如下的分析图,
(小线段因为是基于moveTo/lineTo,绘制的)
在这里插入图片描述
当i越大,小线段的起始点与结束点的距离也越大, 所以i=0的时候, 小线段最短,
在这里插入图片描述
那么我们就发现, 他是从原始画布的90°方向开始绘制的,

我们为了要得到从0点位置那就是对画布进行逆时针的180°旋转
在这里插入图片描述

那么步骤就是
for循环内
1.画布旋转36°-180° / 72°-180° / 108°-180° …
2.绘制小线段
3.画布恢复 逆向的 36°-180° / 72°-180° / 108°-180° …

于是得到了

在这里插入图片描述
再进过处理

在这里插入图片描述

再把圆环补全,去掉不用的小线段
在这里插入图片描述
与效果图对比(UI图实际是有点错误的,但这不重要)
在这里插入图片描述
最终效果:

	<scoreLevelCanvas :score="277" :progress="0.4"></scoreLevelCanvas>

在这里插入图片描述

<scoreLevelCanvas :score="277" :progress="0.68"></scoreLevelCanvas>

在这里插入图片描述

<scoreLevelCanvas :score="277" :progress="0.97"></scoreLevelCanvas>

在这里插入图片描述

源码

<template><view class="score-level-box" :style="{'width':reactWH+'px','height':reactWH+'px'}"><!-- baseCanvas --><canvas id="scoreLevelBase" canvas-id="scoreLevelBase":style="{'width':reactWH+'px','height':reactWH+'px'}"></canvas><!-- progressCanvas --><canvas id="scoreLevelProgress" canvas-id="scoreLevelProgress"style="position: absolute;left: 0;top:0":style="{'width':reactWH+'px','height':reactWH+'px'}"></canvas><view class="score-view" :style="{'fontSize':scoreFontSize+'px','color':strokeColor}">{{scoreString}}</view></view>
</template><script>export default {name: "scoreLevelCanvas",props: {// canvas视图的宽高(矩形->正方形)reactWH: {type: Number,default: () => 200,},// 进度progress: {type: Number,default: () => 0.4},score: {type: Number,default: () => 20,}},data() {return {baseCtx: null,progressCtx: null,};},computed: {// 计算中心点XcenterPointX() {return this.reactWH / 2;},// 计算中心点YcenterPointY() {return this.reactWH / 2;},//计算半径radius() {return this.reactWH / 2 * 0.9;},//计算小线段绘制的起始 - 偏内0.1个半径dotLineMoveTo() {return this.reactWH / 2 * (0.9 - 0.1);},//计算小线段绘制的结束 - 偏外0.1个半径dotLineLineTo() {return this.reactWH / 2 * (0.9 + 0.1);},//计算进度环的厚度progressWidth() {// 进度环的厚度, 设置为半径的8%return (this.reactWH / 2) * 0.08;},//计算小线段的厚度dotLineWidth() {// 小线段的厚度, 同圆环厚度return (this.reactWH / 2) * 0.08;},//计算进度环颜色strokeColor() {let strokeColor = ""if (this.progress < 0.6) {strokeColor = "#EA532F"} else if (this.progress >= 0.6 && this.progress < 0.8) {strokeColor = "#F9B93C"} else if (this.progress >= 0.8) {strokeColor = "#4CBA85"}return strokeColor},//计算得分字段scoreString() {return (this.score || "") + "分"},//计算得分字体大小scoreFontSize() {return this.radius * 0.4}},mounted() {// 绘制 基础圆样式this.drawScoreLevelBaseView()// 绘制 动态进度圆this.drawScoreLevelProgressView()// 最终绘制 - draw()this.draw()},methods: {// 绘制 基础圆样式drawScoreLevelBaseView() {const baseCtx = uni.createCanvasContext("scoreLevelBase", this);baseCtx.save();// 把圆心移到矩形中心点baseCtx.translate(this.centerPointX, this.centerPointY);//0.1把画布先 逆时针旋转90度, 从0点绘制开始绘制baseCtx.rotate(-90 * Math.PI / 180)//0.2绘制圆心, 方便观察// baseCtx.beginPath()// baseCtx.setStrokeStyle('#090')// baseCtx.arc(0, 0, 3, 0, 2 * Math.PI)// baseCtx.stroke()//1.绘制基础圆baseCtx.beginPath()baseCtx.setStrokeStyle("#EAEAEA")baseCtx.setLineWidth(this.progressWidth)baseCtx.setLineCap('round')baseCtx.arc(0, 0, this.radius, 0, 2 * Math.PI)baseCtx.stroke()//1.1恢复旋转角度(目的是恢复画布)baseCtx.rotate(90 * Math.PI / 180)//2. 绘制小线段 (360°/10)for (var i = 0; i < 10; i++) {// 计算每个小线段的旋转角度- 顺时针旋转画布// 发现,小线段在原始画布下, 是从90°方向顺时针绘制的, 因此要逆时针旋转180°let rotateDeg = i * 36 - 180baseCtx.rotate(rotateDeg * Math.PI / 180)baseCtx.beginPath()baseCtx.setLineWidth(0.3) // 预设一个极细的厚度,baseCtx.setLineCap('round')baseCtx.setStrokeStyle('#EAEAEA')// baseCtx.moveTo(0, this.dotLineMoveTo - (i * 8)) // (i*8)为了测试方便,baseCtx.moveTo(0, this.dotLineMoveTo)baseCtx.lineTo(0, this.dotLineLineTo)// 保留 100% 60% 80%进度的小线段if (i == 0 || i == 6 || i == 8) {baseCtx.setLineWidth(this.dotLineWidth)}baseCtx.stroke()// 绘制完成小线段后, 恢复画布旋转角度;baseCtx.rotate(-rotateDeg * Math.PI / 180)}this.baseCtx = baseCtx;},// 绘制 进度圆drawScoreLevelProgressView() {const progressCtx = uni.createCanvasContext("scoreLevelProgress", this);progressCtx.save();// 把圆心移到矩形中心点progressCtx.translate(this.centerPointX, this.centerPointY);//0.1把画布先 逆时针旋转90度, 从0点绘制开始绘制progressCtx.rotate(-90 * Math.PI / 180)//0.2绘制圆心, 方便观察// progressCtx.beginPath()// progressCtx.setStrokeStyle('#113')// progressCtx.arc(0, 0, 3, 0, 2 * Math.PI)// progressCtx.stroke()//1.绘制基础圆progressCtx.beginPath()progressCtx.setStrokeStyle(this.strokeColor)progressCtx.setLineWidth(this.progressWidth)progressCtx.setLineCap('round')progressCtx.arc(0, 0, this.radius, 0, 2 * this.progress * Math.PI)progressCtx.stroke()//1.1恢复旋转角度(目的是恢复画布)progressCtx.rotate(90 * Math.PI / 180)this.progressCtx = progressCtx;},draw() {setTimeout(() => {this.baseCtx.draw();this.progressCtx.draw();}, 50)},}}
</script><style lang="scss">.score-level-box {position: relative;// background-color: #91f;.score-view {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);font-family: PingFangSC-Medium, PingFang SC;font-weight: 500;}}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/138832.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4.Vue-Vue调用第三方接口

题记 用vue调用第三方接口&#xff0c;以下是全部代码和操作流程。 寻找第三方接口网站 推荐&#xff1a;免费API - 提供免费接口调用平台 (aa1.cn) 下面的代码以下图中的接口为例 安装axios模块 在终端输入以下命令&#xff1a; npm install axios 调用第三方接口代码 调…

从入门到进阶 之 ElasticSearch 节点配置 集群篇

&#x1f339; 以上分享 ElasticSearch 安装部署&#xff0c;如有问题请指教写。&#x1f339;&#x1f339; 如你对技术也感兴趣&#xff0c;欢迎交流。&#x1f339;&#x1f339;&#x1f339; 如有需要&#xff0c;请&#x1f44d;点赞&#x1f496;收藏&#x1f431;‍&a…

Spring框架(三)

1、代理模式&#xff1a; 二十三种设计模式中的一种&#xff0c;属于结构型模式。它的作用就是通过提供一个代理类&#xff0c;让我们在调用目标方法的时候&#xff0c;不再是直接对目标方法进行调用&#xff0c;而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标…

如何让大模型自由使用外部知识与工具

本文将分享为什么以及如何使用外部的知识和工具来增强视觉或者语言模型。 全文目录&#xff1a; 1. 背景介绍 OREO-LM: 用知识图谱推理来增强语言模型 REVEAL: 用多个知识库检索来预训练视觉语言模型 AVIS: 让大模型用动态树决策来调用工具 技术交流群 建了技术交流群&a…

【灵动 Mini-G0001开发板】+Keil5开发环境搭建+ST-Link/V2程序下载和仿真+4颗LED100ms闪烁。

我们拿到手里的是【灵动 Mini-G0001开发板】 如下图 我们去官网下载开发板对应资料MM32G0001官网 我们需要下载Mini—G0001开发板的库函数与例程&#xff08;第一手学习资料&#xff09;Keil支持包&#xff0c; PCB文件有需要的&#xff0c;可以自行下载。用户指南需要下载&a…

Linux网络-UDP/TCP协议详解

Linux网络-UDP/TCP协议详解 2023/10/17 14:32:49 Linux网络-UDP/TCP协议详解 零、前言一、UDP协议二、TCP协议 1、应答机制2、序号机制3、超时重传机制4、连接管理机制 三次握手四次挥手5、理解CLOSE_WAIT状态6、理解TIME_WAIT状态7、流量控制8、滑动窗口 丢包问题9、拥塞控制…

探索音频传输系统:数字声音的无限可能 | 百能云芯

音频传输系统是一项关键的技术&#xff0c;已经在数字时代的各个领域中广泛应用&#xff0c;从音乐流媒体到电话通信&#xff0c;再到多媒体制作。本文将深入探讨音频传输系统的定义、工作原理以及在现代生活中的各种应用&#xff0c;以帮助您更好地了解这一重要技术。 音频传输…

接口加密解决方案:Python的各种加密实现!

01、前言 在现代软件开发中&#xff0c;接口测试已经成为了不可或缺的一部分。随着互联网的普及&#xff0c;越来越多的应用程序都采用了接口作为数据传输的方式。接口测试的目的是确保接口的正确性、稳定性和安全性&#xff0c;从而保障系统的正常运行。 在接口测试中&…

通过商品ID查询天猫商品详情数据,可以拿到商品标题,商品价格,商品库存,商品销量,商品sku数据等,天猫API接口

通过商品ID查询天猫商品详情数据可以用淘宝开放平台的淘宝客商品详情查询接口&#xff08;taobao.tbk.item.info.get&#xff09;来完成。 首先需要申请一个淘宝开放平台的应用&#xff0c;并获取到App Key和App Secret&#xff0c;然后使用淘宝开放平台的淘宝客商品详情查询接…

用友NC-Cloud uploadChunk 任意文件上传漏洞

一、漏洞描述 用友 NC Cloud&#xff0c;大型企业数字化平台&#xff0c; 聚焦数字化管理、数字化经营、数字化商业&#xff0c;帮助大型企业实现 人、财、物、客的全面数字化&#xff0c;从而驱动业务创新与管理变革&#xff0c;与企业管理者一起重新定义未来的高度。为客户提…

A062-防火墙安全配置-配置Iptables防火墙策略

实验步骤: 【教学资源类别】 序号 类别 打勾√ 1 学习资源 √ 2 单兵模式赛题资源 3 分组对抗赛题资源 【教学资源名称】 防火墙安全配置-配置安全设置iptables防火墙策略 【教学资源分类】 一级大类 二级大类 打勾√ 1.安全标准 法律法规 行业标准 安全…

云安全—云计算基础

0x00 前言 学习云安全&#xff0c;那么必然要对云计算相关的内容进行学习和了解&#xff0c;所以云安全会分为两个部分来进行&#xff0c;首先是云计算先关的内容。 0x01 云计算 广泛传播 云计算最早大范围传播是2006年&#xff0c;8月&#xff0c;在圣何塞【1】举办的SES&a…