首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

手把手使用 SVG + CSS 实现渐变进度环效果

编程知识
2024年08月02日 21:36

效果

image

轨道

使用 svg 画个轨道

image

  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke="#333"></circle>
  </svg>

简单的说,就是使用 circle 画个圆。需要注意的是,轨道实际是 circle 的 stroke,所以目标 svg 尺寸是 100,则圆的半径是 40,而 stroke 为 10。

接着,按设计,轨道只需要 3/4 个圆即可:

image

<!-- 3/4 track before rotate -->

<!-- circumference = radius * 2 * PI = 40 * 2 * Math.PI = 251.3274 -->
<!-- stroke-dasharray left = circumference * percent = 251.3274 * 0.75 = 188.4955 -->
<!-- stroke-dasharray right = circumference * (1 - percent) = 251.3274 * (1 - 0.75) = 62.8318 -->
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" stroke="#333"></circle>
  </svg>

为了实现这轨道,这个时候需要用到 stroke-dasharray。

为了更好理解这里 stroke-dasharray 的作用,先画一个 line:

image

  <svg viewBox="0 0 300 10" style="display: block;">
    <line x1="0" y1="5" x2="300" y2="5" stroke-width="10" stroke="#333" stroke-dasharray="75,25"></line>
  </svg>

简单的说,上面 line 长 300,每画一段 75 的 stroke,接着留空一段 25,如此重复,正好重复 3 次,刚好铺满了 300 的长度。

应用到 circle 也是如此,只是它是绕着圆,逆时针的画 stroke,类比的举例:

image

stroke-dasharray 的是长度,这里就需要通过计算周长,得出 A 与 E 分别是多长:

周长 = 半径 * 2 * PI = 40 * 2 * Math.PI = 251.3274
A = 周长 * 3/4 = 251.3274 * 0.75 = 188.4955
E = 周长 * 1/4 = 251.3274 * 0.25 = 62.8318

现在还要使用 transform 旋转 135 度以满足需求:

image

<!-- 3/4 track after rotate 135deg -->
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#333"></circle>
  </svg>

进度条

先画一个纯色的进度条:

image

body {
  background: black;
}

.gauge {
  position: relative;
  display: inline-block;
}

.gauge > svg {
  width: 200px;
  height: 200px;
}

.gauge > span {
  color: #fff;
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  text-align: center;
  transform: translate(0, -50%);
  font-size: 2em;
}
<!-- stroke-dasharray left = circumference * 0.75 * percent = 188.4955 * 0.10 = 18.8495 -->
<!-- stroke-dasharray right = circumference * 0.75 * (1 - percent) + circumference * (1 - 0.75) = 188.4955 * (1 - 0.10) + 62.8318 = 232.4778 -->
<div>
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#333"></circle>
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="18.8495,232.4778" transform="rotate(135, 50, 50)" stroke="#ffff00"></circle>
  </svg>
  <span>10%</span>
</div>

<!-- stroke-dasharray left = circumference * 0.75 * percent = 188.4955 * 0.50 = 94.2477 -->
<!-- stroke-dasharray right = circumference * 0.75 * (1 - percent) + circumference * (1 - 0.75) = 188.4955 * (1 - 0.50) + 62.8318 = 157.0795 -->
<div>
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#333"></circle>
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="94.2477,157.0795" transform="rotate(135, 50, 50)" stroke="#ffff00"></circle>
  </svg>
  <span>50%</span>
</div>

<!-- stroke-dasharray left = circumference * 0.75 * percent = 188.4955 * 1.00 = 94.2477 -->
<!-- stroke-dasharray right = circumference * 0.75 * (1 - percent) + circumference * (1 - 0.75) = 188.4955 * (1 - 1.00) + 62.8318 = 157.0795 -->
<div>
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#333"></circle>
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#ffff00"></circle>
  </svg>
  <span>100%</span>
</div>

