• svg 实现半环形进度条


    要实现的效果图如下

    image.png

    svg 语法学习

    可以参考https://developer.mozilla.org/zh-CN/docs/Web/SVG网站上的语法

    元素参考

    path元素用来定义形状的通用元素。
    下面的命令可用于路径数据:

    • M = moveto
    • L = lineto
    • H = horizontal lineto
    • V = vertical lineto
    • C = curveto
    • S = smooth curveto
    • Q = quadratic Belzier curve
    • T = smooth quadratic Belzier curveto
    • A = elliptical Arc
    • Z = closepath
    注释:以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。

    例如:画个圆环

    <path d="
            M 50 50
            m 0 -47
            a 47 47 0 1 1 0 94
            a 47 47 0 1 1 0 -94
            " stroke="#e5e9f2" stroke-width="4.8" fill="none" ></path>
    

    解析:
    image.png

    symbol元素用来定义一个图形模板对象,它可以用一个<use>元素实例化。symbol元素对图形的作用是在同一文档中多次使用,添加结构和语义。结构丰富的文档可以更生动地呈现出来,类似讲演稿或盲文,从而提升了可访问性。注意,一个symbol元素本身是不呈现的。只有symbol元素的实例(亦即,一个引用了symbol的 <use>元素)才能呈现。

    use元素在SVG文档内取得目标节点,并在别的地方复制它们。它的效果等同于这些节点被深克隆到一个不可见的DOM中,然后将其粘贴到use元素的位置,很像HTML5中的克隆模板元素。因为克隆的节点是不可见的,所以当使用CSS样式化一个use元素以及它的隐藏的后代元素的时候,必须小心注意。隐藏的、克隆的DOM不能保证继承CSS属性,除非你明文设置使用[CSS继承]
    (https://developer.mozilla.org/en/CSS/inheritance)。
    一般情况下symbol 和use配合着使用的。
    例如: 效果中的小人,如果自己画的话,就非常耗时间,可以在iconfont 里找一个,然后引入进来;
    在自己的svg 里引入

    <use xlink:href="#male" x="180" y="135"/>
    <use xlink:href="#female" x="230" y="135"/>
    

    在阿里图标库复制svg,如下:两个小人

    <svg class="icon" >
          <symbol id="male" viewBox="0 0 1024 1024" width="80" height="80" fill="#23C8F5">
            <path d="M631.091 661.333l-13.79 319.932A44.988 44.988 0 0 1 572.416 1024l-64.717-42.667L443.017 1024a44.988 44.988 0 0 1-44.852-42.735l-13.79-319.932h-27.682a45.807 45.807 0 0 1-45.397-42.564l-38.161-277.538a40.073 40.073 0 0 1 40.55-42.564h388.096c23.723 0 41.882 19.046 40.55 42.564l-38.126 277.538a45.807 45.807 0 0 1-45.398 42.564h-27.716zM507.733 256a128 128 0 1 1 0-256 128 128 0 0 1 0 256z"></path>
          </symbol>
          <symbol id="female" viewBox="0 0 1024 1024" width="80" height="80" fill="#f4ea2a">
            <path d="M512 160m-160 0a160 160 0 1 0 320 0 160 160 0 1 0-320 0Z" ></path>
            <path d="M384 800h256l-77.888 224H456.992z" p-id="2418" ></path>
            <path d="M480 320h63.424a96 96 0 0 1 88.768 59.456l144.928 352A96 96 0 0 1 688.32 864H335.04a96 96 0 0 1-88.8-132.544l144.96-352A96 96 0 0 1 480 320z"></path>
          </symbol>
        </svg>
    

    解析结果:
    image.png

    line元素是一个SVG基本形状,用来创建一条连接两个点的线。

    • x1 属性在 x 轴定义线条的开始
    • y1 属性在 y 轴定义线条的开始
    • x2 属性在 x 轴定义线条的结束
    • y2 属性在 y 轴定义线条的结束
      例如:
    <line
            x1="210"
            y1="174"
            x2="0"
            y2="174"
            stroke="rgba(35, 200, 245, 0.39)"
            stroke-dasharray="2,2"
            stroke-width="2"
          />
    

    解析:
    image.png

    text元素定义了一个由文字组成的图形。
    例如:

       <text x="0" y="160" fill="#23C8F5" class="svg-text">
            男:45%
          </text>
    

    解析:
    image.png

    linearGradient元素用来定义线性渐变,用于图形元素的填充或描边。
    例如:

    <svg width="120" height="120"  viewBox="0 0 120 120"
         xmlns="http://www.w3.org/2000/svg" version="1.1"
         xmlns:xlink="http://www.w3.org/1999/xlink" >
    
        <defs>
            <linearGradient id="MyGradient">
                <stop offset="5%"  stop-color="green"/>
                <stop offset="95%" stop-color="gold"/>
            </linearGradient>
        </defs>
    
        <rect fill="url(#MyGradient)"
              x="10" y="10" width="100" height="100"/>
    </svg>
    

    解析:

    svg 属性参考

    viewBox属性允许指定一个给定的一组图形伸展以适应特定的容器元素。
    viewBox属性的值是一个包含4个参数的列表 min-x, min-y, width and height, 以空格或者逗号分隔开。

    stroke-dasharray 属性可控制用来描边的点划线的图案范式,作为一个外观属性,它也可以直接用作一个CSS样式表内部的属性,用于创建虚线,之所以后面跟的是array的,是因为值其实是数组。
    例如:

    stroke-dasharray = '10'
    stroke-dasharray = '10, 5'
    stroke-dasharray = '20, 10, 5'
    

    解析:
    image.png

    stroke-dasharray为一个参数时: 其实是表示虚线长度和每段虚线之间的间距
      如:stroke-dasharray = '10' 表示:虚线长10,间距10,然后重复 虚线长10,间距10

    offset:偏移的意思,这个属性是相对于起始点的偏移,正数偏移x值的时候,相当于往左移动了x个长度单位,负数偏移x的时候,相当于往右移动了x个长度单位。
    需要注意的是,不管偏移的方向是哪边,要记得dasharray 是循环的,也就是 虚线-间隔-虚线-间隔。
    这个属性要搭配stroke-dashoffset才能看得出来效果,非虚线的话,是无法看出偏移的。
    $color{red}{注意:dashoffset 偏移是顺时针的字}$

    思路

    半弧度进度条是最难的,可使用stroke-dasharray配合stroke-dashoffset 来画。

    弧度讲解1.png

    图2.png

    进度红色部分AC为实线弧度,灰色部分BC为虚线弧度,空白部分AB弧度为间隔

    • 实线弧度AC = 圆周长P - 弧线弧长BC - 空白弧长AB
    • 偏移角度:左半边偏移量只和空白弧长AB有关,右半边偏移量和弧长BE+空白弧长AB有关
    • 空白弧长AB = 2Rarcsin(a/2R) (注意a为弦长AB)
    • 图 2 里的4个半弧长是有4个path 化成的
    • 由于弧长有宽度,弧长AB的半径 = 进度条弧长的半径- 弧长的宽度

    实现代码

    <template>
      <div class="circle-wrap">
        <svg class="circle" viewBox="0 0 480 350">
          <defs>
            <linearGradient id="greenGradient" x1="100%" y1="100%">
              <stop offset="0%" stop-color="rgba(32, 174, 214, 0.07)">
                <!-- <animate attributeName="stop-color" values="lightblue;blue;red;red;black;red;red;purple;lightblue" dur="14s" repeatCount="indefinite" /> -->
              </stop>
              <stop offset="100%" stop-color="rgba(8, 24, 88, 0.07)">
                <!-- <animate attributeName="stop-color" values="lightblue;orange;purple;purple;black;purple;purple;blue;lightblue" dur="14s" repeatCount="indefinite" />
                <animate attributeName="offset" values=".95;.80;.60;.40;.20;0;.20;.40;.60;.80;.95" dur="14s" repeatCount="indefinite" /> -->
              </stop>
            </linearGradient>
          </defs>
          <polygon
            points="80 260,400 260,480 340,0 340"
            fill="url(#greenGradient)"
          />
          <!-- 内圆 -->
          <path
            d="
            M 240 175
            m 0 110
            a 110 110 0 1 1 0 -220
            a 110 110 0 1 1 0 220
            "
            stroke="#09265E"
            stroke-width="1"
            fill="none"
            stroke-linecap="round"
            class="inside-circle"
            style="stroke-dasharray: 5px 5px"
          ></path>
          <!-- 中间两个半圆圆 -->
          <path
            d="
            M 240 175
            m 0 130
            a 130 130 0 1 1 0 -260
            a 130 130 0 1 1 0 260
            "
            stroke="#09265E"
            stroke-width="20"
            fill="none"
            stroke-linecap="round"
            class="left-below-circle"
            :style="{
              strokeDasharray:
                midBelowArcLength + 'px   ' + (midP - midBelowArcLength) + 'px',
              strokeDashoffset: -Math.floor(midIntervalLeng / 2) + 'px',
            }"
          ></path>
    
          <path
            d="
            M 240 175
            m 0 130
            a 130 130 0 1 1 0 -260
            a 130 130 0 1 1 0 260
            "
            stroke="#23C8F5"
            stroke-width="20"
            fill="none"
            stroke-linecap="round"
            v-show="leftMidSolidLine"
            class="left-above-circle"
            :style="{
              strokeDasharray:
                leftMidSolidLine + 'px   ' + leftMidDottedLine + 'px',
              strokeDashoffset: -Math.floor(midIntervalLeng / 2) + 'px',
            }"
          >
            >
          </path>
          <path
            d="
              M 240 175
              m 0 130
              a 130 130 0 1 1 0 -260
              a 130 130 0 1 1 0 260"
            stroke="#09265E"
            stroke-width="20"
            fill="none"
            stroke-linecap="round"
            class="right-below-circle"
            :style="{
              strokeDasharray:
                midBelowArcLength + 'px   ' + (midP - midBelowArcLength) + 'px',
              strokeDashoffset:
                Math.floor(midIntervalLeng / 2 + midBelowArcLength) + 'px',
            }"
          ></path>
          <path
            d="
              M 240 175
              m 0 130
              a 130 130 0 1 1 0 -260
              a 130 130 0 1 1 0 260"
            stroke="#E7B417"
            stroke-width="20"
            fill="none"
            stroke-linecap="round"
            class="right-above-circle"
            :style="{
              strokeDasharray:
                rightMidSolidLine + 'px   ' + rightMidDottedLine + 'px',
              strokeDashoffset:
                Math.floor(midIntervalLeng / 2 + rightMidSolidLine) + 'px',
            }"
          ></path>
          <!-- 外边圆 -->
          <path
            d="
            M 240 175
            m 0 145
            a 145 145 0 1 1 0 -290
            a 145 145 0 1 1 0 290
            "
            stroke="#09265E"
            stroke-width="2"
            fill="none"
            stroke-linecap="round"
            class="left-below-circle"
            :style="{
              strokeDasharray:
                outBelowArcLength + 'px   ' + (outP - outBelowArcLength) + 'px',
              strokeDashoffset: -Math.floor(outIntervalLeng / 2) + 'px',
            }"
          ></path>
          <path
            d="
            M 240 175
            m 0 145
            a 145 145 0 1 1 0 -290
            a 145 145 0 1 1 0 290
            "
            stroke="#23C8F5"
            stroke-width="2"
            fill="none"
            stroke-linecap="round"
            v-show="leftOutSolidLine"
            class="left-above-circle"
            :style="{
              strokeDasharray:
                leftOutSolidLine + 'px   ' + leftOutDottedLine + 'px',
              strokeDashoffset: -Math.floor(outIntervalLeng / 2) + 'px',
            }"
          ></path>
          <path
            d="
            M 240 175
            m 0 145
            a 145 145 0 1 1 0 -290
            a 145 145 0 1 1 0 290
            "
            stroke="#09265E"
            stroke-width="2"
            fill="none"
            stroke-linecap="round"
            class="right-below-circle"
            :style="{
              strokeDasharray:
                outBelowArcLength + 'px   ' + (outP - outBelowArcLength) + 'px',
              strokeDashoffset:
                Math.floor(outIntervalLeng / 2 + outBelowArcLength) + 'px',
            }"
          ></path>
          <path
            d="
              M 240 175
              m 0 145
              a 145 145 0 1 1 0 -290
              a 145 145 0 1 1 0 290"
            stroke="#E7B417"
            stroke-width="2"
            fill="none"
            stroke-linecap="round"
            class="right-above-circle"
            :style="{
              strokeDasharray:
                rightOutSolidLine + 'px   ' + rightOutDottedLine + 'px',
              strokeDashoffset:
                Math.floor(outIntervalLeng / 2 + rightOutSolidLine) + 'px',
            }"
          ></path>
          <text x="0" y="160" fill="#23C8F5" class="svg-text">
            男:{{ leftPer }}%
          </text>
          <text x="410" y="160" fill="#E7B417" class="svg-text">
            女:{{ rightPer }}%
          </text>
          <!-- 左边线 -->
          <line
            x1="210"
            y1="174"
            x2="0"
            y2="174"
            stroke="rgba(35, 200, 245, 0.39)"
            stroke-dasharray="2,2"
            stroke-width="2"
          />
          <!-- 右边线 -->
          <line
            x1="275"
            y1="174"
            x2="480"
            y2="174"
            stroke="rgba(216, 162, 18, .39)"
            stroke-dasharray="2,2"
            stroke-width="2"
          />
          <use xlink:href="#male" x="180" y="135" />
          <use xlink:href="#female" x="230" y="135" />
        </svg>
    
        <svg class="icon">
          <symbol
            id="male"
            viewBox="0 0 1024 1024"
            width="80"
            height="80"
            fill="#23C8F5"
          >
            <path
              d="M631.091 661.333l-13.79 319.932A44.988 44.988 0 0 1 572.416 1024l-64.717-42.667L443.017 1024a44.988 44.988 0 0 1-44.852-42.735l-13.79-319.932h-27.682a45.807 45.807 0 0 1-45.397-42.564l-38.161-277.538a40.073 40.073 0 0 1 40.55-42.564h388.096c23.723 0 41.882 19.046 40.55 42.564l-38.126 277.538a45.807 45.807 0 0 1-45.398 42.564h-27.716zM507.733 256a128 128 0 1 1 0-256 128 128 0 0 1 0 256z"
            ></path>
          </symbol>
          <symbol
            id="female"
            viewBox="0 0 1024 1024"
            width="80"
            height="80"
            fill="#f4ea2a"
          >
            <path
              d="M512 160m-160 0a160 160 0 1 0 320 0 160 160 0 1 0-320 0Z"
            ></path>
            <path d="M384 800h256l-77.888 224H456.992z" p-id="2418"></path>
            <path
              d="M480 320h63.424a96 96 0 0 1 88.768 59.456l144.928 352A96 96 0 0 1 688.32 864H335.04a96 96 0 0 1-88.8-132.544l144.96-352A96 96 0 0 1 480 320z"
            ></path>
          </symbol>
        </svg>
      </div>
    </template>
    <script>
    export default {
      components: {},
      props: {},
      data() {
        return {
          pi: 3.1415926, // π
          midR: 130, // 中间圆半径
          midR2: 110,
          outR: 145, // 外圆半径
          midP: '', // 中间圆周长
          outP: '', // 外圆周长
          a: 70, // 弦长
          midBelowArcLength: '', // 中间半弧长
          outBelowArcLength: '', // 外面半弧长
          leftMidSolidLine: '', // 中间左半圆实线弧长
          leftMidDottedLine: '', // 中间左半圆虚线弧长
          rightMidSolidLine: '', // 中间右半圆实线弧长
          rightMidDottedLine: '', // 中间半圆虚线弧长
          rightMidrotate: '', // 中间半圆旋转角度
          leftOutSolidLine: '', // 外边左半圆实线弧长
          leftOutDottedLine: '', // 外边左半圆虚线弧长
          rightOutSolidLine: '', // 外边右半圆实线弧长
          rightOutDottedLine: '', // 外边半圆虚线弧长
          rightOutrotate: '', // 外边半圆旋转角度
          midIntervalLeng: '', // 中间空白弧长
          outIntervalLeng: '', // 外边空白弧长
          // leftAbovePer: 45, // 左边进度
          // rightAbovePer: 55, // 右边进度
        };
      },
      mounted() {
        
        this.getP();
        this.getArcLeng();
        this.getAboveArcLeng();
      },
      props:{
        leftPer: { // 左边进度
          type: Number,
          default() {
            return 45;
          }
        },
        rightPer:{ // 右边进度
          type: Number,
          default() {
            return 55;
          }
        }
      },
      watch:{
        leftPer(newVal,oldVal) {
          // this.rightPer = 100 - newVal;
          this.getAboveArcLeng()
    
        }
      },
      methods: {
        /**
         * 计算周长函数
         */
        getP() {
          this.midP = this.pi * 2 * this.midR;
          console.log('中间圆周长=', this.midP);
          this.outP = this.pi * 2 * this.outR;
          console.log('外边圆周长=', this.outP);
        },
        /**
         * 计算弦长函数
         */
        getArcLeng() {
          this.midIntervalLeng =
            2 * this.midR * Math.asin(this.a / (2 * this.midR2)); // 中间圆空白弧长
          console.log('中间圆空白弧长=', this.midIntervalLeng);
          this.midBelowArcLength = (this.midP - this.midIntervalLeng * 2) / 2; // 中间圆底层半弧长
          console.log('中间圆底层半弧长=', this.midBelowArcLength);
    
          this.outIntervalLeng =
            2 * this.outR * Math.asin(this.a / (2 * this.outR)); // 外边圆空白弧长
          console.log('外边圆空白弧长=', this.outIntervalLeng);
          this.outBelowArcLength = (this.outP - this.outIntervalLeng * 2) / 2; // 外边圆底层半弧长
          console.log('外边圆底层半弧长=', this.outBelowArcLength);
        },
        /**
         * 计算进度弧长
         */
        getAboveArcLeng() {
          // 中间圆左边实线弧长
          this.leftMidSolidLine = this.leftPer
            ? (this.midBelowArcLength / 100) * this.leftPer - 10
            : 0;
          // console.log('中间圆左边实线弧长=', this.leftMidSolidLine);
          // 中间圆左边虚线弧长
          this.leftMidDottedLine = this.midP - this.leftMidSolidLine;
          // console.log('中间圆左边虚线弧长=', this.leftMidDottedLine);
    
          // 中间圆右边实线弧长
          this.rightMidSolidLine = this.rightPer
            ? (this.midBelowArcLength / 100) * this.rightPer - 10
            : 0;
          // console.log('中间圆右边实线弧长=', this.rightMidSolidLine);
          // 中间圆右边虚线弧长
          this.rightMidDottedLine = this.midP - this.rightMidSolidLine;
          // console.log('中间圆右边虚线弧长=', this.rightMidDottedLine);
    
          // 外边圆左边实线弧长
          this.leftOutSolidLine = this.leftPer
            ? (this.outBelowArcLength / 100) * this.leftPer
            : 0;
          // console.log('外边圆左边实线弧长=', this.outBelowArcLength);
          // 外边圆左边虚线弧长
          this.leftOutDottedLine = this.outP - this.leftOutSolidLine;
          // console.log('外边圆左边虚线弧长=', this.leftOutDottedLine);
    
          // 外边圆右边实线弧长
          this.rightOutSolidLine = this.rightPer
            ? (this.outBelowArcLength / 100) * this.rightPer - 10
            : 0;
          // console.log('外边圆右边实线弧长=', this.rightOutSolidLine);
          // 外边圆右边虚线弧长
          this.rightOutDottedLine = this.outP - this.rightOutSolidLine;
          // console.log('外边圆右边虚线弧长=', this.rightOutDottedLine);
        },
      },
    };
    </script>
    <style lang="scss" scoped>
    .circle-wrap {
      position: relative;
       100%;
      height: 100%;
    }
    .circle {
       100%;
      height: 100%;
    }
    
    .svg-text {
      font-size: 16px;
    }
    </style>
    
  • 相关阅读:
    HDU 1754线段树基本操作,建树,更新,查询
    用第三方下载工具下载官方XCode独立安装包的方法
    解决Windows平台通过cURL上传APP到蒲公英pgyer平台时无法使用中文升级描述的问题
    Cygwin 版本的 Curl 安装,提取,使用笔记
    Android Gradle 引用本地 AAR 的几种方式
    VM虚拟机快照还原效果实现方式
    插入中文错误ERROR 1406 (22001): Data too long for column 'name' at row 1
    mysql初始化默认为空的密码修改
    性能测试学习计划(转)
    context-param和init-param区别
  • 原文地址:https://www.cnblogs.com/zuoan-oopp/p/13815015.html
Copyright © 2020-2023  润新知