环形进度条(从0到100%)效果

最近公司项目中要用到这种类似环形进度条的效果,初始就从0开始动画到100%结束。动画结果始终会停留在100%上,并不会到因为数据的关系停留在一半。

如图

代码如下

demo.html 

 1 <!doctype html>
 2 <html lang="zh">
 3     <head>
 4         <meta charset="UTF-8">
 5         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 
 6         <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7         <title>demo</title>
 8         <style>
 9             .rad-prg{
10                 position: relative;
11             }
12             .rad-con{
13                 position: absolute;
14                 z-index: 1;
15                 top:0;
16                 left: 0;
17                 text-align: center;
18                 width:90px;
19                 height: 90px;
20                 padding: 10px;
21                 font-family: "microsoft yahei";
22             }
23         </style>
24     </head>
25     <body>
26         <div class="prg-cont rad-prg" id="indicatorContainer">
27             <div class="rad-con">
28                 <p>¥4999</p>
29                 <p>账户总览</p>
30             </div>
31         </div>
32         <script type="text/javascript" src="js/jquery.min.js"></script>
33         <script src="js/radialIndicator.js"></script>
34         <script>
35 
36             $('#indicatorContainer').radialIndicator({
37                 barColor: '#007aff',
38                 barWidth: 5,
39                 initValue: 0,
40                 roundCorner : true,
41                 percentage: true,
42                 displayNumber: false,
43                 radius: 50
44             });
45 
46             setTimeout(function(){
47                 var radObj = $('#indicatorContainer2').data('radialIndicator');
48                 radObj.animate(100);
49             },300);
50             
51         </script>
52     </body>
53 </html>