有个很重要的前提,例如图中的 10%、50%、100% 的百分比,是基于那 3/4 轨道的,不是整个圆,所以计算 stroke-dasharray 的时候,实际考虑的是 3 个部分:

image

10%

A = s1 = 周长 * 3/4 * progress = 251.3274 * 0.75 * 0.10 = 18.8495
E = s2 + s3 = 周长 * 3/4 * (1 - progress) + 周长 * 1/4 = 251.3274 * 0.75 * (1 - 0.10) + 251.3274 * 0.25 = 232.4778

50%

A = s1 = 周长 * 3/4 * progress = 251.3274 * 0.75 * 0.50 = 94.2477
E = s2 + s3 = 周长 * 3/4 * (1 - progress) + 周长 * 1/4 = 251.3274 * 0.75 * (1 - 0.50) + 251.3274 * 0.25 = 157.0796

100%

A = s1 = 周长 * 3/4 * progress = 251.3274 * 0.75 * 1.00 = 188.4955
E = s2 + s3 = 周长 * 3/4 * (1 - progress) + 周长 * 1/4 = 251.3274 * 0.75 * (1 - 1.00) + 251.3274 * 0.25 = 62.8318

渐变

image

渐变由最初的从左到右,跟随轨道的 rotate,最后变成从右上到左下,也就意味着,此处的渐变并不是跟随轨道从 0 到 100%,仅实现了类似的感觉的模拟。

image

<!-- progress bar with gradient -->

<!-- stroke-dasharray left = circumference * 0.75 * percent = 188.4955 * 0.30 = 94.2477 -->
<!-- stroke-dasharray right = circumference * 0.75 * (1 - percent) + circumference * (1 - 0.75) = 188.4955 * (1 - 0.30) + 62.8318 = 157.0795 -->
<div>
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#333"></circle>
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="56.5486,194.7786" transform="rotate(135, 50, 50)" stroke="url(#gauge-gradient)"></circle>
  </svg>
  <span>30%</span>
</div>

<!-- stroke-dasharray left = circumference * 0.75 * percent = 188.4955 * 0.80 = 94.2477 -->
<!-- stroke-dasharray right = circumference * 0.75 * (1 - percent) + circumference * (1 - 0.75) = 188.4955 * (1 - 0.80) + 62.8318 = 157.0795 -->
<div>
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#333"></circle>
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="150.7964,100.5308" transform="rotate(135, 50, 50)" stroke="url(#gauge-gradient)"></circle>
  </svg>
  <span>80%</span>
</div>

动画

最后,为了实现“效果”中的动画,需要 CSS 配合 JS 实现:

<!-- with animation -->

<div>
  <svg viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="188.4955,62.8318" transform="rotate(135, 50, 50)" stroke="#333"></circle>
    <circle cx="50" cy="50" r="40" fill="none" stroke-width="10" stroke-dasharray="0,251.3274" transform="rotate(135, 50, 50)" stroke="url(#gauge-gradient3)"></circle>
  </svg>
  <span>100%</span>
</div>
#circle {
  transition: all 1s linear;
}
(function() {
  const radius = 40;
  const trackPercent = 0.75
  const circumference = 40 * 2 * Math.PI;
  const percent = 1.00;

  const strokeDasharrayLeft = circumference * trackPercent * percent
  const strokeDasharrayRight = circumference * trackPercent * (1 - percent) + circumference * (1 - trackPercent)

  const circle = document.querySelector('#circle');

  function change() {
    const strokeDasharray = circle.getAttribute('stroke-dasharray').split(',')
    const left = parseFloat(strokeDasharray[0])
    const right = parseFloat(strokeDasharray[1])

    if (left === 0) {
      circle.setAttribute('stroke-dasharray', `${strokeDasharrayLeft},${strokeDasharrayRight}`)
    } else {
      circle.setAttribute('stroke-dasharray', `0,251.3274`)
    }
  }

  setTimeout(function() {

    setInterval(function() {
      change()
    }, 1000)

    change()
  }, 0)
})();

