小程序 js+Canvas 绘制半圆环虚线进度条

news2025/2/22 21:02:51
效果图:

思路:过程分为三步,第1步,先画虚线底部背景,第2步,画动态的虚线(已选虚线蓝颜色),第3步,画动态的外标(已选虚线外位置的标),相关联的有1和2、2和3,1和2比较明显,颜色背景位置相同,2覆盖在1上,2和3终点位置相同,也就是计算弧度是一样的。

代码实现:
<view class="progress_item">
   <canvas class="progress_ring" type="2d" id="bgline"></canvas>
   <canvas class="progress_draw" type="2d" id="drawLine"></canvas>
   <canvas class="progress_move" type="2d" id="drawMove" bind:touchstart="moveDraw" bind:touchmove="moveDraw"></canvas>
</view>
css:
.progress_item{width:100%;position: relative;}
.progress_ring{width:280px;height: 140px;margin: 30px auto;}
.progress_draw{position: absolute;left:50%;transform: translateX(-50%);z-index: 3;top:0;width:280px;height: 140px;}
.progress_move{position: absolute;left:50%;transform: translateX(-50%);z-index: 5;top:-12px;width:300px;height: 170px;}
js:
let bgLineCtx,drawCtx,markCtx;
let markTimeStamp = 0;
let gbProgress = 0;

// 初始化画布
initRing(){
  const query = wx.createSelectorQuery()
  query.selectAll('#bgline,#drawLine,#drawMove').fields({ node: true, size: true }).exec((res) => {
    const dpr = wx.getSystemInfoSync().pixelRatio
    // 1、背景 半圆背景虚线底
    const bgLineCanvas = res[0][0].node
    bgLineCtx = bgLineCanvas.getContext('2d');
    bgLineCanvas.width = res[0][0].width * dpr
    bgLineCanvas.height = res[0][0].height * dpr
    bgLineCtx.scale(dpr, dpr);
    bgLineCtx.clearRect(0, 0, 280, 140);
    bgLineCtx.beginPath()
    bgLineCtx.strokeStyle = "#aaa";
    bgLineCtx.lineWidth = 12;
    bgLineCtx.lineCap = "line";
    bgLineCtx.setLineDash([2, 12]);
    bgLineCtx.arc(140,140,130,Math.PI,2*Math.PI);
    bgLineCtx.stroke();
    // 2、选中半圆虚线
    const drawLineCanvas = res[0][1].node
    drawCtx = drawLineCanvas.getContext('2d');
    drawLineCanvas.width = res[0][1].width * dpr
    drawLineCanvas.height = res[0][1].height * dpr
    drawCtx.scale(dpr, dpr);
    drawCtx.strokeStyle = "#2a82e4";
    drawCtx.lineWidth = 12;
    drawCtx.lineCap = "line";
    drawCtx.setLineDash([2, 12]);
    this.drawPress(1);
    // 3、手指滑动
    const drawMoveCanvas = res[0][2].node
    markCtx = drawMoveCanvas.getContext('2d');
    drawMoveCanvas.width = res[0][2].width * dpr
    drawMoveCanvas.height = res[0][2].height * dpr
    markCtx.scale(dpr, dpr);
    markCtx.translate(150, 150);
    markCtx.strokeStyle = "#2a82e4";
    markCtx.lineWidth = 4;
    markCtx.lineCap = 'round';
    this.drawRingDot(Math.PI);
  })
},
// 虚线占比 num为1时有动画效果
drawPress(num){
  let addNum = gbProgress / 20; // 转到多少 π(分为100份)每次转多少 π
  function draw(x){
    drawCtx.clearRect(0,0,280,140);
    drawCtx.beginPath()
    drawCtx.arc(140,140,130,Math.PI,Math.PI+x);
    drawCtx.stroke();
  }
  function animate(s){
    if(num == 1){
      setTimeout(function(){
        s += addNum;
        if (s >= gbProgress) {
          draw(gbProgress);
        }else {
          draw(s);
          animate(s);
        }
      }, 20); 
    }else{
      draw(gbProgress);
    }
  }
  animate(0);
},
// 虚线外的指标
drawRingDot(angle){
  markCtx.clearRect(-150, -150, 300, 170);
  markCtx.beginPath()
  markCtx.moveTo((148)*Math.cos(angle),(148)*Math.sin(angle));
  markCtx.lineTo((140)*Math.cos(angle),(140)*Math.sin(angle));
  markCtx.stroke();
},
// 手指触摸
moveDraw(e){
  let x = e.changedTouches[0].x;
  let y = e.changedTouches[0].y;
  if(e.type == "touchstart"){
    markTimeStamp = parseInt(e.timeStamp);
  }
  const radius = 150; // 半圆环的半径
  let maxDistance = radius+10; // 最大圆的距离
  let minDistance = radius-30; // 最小圆的距离
  let distance = Math.sqrt(Math.pow(x-radius, 2) + Math.pow(y-radius, 2));
  let num = parseInt(e.timeStamp - markTimeStamp);
  if(e.type=="touchmove" && num >= 200){
    markTimeStamp = parseInt(e.timeStamp);
  }
  if(y >= radius){
    y = radius
  }
  if (distance <= maxDistance && distance >= minDistance) {
    let radian = Math.atan2(y-radius, x-radius);
    let realAngle = (radian/ Math.PI+2).toFixed(2)*Math.PI; //弧度转化为角度
    let pAg = ((radian/ Math.PI+1)*100).toFixed(2);
    // console.log('val',radian,realAngle,pAg)
    if(pAg == 200){pAg = 0;}
    if(pAg >= 0 && pAg <= 100){
      gbProgress = pAg * (Math.PI/100);
      this.setData({
        progress: parseInt(pAg)
      })
      this.drawPress(0);
    }
    this.drawRingDot(realAngle);
  }
},

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AOSP12隐藏首页搜索框----隐藏google 搜索栏

