首页 > 技术文章 > JavaScript+canvas圆形水波进度条,百分比显示数据

facenano 2021-10-21 14:39 原文

浏览器显示的效果

 

 

 头部

<head>
    <meta charset="UTF-8">
    <title>test</title>
    <style>
       body {
        margin-top: 60px;
        display: flex;
        flex-flow: column wrap;
        justify-content: center;
        align-items: center;
        background: #000;
      }
      #c {
        background: url(../css/img/pie-g.png) center 25% no-repeat;
      }
      p {
        color: #00d2ff;
        font-size: 26px;
      }
      input[type=range]::before {content: attr(min);  color: #000; padding-right: 15px;}
      input[type=range]::after { content: attr(max); color: #000; padding-left: 15px;}
    </style>
</head>

  

主体

  1 <body>
  2     <canvas id="c">当前浏览器不支持canvas 请升级!</canvas>
  3     <input type="range" name="range" min="0" max="100" step="1" style="display: none;">
  4     <p>网站应用</p>
  5 </body>
  6 <script>
  7 let canvas = document.getElementById("c")
  8 let ctx = canvas.getContext("2d")
  9 let oRange = document.getElementsByName("range")[0];
 10 let M = Math
 11 let Sin = M.sin
 12 let Cos = M.cos
 13 let Sqrt = M.sqrt
 14 let Pow = M.pow
 15 let PI = M.PI
 16 let Round = M.round
 17 let oW = canvas.width = 230
 18 let oH = canvas.height = 230
 19 let lineWidth = 2 // 线宽
 20 let r = (oW / 2) // 大半径
 21 let cR = r - 10 * lineWidth
 22 ctx.beginPath()
 23 ctx.lineWidth = lineWidth
 24  
 25 // 水波动画初始参数
 26 let axisLength = 2 * r - 16 * lineWidth // Sin 图形长度
 27 let unit = axisLength / 9 // 波浪宽
 28 let range = .4 // 浪幅
 29 let nowrange = range
 30 let xoffset = 8 * lineWidth // x 轴偏移量
 31 let data = ~~(oRange.value) / 100 // 数据量
 32 let sp = 0 // 周期偏移量
 33 let nowdata = 0
 34 let waveupsp = 0.006 // 水波上涨速度
 35  
 36 // 圆动画初始参数
 37 let arcStack = [] // 圆栈
 38 let bR = r - 8 * lineWidth
 39 let soffset = -(PI / 2) // 圆动画起始位置
 40 let circleLock = true // 起始动画锁
 41  
 42 // 获取圆动画轨迹点集
 43 for (var i = soffset; i < soffset + 2 * PI; i += 1 / (8 * PI)) {
 44     arcStack.push([
 45         r + bR * Cos(i),
 46         r + bR * Sin(i)
 47     ])
 48 }
 49 // 圆起始点
 50 let cStartPoint = arcStack.shift();
 51 ctx.strokeStyle = "#1c86d1";
 52 ctx.moveTo(cStartPoint[0], cStartPoint[1]);
 53 // 开始渲染
 54 render();
 55  
 56 function drawSine() {
 57     ctx.beginPath();
 58     ctx.save();
 59     var Stack = []; // 记录起始点和终点坐标
 60     for (var i = xoffset; i <= xoffset + axisLength; i += 20 / axisLength) {
 61         var x = sp + (xoffset + i) / unit;
 62         var y = Sin(x) * nowrange;
 63         var dx = i;
 64         var dy = 2 * cR * (1 - nowdata) + (r - cR) - (unit * y);
 65         ctx.lineTo(dx, dy);
 66         Stack.push([dx, dy])
 67     }
 68     // 获取初始点和结束点
 69     var startP = Stack[0]
 70     var endP = Stack[Stack.length - 1]
 71     ctx.lineTo(xoffset + axisLength, oW);
 72     ctx.lineTo(xoffset, oW);
 73     ctx.lineTo(startP[0], startP[1])
 74     ctx.fillStyle = "#43bd00";
 75     ctx.fill();
 76     ctx.restore();
 77 }
 78  
 79 function drawText() {
 80     ctx.globalCompositeOperation = 'source-over';
 81     var size = 0.4 * cR;
 82     ctx.font = 'bold ' + size + 'px Microsoft Yahei';
 83     let txt = (nowdata.toFixed(2) * 100).toFixed(0) + '.92' + '%';
 84     var fonty = r + size / 2;
 85     var fontx = r - size * 0.8;
 86     ctx.fillStyle = "#fff";
 87     ctx.textAlign = 'center';
 88     ctx.fillText(txt, r + 5, r + 20)
 89 }
 90 //最外面淡黄色圈
 91 function drawCircle() {
 92     ctx.beginPath();
 93     ctx.lineWidth = 10;
 94     ctx.strokeStyle = '#43bd00';
 95     ctx.arc(r, r, cR + 7, 0, 2 * Math.PI);
 96     ctx.stroke();
 97     ctx.restore();
 98 }
 99 //灰色圆圈
100 function grayCircle() {
101     ctx.beginPath();
102     ctx.lineWidth = 10;
103     ctx.strokeStyle = '#030b30';
104     ctx.arc(r, r, cR - 5, 0, 2 * Math.PI);
105     ctx.stroke();
106     ctx.restore();
107     ctx.beginPath();
108 }
109 //橘黄色进度圈
110 function orangeCircle() {
111     ctx.beginPath();
112     // ctx.strokeStyle = '#030b30';
113     //使用这个使圆环两端是圆弧形状
114     ctx.lineCap = 'round';
115     ctx.arc(r, r, cR - 5, 0 * (Math.PI / 180.0) - (Math.PI / 2), (nowdata * 360) * (Math.PI / 180.0) - (Math.PI / 2));
116     ctx.stroke();
117     ctx.save()
118 }
119 //裁剪中间水圈
120 function clipCircle() {
121     ctx.beginPath();
122     ctx.arc(r, r, cR - 10, 0, 2 * Math.PI, false);
123     ctx.clip();
124 }
125 //渲染canvas
126 function render() {
127     ctx.clearRect(0, 0, oW, oH);
128     //最外面淡黄色圈
129     drawCircle();
130     //灰色圆圈
131     grayCircle();
132     //橘黄色进度圈
133     orangeCircle();
134     //裁剪中间水圈
135     clipCircle();
136     // 控制波幅
137     oRange.addEventListener("change", function() {
138         data = ~~(oRange.value) / 100;
139     }, 0);
140     if (data >= 0.85) {
141         if (nowrange > range / 4) {
142             var t = range * 0.01;
143             nowrange -= t;
144         }
145     } else if (data <= 0.1) {
146         if (nowrange < range * 1.5) {
147             var t = range * 0.01;
148             nowrange += t;
149         }
150     } else {
151         if (nowrange <= range) {
152             var t = range * 0.01;
153             nowrange += t;
154         }
155         if (nowrange >= range) {
156             var t = range * 0.01;
157             nowrange -= t;
158         }
159     }
160     if ((data - nowdata) > 0) {
161         nowdata += waveupsp;
162     }
163     if ((data - nowdata) < 0) {
164         nowdata -= waveupsp
165     }
166 
167     data = 0.643 //给固定值
168     data = 0.423 //给固定值
169     data = 0.3592 //给固定值
170 
171     sp += 0.07;
172     // 开始水波动画
173     drawSine();
174     // 写字
175     drawText();
176     requestAnimationFrame(render)
177 }
178 </script>

 

推荐阅读