JS 的主要作用就是动态的计算 stroke-dasharray,并配合 CSS 的 transition all 即可实现。

Done!

From:https://www.cnblogs.com/xachary/p/18339737
本文地址: http://www.shuzixingkong.net/article/729
0评论
提交 加载更多评论
其他文章 代码随想录Day3
203.移除链表元素 给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。 示例 1: 输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5] 示例 2: 输入:hea
代码随想录Day3 代码随想录Day3
VirtualBox扩容CentOS-7虚拟机磁盘
1、背景描述 如上图所示,根路径“/”所在的文件系统已没有可用的磁盘空间,需要扩容磁盘。 df -h 2、VirtualBox操作 2.1、查看当前虚拟磁盘的大小 如上图所示,点击打开选中的虚拟机的 Settings 界面。 如上图所示,当前虚拟机的虚拟磁盘大小为 8GB 。 2.2、修改虚拟磁盘的
VirtualBox扩容CentOS-7虚拟机磁盘 VirtualBox扩容CentOS-7虚拟机磁盘 VirtualBox扩容CentOS-7虚拟机磁盘
【Java】Jsoup 解析HTML报告
一、需求背景 有好几种报告文件,目前是人肉找报告信息填到Excel上生成统计信息 跟用户交流了下需求和提供的几个文件,发现都是html文件 其实所谓的报告的文件,就是一些本地可打开的静态资源,里面也有js、img等等 二、方案选型 前面老板一直说是文档解析,我寻思这不就是写爬虫吗.... 因为是在现
【Java】Jsoup 解析HTML报告 【Java】Jsoup 解析HTML报告 【Java】Jsoup 解析HTML报告
告别痕迹:远程桌面连接历史和凭据的清零指南
本文指出在工作中运用 Windows 远程桌面工具时,因安全与隐私因素,有时需删除连接的历史记录和凭据。文中给出了一个相关的 PowerShell 脚本,还说明了其使用方法,涵盖运行 PowerShell 的条件、CredentialManager 模块的安装、脚本的执行流程及输入选择等,同时提到了
python数据分析与可视化基础
一、数据分析介绍:1.数据分析含义:数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,将它们加以汇总和理解并消化,以求最大化地开发数据的功能,发挥数据的作用。数据分析是为了提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。 数据分析的数学基础在20世纪早期就已确立,但直到计算机的
Jupyter Lab和Jupyter Notebook的区别
JupyterLab与Jupyter Notebook:详细比较 简介 Jupyter Notebook是一个开源的Web应用程序,允许用户创建和共享包含实时代码、方程、可视化和解释性文本的文档。JupyterLab是Jupyter Notebook的下一代界面,提供了更高级的功能和更现代化的用户界
[VS Code扩展]写一个代码片段管理插件(一):介绍与界面搭建
@目录VS Code扩展机制项目搭建创建UI元素活动栏按钮主边栏视图主边栏工具栏按钮侧边栏右键菜单编辑器右键菜单项目地址 [VS Code扩展]写一个代码片段管理插件(一):介绍与界面搭建 [VS Code扩展]写一个代码片段管理插件(二):功能实现 写代码的时候,经常要输入重复的内容,虽然VS C
[VS Code扩展]写一个代码片段管理插件(一):介绍与界面搭建 [VS Code扩展]写一个代码片段管理插件(一):介绍与界面搭建 [VS Code扩展]写一个代码片段管理插件(一):介绍与界面搭建
全网最适合入门的面向对象编程教程:30 Python的内置数据类型-object根类
在 Python 中,所有的类都直接或间接继承自一个根类,这个根类是Object。Object类是 Python 中所有新式类的基础类,在 Python 的类层次结构中,Object类是所有类的最终基类。
全网最适合入门的面向对象编程教程:30 Python的内置数据类型-object根类 全网最适合入门的面向对象编程教程:30 Python的内置数据类型-object根类 全网最适合入门的面向对象编程教程:30 Python的内置数据类型-object根类