目录 第一步&#xff1a;修改文件 第二步&#xff1a;修改文件 第三步&#xff1a;重新编译源码&#xff0c;启动模拟器 第四步、运行效果 第一步&#xff1a;修改文件 源码文件路径: packages/apps/Launcher3/res/layout/search_container_workspace.xml&#xff0c;将…

Navicat for MySQL 11软件下载附加详细安装教程

根据使用者情况表明Navicat Premium 能使你快速地在各种数据库系统间传输数据&#xff0c;或传输到一份指定 SQL 格式和编码的纯文本文件&#xff0c;计划不同数据库的批处理作业并在指定的时间运行&#xff0c;其他功能包括导入向导、导出向导、查询创建工具、报表创建工具、数…

【6】第一个Java程序:Hello World

一、引言 Java&#xff0c;作为一种广泛使用的编程语言&#xff0c;其强大的跨平台能力和丰富的库函数使其成为开发者的首选。对于初学者来说&#xff0c;编写并运行第一个Java程序是一个令人兴奋的时刻。本文将指导你使用Eclipse这一流行的集成开发环境&#xff08;IDE&#…

【对抗样本】【FGSM】Explaining and Harnessing Adversarial Examples 代码复现

简介 参考Pytorch官方的代码Adversarial Example Generation 参数设置(main.py) # 模型选择&#xff1a;GPU device mps if torch.backends.mps.is_available() else cpu # 数据集位置 dataset_path ../../../Datasets batch_size 1 shuffle True download False # 学习率…

express入门03增删改查

目录 1 搭建服务器2 静态文件托管3 引入bootstrap4 引入jquery5 编写后端接口5.1 添加列表查询方法5.2 添加路由5.3 添加数据表格 总结 我们前两篇介绍了如何利用express搭建服务器&#xff0c;如何实现静态资源托管。那利用这两篇的知识点&#xff0c;我们就可以实现一个小功能…

WebSocket 快速入门 与 应用

WebSocket 是一种在 Web 应用程序中实现实时、双向通信的技术。它允许客户端和服务器之间建立持久性的连接&#xff0c;以便可以在两者之间双向传输数据。 以下是 WebSocket 的一些关键特点和工作原理&#xff1a; 0.特点&#xff1a; 双向通信&#xff1a;WebSocket 允许服务…

艾宾浩斯winform单词系统+mysql

为用户提供集词典、题库、记忆单词功能于一体的应用&#xff0c;为用户提供目的性强、科学高效、多样化的记忆单词方法&#xff0c;使用户学习英语和记忆单词的效率得到提高 单词记忆模块 管理模块 查询单词 阅读英文 查看词汇 记忆单词 收藏单词 字段管理设置 统计 艾宾浩斯wi…

springBoot多数据源使用、配置

又参加了一个新的项目&#xff0c;虽然是去年做的项目&#xff0c;拿来复用改造&#xff0c;但是也学到了很多。这个项目会用到其他项目的数据&#xff0c;如果调用他们的接口取数据&#xff0c;我还是觉得太麻烦了。打算直接配置多数据源。 然后去另一个数据库系统中取出数据…

【C语音 || 数据结构】二叉树--堆