radialIndicator.js  这是jquery的插件

  1 /*
  2     radialIndicator.js v 1.0.0
  3     Author: Sudhanshu Yadav
  4     Copyright (c) 2015 Sudhanshu Yadav - ignitersworld.com , released under the MIT license.
  5     Demo on: ignitersworld.com/lab/radialIndicator.html
  6 */
  7 
  8 ;(function ($, window, document) {
  9     "use strict";
 10     //circumfence and quart value to start bar from top
 11     var circ = Math.PI * 2,
 12         quart = Math.PI / 2;
 13 
 14     //function to convert hex to rgb
 15 
 16     function hexToRgb(hex) {
 17         // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
 18         var shorthandRegex = /^#?([a-fd])([a-fd])([a-fd])$/i;
 19         hex = hex.replace(shorthandRegex, function (m, r, g, b) {
 20             return r + r + g + g + b + b;
 21         });
 22 
 23         var result = /^#?([a-fd]{2})([a-fd]{2})([a-fd]{2})$/i.exec(hex);
 24         return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : null;
 25     }
 26 
 27     function getPropVal(curShift, perShift, bottomRange, topRange) {
 28         return Math.round(bottomRange + ((topRange - bottomRange) * curShift / perShift));
 29     }
 30 
 31 
 32     //function to get current color in case of 
 33     function getCurrentColor(curPer, bottomVal, topVal, bottomColor, topColor) {
 34         var rgbAryTop = topColor.indexOf('#') != -1 ? hexToRgb(topColor) : topColor.match(/d+/g),
 35             rgbAryBottom = bottomColor.indexOf('#') != -1 ? hexToRgb(bottomColor) : bottomColor.match(/d+/g),
 36             perShift = topVal - bottomVal,
 37             curShift = curPer - bottomVal;
 38 
 39         if (!rgbAryTop || !rgbAryBottom) return null;
 40 
 41         return 'rgb(' + getPropVal(curShift, perShift, rgbAryBottom[0], rgbAryTop[0]) + ',' + getPropVal(curShift, perShift, rgbAryBottom[1], rgbAryTop[1]) + ',' + getPropVal(curShift, perShift, rgbAryBottom[2], rgbAryTop[2]) + ')';
 42     }
 43 
 44     //to merge object
 45     function merge() {
 46         var arg = arguments,
 47             target = arg[0];
 48         for (var i = 1, ln = arg.length; i < ln; i++) {
 49             var obj = arg[i];
 50             for (var k in obj) {
 51                 if (obj.hasOwnProperty(k)) {
 52                     target[k] = obj[k];
 53                 }
 54             }
 55         }
 56         return target;
 57     }
 58 
 59     //function to apply formatting on number depending on parameter
 60     function formatter(pattern) {
 61         return function (num) {
 62             if(!pattern) return num.toString();
 63             num = num || 0
 64             var numRev = num.toString().split('').reverse(),
 65                 output = pattern.split("").reverse(),
 66                 i = 0,
 67                 lastHashReplaced = 0;
 68 
 69             //changes hash with numbers
 70             for (var ln = output.length; i < ln; i++) {
 71                 if (!numRev.length) break;
 72                 if (output[i] == "#") {
 73                     lastHashReplaced = i;
 74                     output[i] = numRev.shift();
 75                 }
 76             }
 77 
 78             //add overflowing numbers before prefix
 79             output.splice(lastHashReplaced+1, output.lastIndexOf('#') - lastHashReplaced, numRev.reverse().join(""));
 80 
 81             return output.reverse().join('');
 82         }
 83     }
 84 
 85 
 86     //circle bar class
 87     function Indicator(container, indOption) {
 88         indOption = indOption || {};
 89         indOption = merge({}, radialIndicator.defaults, indOption);
 90 
 91         this.indOption = indOption;
 92 
 93         //create a queryselector if a selector string is passed in container
 94         if (typeof container == "string")
 95             container = document.querySelector(container);
 96 
 97         //get the first element if container is a node list
 98         if (container.length)
 99             container = container[0];
100 
101         this.container = container;
102 
103         //create a canvas element
104         var canElm = document.createElement("canvas");
105         container.appendChild(canElm);
106 
107         this.canElm = canElm; // dom object where drawing will happen
108 
109         this.ctx = canElm.getContext('2d'); //get 2d canvas context
110 
111         //add intial value 
112         this.current_value = indOption.initValue || indOption.minValue || 0;
113 
114     }
115 
116 
117     Indicator.prototype = {
118         constructor: radialIndicator,
119         init: function () {
120             var indOption = this.indOption,
121                 canElm = this.canElm,
122                 ctx = this.ctx,
123                 dim = (indOption.radius + indOption.barWidth) * 2, //elm width and height
124                 center = dim / 2; //center point in both x and y axis
125 
126 
127             //create a formatter function
128             this.formatter = typeof indOption.format == "function" ? indOption.format : formatter(indOption.format);
129 
130             //maximum text length;
131             this.maxLength = indOption.percentage ? 4 : this.formatter(indOption.maxValue).length;
132 
133             canElm.width = dim;
134             canElm.height = dim;
135 
136             //draw a grey circle
137             ctx.strokeStyle = indOption.barBgColor; //background circle color
138             ctx.lineWidth = indOption.barWidth;
139             ctx.beginPath();
140             ctx.arc(center, center, indOption.radius, 0, 2 * Math.PI);
141             ctx.stroke();
142 
143             //store the image data after grey circle draw
144             this.imgData = ctx.getImageData(0, 0, dim, dim);
145 
146             //put the initial value if defined
147             this.value(this.current_value);
148 
149             return this;
150         },
151         //update the value of indicator without animation
152         value: function (val) {
153             //return the val if val is not provided
154             if (val === undefined || isNaN(val)) {
155                 return this.current_value;
156             }
157 
158             val = parseInt(val);
159             
160             var ctx = this.ctx,
161                 indOption = this.indOption,
162                 curColor = indOption.barColor,
163                 dim = (indOption.radius + indOption.barWidth) * 2,
164                 minVal = indOption.minValue,
165                 maxVal = indOption.maxValue,
166                 center = dim / 2;
167 
168             //limit the val in range of 0 to 100
169             val = val < minVal ? minVal : val > maxVal ? maxVal : val;
170 
171             var perVal = Math.round(((val - minVal) * 100 / (maxVal - minVal)) * 100) / 100, //percentage value tp two decimal precision
172                 dispVal = indOption.percentage ? perVal + '%' : this.formatter(val); //formatted value
173 
174             //save val on object
175             this.current_value = val;
176 
177 
178             //draw the bg circle
179             ctx.putImageData(this.imgData, 0, 0);
180 
181             //get current color if color range is set
182             if (typeof curColor == "object") {
183                 var range = Object.keys(curColor);
184 
185                 for (var i = 1, ln = range.length; i < ln; i++) {
186                     var bottomVal = range[i - 1],
187                         topVal = range[i],
188                         bottomColor = curColor[bottomVal],
189                         topColor = curColor[topVal],
190                         newColor = val == bottomVal ? bottomColor : val == topVal ? topColor : val > bottomVal && val < topVal ? indOption.interpolate ? getCurrentColor(val, bottomVal, topVal, bottomColor, topColor) : topColor : false;
191 
192                     if (newColor != false) {
193                         curColor = newColor;
194                         break;
195                     }
196                 }
197             }
198 
199             //draw th circle value
200             ctx.strokeStyle = curColor;
201 
202             //add linecap if value setted on options
203             if (indOption.roundCorner) ctx.lineCap = "round";
204 
205             ctx.beginPath();
206             ctx.arc(center, center, indOption.radius, -(quart), ((circ) * perVal / 100) - quart, false);
207             ctx.stroke();
208 
209             //add percentage text
210             if (indOption.displayNumber) {
211                 var cFont = ctx.font.split(' '),
212                     weight = indOption.fontWeight,
213                     fontSize = indOption.fontSize || (dim / (this.maxLength - (Math.floor(this.maxLength*1.4/4)-1)));
214 
215                 cFont = indOption.fontFamily || cFont[cFont.length - 1];
216 
217 
218                 ctx.fillStyle = indOption.fontColor || curColor;
219                 ctx.font = weight +" "+ fontSize + "px " + cFont;
220                 ctx.textAlign = "center";
221                 ctx.textBaseline = 'middle';
222                 ctx.fillText(dispVal, center, center);
223             }
224 
225             return this;
226         },
227         //animate progressbar to the value
228         animate: function (val) {
229 
230             var indOption = this.indOption,
231                 counter = this.current_value || indOption.minValue,
232                 self = this,
233                 incBy = Math.ceil((indOption.maxValue - indOption.minValue) / (indOption.frameNum || (indOption.percentage ? 100 : 500))), //increment by .2% on every tick and 1% if showing as percentage
234                 back = val < counter;
235 
236             //clear interval function if already started
237             if (this.intvFunc) clearInterval(this.intvFunc); 
238 
239             this.intvFunc = setInterval(function () {
240 
241                 if ((!back && counter >= val) || (back && counter <= val)) {
242                     if (self.current_value == counter) {
243                         clearInterval(self.intvFunc);
244                         return;
245                     } else {
246                         counter = val;
247                     }
248                 }
249 
250                 self.value(counter); //dispaly the value
251 
252                 if (counter != val) {
253                     counter = counter + (back ? -incBy : incBy)
254                 }; //increment or decrement till counter does not reach  to value
255             }, indOption.frameTime);
256 
257             return this;
258         },
259         //method to update options
260         option: function (key, val) {
261             if (val === undefined) return this.option[key];
262 
263             if (['radius', 'barWidth', 'barBgColor', 'format', 'maxValue', 'percentage'].indexOf(key) != -1) {
264                 this.indOption[key] = val;
265                 this.init().value(this.current_value);
266             }
267             this.indOption[key] = val;
268         }
269 
270     };
271 
272     /** Initializer function **/
273     function radialIndicator(container, options) {
274         var progObj = new Indicator(container, options);
275         progObj.init();
276         return progObj;
277     }
278 
279     //radial indicator defaults
280     radialIndicator.defaults = {
281         radius: 50, //inner radius of indicator
282         barWidth: 5, //bar width
283         barBgColor: '#eeeeee', //unfilled bar color
284         barColor: '#99CC33', //filled bar color , can be a range also having different colors on different value like {0 : "#ccc", 50 : '#333', 100: '#000'}
285         format: null, //format indicator numbers, can be a # formator ex (##,###.##) or a function
286         frameTime: 10, //miliseconds to move from one frame to another
287         frameNum: null, //Defines numbers of frame in indicator, defaults to 100 when showing percentage and 500 for other values
288         fontColor: null, //font color
289         fontFamily: null, //defines font family
290         fontWeight: 'bold', //defines font weight
291         fontSize : null, //define the font size of indicator number
292         interpolate: true, //interpolate color between ranges
293         percentage: false, //show percentage of value
294         displayNumber: true, //display indicator number
295         roundCorner: false, //have round corner in filled bar
296         minValue: 0, //minimum value
297         maxValue: 100, //maximum value
298         initValue: 0 //define initial value of indicator
299     };
300     
301     window.radialIndicator = radialIndicator;
302 
303     //add as a jquery plugin
304     if ($) {
305         $.fn.radialIndicator = function (options) {
306             return this.each(function () {
307                 var newPCObj = radialIndicator(this, options);
308                 $.data(this, 'radialIndicator', newPCObj);
309             });
310         };
311     }
312 
313 }(window.jQuery, window, document, void 0));
原文地址:https://www.cnblogs.com/sonicwater/p/5643627.html