[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.rhkb.cn/news/161943.html

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

相关文章

【前端学习】—JS判断数据类型的方式有哪些(八)

【前端学习】—JS判断数据类型的方式有哪些&#xff08;八&#xff09; 一、JS中判断数据类型的场景 二、JS中有哪些数据类型 三、JS判断数据类型的方式有哪些 const arr[]; const object{};const number1; const stringstring;//typeofconst typetypeof arr; console.log(type…

【算法|前缀和系列No.5】leetcode1314. 矩阵区域和

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【Leetcode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

使用流量管理工具保护 Kubernetes 的六种方法

原文作者&#xff1a;Jenn Gile - F5 NGINX 产品营销经理 原文链接&#xff1a;使用流量管理工具保护 Kubernetes 的六种方法 转载来源&#xff1a;NGINX 中文官网 NGINX 唯一中文官方社区 &#xff0c;尽在 nginx.org.cn 编者按 —— 本文是以下系列博文中的一篇&#xff08;共…

DeFi世界 MXT脱颖而出 利好不断

​​MixTrust希望成为用户在Web3世界的专用金融平台&#xff0c;注重为用户提供个性化的金融服务。而WorldCoin的愿景则是建设一个全球最大的、公平的数字身份和货币体系&#xff0c;强调构建一个涵盖全球范围的身份认证和货币交易系统。 扩展性 在扩展性方面&#xff0c;双方…

Windows11家庭版没有本地组策略编辑器解决

1. 新建一个文本文件将下面代码粘到里面&#xff0c;保存后修改后缀为.cmd或者.bat echo off pushd "%~dp0"dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >List.txt dir /b C:\Windows\servicing\Packa…

pytorch_神经网络构建4

文章目录 循环神经网络LSTM词嵌入skip-Gram模型N-Gram模型词性预测RNN循环神经网络的基础模块实现RNN识别图片RNN时间序列预测词向量模块词向量运用N-Gram模型lstm词性预测 循环神经网络 这个网络主要用来处理序列信息,之前处理图片时大部分是分析图片的结构信息, 什么是序列信…

Kafka SASL认证授权(五)ACL源码解析

Kafka SASL认证授权(五)ACL源码解析。 官网地址:https://kafka.apache.org/ 一、ACL检查流程解析 一起看一下kafka server的启动与监听流程: Kafka -> KafkaServer -> SocketServer、KafkaRequestHandler 其中KafkaServer做相关的初始化,包括SocketServer 与 han…

django无法导入第三方库

引子 有的人可能会很困惑&#xff0c;为什么自己在pip中安装了某个包&#xff0c;但是在django中死活无法导入。 在cmd中能够导入。 启动django&#xff0c;总是无法导入。 本文将会用一分钟解决你的困惑。 正文 那么本文以上述的第三方库dj_db_conn_pool为例&#xff0c;…

STM32 BootLoader设置

编写bootloader程序&#xff1a; 直接复制下面代码到自己程序中。 typedef void (*iapfun)(void); //定义一个函数类型的参数. iapfun jump2app; //设置栈顶地址 //addr:栈顶地址 __asm void MSR_MSP(u32 addr) {MSR MSP, r0 //set Main Stack valueBX r14 }//跳转到…

软件工程与计算总结(十三)详细设计中的模块化与信息隐藏

一.模块化与信息隐藏思想 1.设计质量 好的设计要着重满足以下3方面&#xff1a;可管理性、灵活性、可理解性好的设计需要侧重于间接性和可观察性——简洁性使得系统模块易于管理&#xff08;理解和分解&#xff09;、开发&#xff08;修改与调试&#xff09;和复用。实践者都…

BI零售数据分析:以自身视角展开分析

随着零售业务不断扩展&#xff0c;市场竞争不断加剧&#xff0c;各层级的销售管理人员都急需一张能快速查看销售数据分析报表&#xff0c;能从中知道自己管辖内的业务最近或过去的情况&#xff0c;并依次为依据科学优化销售管理措施。这就要求零售数据分析报表信息足够多、数据…

Mac硬盘检测工具

Mac硬盘检测软件是一款用于检测和诊断Mac硬盘健康状态的工具&#xff0c;帮助用户及时发现潜在的硬盘问题&#xff0c;避免数据丢失和系统故障。通过全面的检测和报告功能&#xff0c;用户可以更好地了解自己的硬盘状况&#xff0c;确保数据的安全和可靠。给大家介绍几款好用的…

PhotoShop批量压缩图片

打开photoshop&#xff0c;在顶部的菜单栏选择文件》脚本》图像处理器。 选择合适的参数&#xff0c;运行即可。

postman请求400错误-日期LocalData

错误日志参考 [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type java.lang.String to required type java.time.LocalDate; neste…

电脑D盘文件凭空消失了?切记3招,轻松恢复文件!

“由于我c盘内存不够了&#xff0c;我就将部分重要的文件保存到了d盘&#xff0c;今天打开d盘后才发现我这些文件凭空消失了。这究竟是什么呀&#xff1f;还有机会找回这些消失的d盘文件吗&#xff1f;” D盘作为电脑中一个重要的磁盘&#xff0c;很多电脑用户也会选择将文件保…

6.(vue3.x+vite)路由传参query与params区别

前端技术社区总目录(订阅之前请先查看该博客) 效果截图 一:路由传参有两种方式:params与query params与query区别 1:param,路由带“/”,query带“?” 2:query传过来的参数会显示到地址栏中 而params传过来的参数可以显示参数或隐藏参数到地址栏中(vue-router 4.1.4不…

Flutter笔记:发布一个电商中文货币显示插件Money Display

Flutter笔记 电商中文货币显示插件 Money Display 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/1338…

【性能测试】使用JMeter对code论坛进行压力测试

1.项目介绍 项目简介 code 论坛是一个技术交流社区。主要功能有发布帖子&#xff0c;查看帖子&#xff0c;评价帖子&#xff0c;删除帖子&#xff0c;点赞帖子&#xff0c;站内信&#xff0c;个人中心&#xff0c;修改个人信息等。是一个基于 Spring 的前后端分离项目。 项目链…

分享一下微信小程序怎么添加成绩查询插件

微信小程序如何添加成绩查询插件 一、引言 微信小程序是一种方便快捷的应用程序&#xff0c;可以在微信中使用。随着教育的不断发展&#xff0c;学校和家长对于学生的成绩查询需求也越来越高。通过在微信小程序中添加成绩查询插件&#xff0c;可以为学生和家长提供更加便捷的…

微信小程序获取手机号(2023年10月 python版)[无需订阅]

技术栈&#xff1a; 1. 微信开发者工具中的调试基础库版本&#xff1a;3.1.2。 2. 后台&#xff1a;django。 步骤&#xff1a; 1. 首先在后台django项目的定时任务中增加一个下载access_token函数&#xff0c;并把得到的access_token保存在数据库中&#xff08;其实随便哪里…