文章目录 前言堆1.1 二叉树的概念1.2 满二叉树和完美二叉树1.3 堆的概念1.4 堆的性质1.4 堆的实现1.4.1堆的向上调整算法1.4.1堆的向下调整算法1.4.1堆的接口实现1.4.1.1堆的初始化1.4.1.2堆的销毁1.4.1.3堆的插入1.4.1.4堆的删除1.4.1.4堆的判空1.4.1.4 获取堆的数据个数 前言…

当客户一上来就问你产品价格,你可以多尝试问问

做外贸业务&#xff0c;每个对产品不了解的客户&#xff0c;很多人一上来都会习惯性地问我们价格。一些新手业务会比较直接&#xff0c;一下子就把价格报出去了&#xff0c;很容易因为报错价格导致客户杳无音讯。 其实这个时候&#xff0c;我们最应该做的是尝试跟客户多聊一聊…

vuInhub靶场实战系列--Kioptrix Level #4

免责声明 本文档仅供学习和研究使用,请勿使用文中的技术源码用于非法用途,任何人造成的任何负面影响,与本人无关。 目录 免责声明前言一、环境配置1.1 靶场信息1.2 靶场配置 二、信息收集2.1 主机发现2.1.1 netdiscover2.1.2 arp-scan主机扫描 2.2 端口扫描2.3 指纹识别2.4 目…

MySQL-子查询(DQL 结束)

054-where后面使用子查询 什么是子查询 select语句中嵌套select语句就叫做子查询。select语句可以嵌套在哪里&#xff1f; where后面、from后面、select后面都是可以的。 select ..(select).. from ..(select).. where ..(select)..where后面使用子查询 案例&#xff1a;找…

国际贸易条件简称的解析说明

声明&#xff1a;本文仅代表作者观点和立场&#xff0c;不代表任何公司&#xff01;仅用于SAP软件应用学习参考。 SAP创建销售订单的界面有个国际贸易条件的字段&#xff0c;这个字段选择值主要有如下选择值&#xff0c;国际贸易条件简称的具体解析说明如下&#xff1a; EXW &…

【文档智能】包含段落的开源的中文版面分析模型

github&#xff1a;https://github.com/360AILAB-NLP/360LayoutAnalysis 权重下载地址&#xff1a;https://huggingface.co/qihoo360/360LayoutAnalysis 一、背景 在当今数字化时代&#xff0c;文档版式分析是信息提取和文档理解的关键步骤之一。文档版式分析&#xff0c;也…

数据价值管理-数据验收标准

前情提要&#xff1a;数据价值管理是指通过一系列管理策略和技术手段&#xff0c;帮助企业把庞大的、无序的、低价值的数据资源转变为高价值密度的数据资产的过程&#xff0c;即数据治理和价值变现。第一讲介绍了业务架构设计的基本逻辑和思路。前面我们讲完了数据资产建设标准…

零售业上云为什么首选谷歌云

零售业是国民经济的重要组成部分&#xff0c;在促进经济发展、改善人民生活水平方面发挥着重要作用。零售业也是一个竞争激烈的行业&#xff0c;零售企业需要不断创新经营方式、提高服务质量才能在竞争中立于不败之地。 近年来&#xff0c;中国企业在品牌出海方面&#xff0c;一…

大模型 - Langchain-Chatchat小白本地部署踩坑血泪史

环境介绍 windows 11python 3.9.9显卡 GTX970 4G显存 &#xff08;可怜巴巴&#xff09;内存 24G 一、下载 Langchain-Chatchat 注意&#xff1a;这里先不要执行依赖下载&#xff0c;如果项目是通过 PyCharm 打开&#xff0c;就不要着急下载依赖&#xff0c;跟着往下面走&am…

算法第六天:力扣第977题有序数组的平方

一、977.有序数组的平方的链接与题目描述 977. 有序数组的平方的链接如下所示&#xff1a;https://leetcode.cn/problems/squares-of-a-sorted-array/description/https://leetcode.cn/problems/squares-of-a-sorted-array/description/ 给你一个按 非递减顺序 排序的整数数组…

【Qt 学习笔记】Qt窗口 | 标准对话框 | 输入对话框QInputDialog

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt窗口 | 标准对话框 | 输入对话框QInputDialog 文章编号&#xff1a;…

vue3+electron搭建桌面软件

vue3electron开发桌面软件 最近有个小项目, 客户希望像打开 网易云音乐 那么简单的运行起来系统. 前端用 Vue 会比较快一些, 因此决定使用 electron 结合 Vue3 的方式来完成该项目. 然而, 在实施过程中发现没有完整的博客能够记录从创建到打包的流程, 摸索一番之后, 随即梳理…