基于面向对象思想封装一个水球插件


首先上图,

需要一个环形的水球,没错,我和大家想的一样,去把插件,可是没有一个满意的插件,败兴而归啊;自己动手实践;下面对于开发思路总结:

1.绘制图型需要canvas,canvas中我们需要绘制圆,裁切,绘制文字,进度绘制其实也是圆

2.html5元素canvas

3.是否需要其他的插件做为依赖,为了高的移植性和复制性,那么我打算去掉了依赖的jquery等

好了,先开始第一版

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

但是这样并不友好,每一次都需要写这么长的脚本,实在不符合前端的工程化编程;进入优化时代:

1.我们可以像swiper那样通过一个对象来实例化每一个轮播对象,那么我们也创建一个对象实例化我们的水球

2.确定一些可变的参数:比如背景色,进度条的颜色,

3.对象内的方法私有化,减少全局使用

4.独立我们需要的水球效果脚本,只需要传入id和实例化参数可以实现不同的样式

5.对于不输入参数的,我们实例化时自动配置默认的一些参数;

  1 /**
  2  *  author:starry
  3  *  version:0.0.1;
  4  *  params:{
  5  *    id:canvans的id,默认canvas string
  6  *    text:为空则不显示,水纹的字体颜色 string
  7  *    textC:字体颜色,默认是#000, string
  8  *    r:圆球半径大小 number
  9  *    lineW:线条的粗细 number
 10  *    data:进度数据,number
 11  *    pC: 进度条颜色  string
 12  *    wc:水球颜色    string
 13  *    bg: canvas背景色 string
 14  * }
 15  *
 16  */
 17 function getWater(options) {
 18   let id = options.id ? options.id : "canvas";
 19   let text = options.text ? options.text : "";
 20   let textC = options.textC ? options.textC : "#000";
 21   let r = options.r ? options.r : 200;
 22   let lineW = options.w ? options.w : 1;
 23   let data = options.data ? options.data : 30;
 24   let progress = options.pC ? options.pC : "";
 25   let wc = options.wc ? options.wc : "#3B7BF8";
 26   let bg = options.bg ? options.bg : "#fff";
 27   canvas = document.getElementById(id);
 28 
 29   this.ctx = canvas.getContext("2d");
 30 
 31   M = Math;
 32   Sin = M.sin;
 33   Cos = M.cos;
 34   Sqrt = M.sqrt;
 35   Pow = M.pow;
 36   PI = M.PI;
 37   Round = M.round;
 38   oW = canvas.width = r;
 39   oH = canvas.height = r;
 40   if (options.bg != "") {
 41     canvas.style.borderRadius = "50%";
 42   }
 43   canvas.style.background = bg;
 44   // 线宽
 45   lineWidth = lineW;
 46   // 大半径
 47   r = oW / 2;
 48   cR = r - 1 * lineWidth;
 49   this.ctx.beginPath();
 50   this.ctx.lineWidth = lineWidth;
 51   // 水波动画初始参数
 52   axisLength = 2 * r - 16 * lineWidth; // Sin 图形长度
 53   unit = axisLength / 9; // 波浪宽
 54   range = 0.4; // 浪幅
 55   nowrange = range;
 56   xoffset = 8 * lineWidth; // x 轴偏移量
 57   this.data = data / 100; // 数据量
 58   sp = 0; // 周期偏移量
 59   this.nowdata = 0;
 60   waveupsp = 0.006; // 水波上涨速度
 61   // 圆动画初始参数
 62   arcStack = []; // 圆栈
 63   bR = r - 20 * lineWidth;
 64   soffset = -(PI / 2); // 圆动画起始位置
 65   circleLock = true; // 起始动画锁
 66   // 获取圆动画轨迹点集
 67   for (var i = soffset; i < soffset + 2 * PI; i += 1 / (8 * PI)) {
 68     arcStack.push([r + bR * Cos(i), r + bR * Sin(i)]);
 69   }
 70   // 圆起始点
 71   cStartPoint = arcStack.shift();
 72   this.ctx.fillStyle = "transparent";
 73   this.ctx.moveTo(cStartPoint[0], cStartPoint[1]);
 74   this.ctx.fill();
 75   // 开始渲染
 76   this.drawSine = function() {
 77     this.ctx.beginPath();
 78     this.ctx.save();
 79     var Stack = []; // 记录起始点和终点坐标
 80     for (var i = xoffset; i <= xoffset + axisLength; i += 20 / axisLength) {
 81       var x = sp + (xoffset + i) / unit;
 82       var y = Sin(x) * nowrange;
 83       var dx = i;
 84       var dy = 2 * cR * (1 - that.nowdata) + (r - cR) - unit * y;
 85       this.ctx.lineTo(dx, dy);
 86       Stack.push([dx, dy]);
 87     }
 88     // 获取初始点和结束点
 89     var startP = Stack[0];
 90     var endP = Stack[Stack.length - 1];
 91     this.ctx.lineTo(xoffset + axisLength, oW);
 92     this.ctx.lineTo(xoffset, oW);
 93     this.ctx.lineTo(startP[0], startP[1]);
 94     this.ctx.fillStyle = wc;
 95     this.ctx.fill();
 96     this.ctx.restore();
 97   };
 98   this.drawText = function() {
 99     this.ctx.globalCompositeOperation = "source-over";
100     var size = 0.4 * cR;
101     this.ctx.font = "bold " + size + "px Microsoft Yahei";
102 
103     if (typeof text == "number") {
104       txt = (that.nowdata.toFixed(2) * 100).toFixed(0) + "%";
105     } else {
106       txt = text;
107     }
108 
109     var fonty = r + size / 2;
110     var fontx = r - size * 0.8;
111     this.ctx.fillStyle = textC;
112     this.ctx.textAlign = "center";
113     this.ctx.fillText(txt, r + 5, r + 20);
114   };
115   //最外面淡黄色圈
116   this.drawCircle = function() {
117     this.ctx.beginPath();
118     this.ctx.lineWidth = 15;
119     this.ctx.strokeStyle = progress;
120     this.ctx.arc(r, r, cR - 6.1, 0, 2 * Math.PI);
121     this.ctx.stroke();
122     this.ctx.restore();
123   };
124   //灰色圆圈
125   this.grayCircle = function() {
126     this.ctx.beginPath();
127     this.ctx.lineWidth = 1;
128     this.ctx.strokeStyle = "transparent";
129     this.ctx.arc(r, r, cR + 10, 0, 2 * Math.PI);
130     this.ctx.stroke();
131     this.ctx.restore();
132     this.ctx.beginPath();
133   };
134   //橘黄色进度圈
135   this.orangeCircle = function() {
136     this.ctx.beginPath();
137     this.ctx.strokeStyle = "#B0BAEE";
138     //使用这个使圆环两端是圆弧形状
139     this.ctx.lineCap = "round";
140     this.ctx.arc(
141       r,
142       r,
143       cR - 4,
144       0 * (Math.PI / 180.0) - Math.PI / 2,
145       that.nowdata * 360 * (Math.PI / 180.0) - Math.PI / 2
146     );
147     this.ctx.stroke();
148     this.ctx.save();
149   };
150   //裁剪中间水圈
151   this.clipCircle = function() {
152     this.ctx.beginPath();
153     this.ctx.arc(r, r, cR - 10, 0, 2 * Math.PI, false);
154     this.ctx.clip();
155   };
156   var that = this;
157   this.render = function() {
158     that.ctx.clearRect(0, 0, oW, oH);
159     //最外面淡黄色圈
160     that.drawCircle();
161     //灰色圆圈
162     that.grayCircle();
163     //橘黄色进度圈
164     that.orangeCircle();
165     //裁剪中间水圈
166     that.clipCircle();
167     // 控制波幅
168 
169     if (that.data >= 0.85) {
170       if (nowrange > range / 4) {
171         var t = range * 0.01;
172         nowrange -= t;
173       }
174     } else if (that.data <= 0.1) {
175       if (nowrange < range * 1.5) {
176         var t = range * 0.01;
177         nowrange += t;
178       }
179     } else {
180       if (nowrange <= range) {
181         var t = range * 0.01;
182         nowrange += t;
183       }
184       if (nowrange >= range) {
185         var t = range * 0.01;
186         nowrange -= t;
187       }
188     }
189     if (that.data - that.nowdata > 0) {
190       that.nowdata += waveupsp;
191     }
192     if (that.data - that.nowdata < 0) {
193       that.nowdata -= waveupsp;
194     }
195     sp += 0.07;
196     // 开始水波动画
197     that.drawSine();
198     // 写字
199     if (text != "") {
200       that.drawText();
201     }
202     requestAnimationFrame(that.render);
203   };
204   this.render();
205 
206   //渲染canvas
207 }

这么一看我们示例化水球就好对多了

没错,就怎么new一下就可以了

但是发现一个问题进度条并没有随着数值的改变而改变只是和最后一个data:10保持一致,这个不可以啊,感觉弱爆了,不行再有化一下,

  1 /**
  2  *  author:starry
  3  *  version:0.0.1;
  4  *  params:{
  5  *    id:canvans的id,默认canvas string
  6  *    text:为空则不显示,水纹的字体颜色 string
  7  *    textC:字体颜色,默认是#000, string
  8  *    r:圆球半径大小 number
  9  *    lineW:线条的粗细 number
 10  *    data:进度数据,number
 11  *    pC: 进度条颜色  string
 12  *    wc:水球颜色    string
 13  *    bg: canvas背景色 string
 14  * }
 15  *
 16  */
 17 function getWater(options) {
 18   let id = options.id ? options.id : "canvas";
 19   let text = options.text ? options.text : "";
 20   let textC = options.textC ? options.textC : "#000";
 21   let r = options.r ? options.r : 200;
 22   let lineW = options.w ? options.w : 1;
 23   let data = options.data ? options.data : 30;
 24   let progress = options.pC ? options.pC : "";
 25   let wc = options.wc ? options.wc : "#3B7BF8";
 26   let bg = options.bg ? options.bg : "#fff";
 27   canvas = document.getElementById(id);
 28 
 29   this.ctx = canvas.getContext("2d");
 30 
 31   M = Math;
 32   Sin = M.sin;
 33   Cos = M.cos;
 34   Sqrt = M.sqrt;
 35   Pow = M.pow;
 36   PI = M.PI;
 37   Round = M.round;
 38   oW = canvas.width = r;
 39   oH = canvas.height = r;
 40   if (options.bg != "") {
 41     canvas.style.borderRadius = "50%";
 42   }
 43   canvas.style.background = bg;
 44   // 线宽
 45   lineWidth = lineW;
 46   // 大半径
 47   r = oW / 2;
 48   cR = r - 1 * lineWidth;
 49   this.ctx.beginPath();
 50   this.ctx.lineWidth = lineWidth;
 51   // 水波动画初始参数
 52   axisLength = 2 * r - 16 * lineWidth; // Sin 图形长度
 53   unit = axisLength / 9; // 波浪宽
 54   range = 0.4; // 浪幅
 55   nowrange = range;
 56   xoffset = 8 * lineWidth; // x 轴偏移量
 57   this.data = data / 100; // 数据量
 58   sp = 0; // 周期偏移量
 59   this.nowdata = 0;
 60   waveupsp = 0.006; // 水波上涨速度
 61   // 圆动画初始参数
 62   arcStack = []; // 圆栈
 63   bR = r - 20 * lineWidth;
 64   soffset = -(PI / 2); // 圆动画起始位置
 65   circleLock = true; // 起始动画锁
 66   // 获取圆动画轨迹点集
 67   for (var i = soffset; i < soffset + 2 * PI; i += 1 / (8 * PI)) {
 68     arcStack.push([r + bR * Cos(i), r + bR * Sin(i)]);
 69   }
 70   // 圆起始点
 71   cStartPoint = arcStack.shift();
 72   this.ctx.fillStyle = "transparent";
 73   this.ctx.moveTo(cStartPoint[0], cStartPoint[1]);
 74   this.ctx.fill();
 75   // 开始渲染
 76   this.drawSine = function() {
 77     this.ctx.beginPath();
 78     this.ctx.save();
 79     var Stack = []; // 记录起始点和终点坐标
 80     for (var i = xoffset; i <= xoffset + axisLength; i += 20 / axisLength) {
 81       var x = sp + (xoffset + i) / unit;
 82       var y = Sin(x) * nowrange;
 83       var dx = i;
 84       var dy = 2 * cR * (1 - that.nowdata) + (r - cR) - unit * y;
 85       this.ctx.lineTo(dx, dy);
 86       Stack.push([dx, dy]);
 87     }
 88     // 获取初始点和结束点
 89     var startP = Stack[0];
 90     var endP = Stack[Stack.length - 1];
 91     this.ctx.lineTo(xoffset + axisLength, oW);
 92     this.ctx.lineTo(xoffset, oW);
 93     this.ctx.lineTo(startP[0], startP[1]);
 94     this.ctx.fillStyle = wc;
 95     this.ctx.fill();
 96     this.ctx.restore();
 97   };
 98   this.drawText = function() {
 99     this.ctx.globalCompositeOperation = "source-over";
100     var size = 0.4 * cR;
101     this.ctx.font = "bold " + size + "px Microsoft Yahei";
102 
103     if (typeof text == "number") {
104       txt = (that.nowdata.toFixed(2) * 100).toFixed(0) + "%";
105     } else {
106       txt = text;
107     }
108 
109     var fonty = r + size / 2;
110     var fontx = r - size * 0.8;
111     this.ctx.fillStyle = textC;
112     this.ctx.textAlign = "center";
113     this.ctx.fillText(txt, r + 5, r + 20);
114   };
115   //最外面淡黄色圈
116   this.drawCircle = function() {
117     this.ctx.beginPath();
118     this.ctx.lineWidth = 15;
119     this.ctx.strokeStyle = progress;
120     this.ctx.arc(r, r, cR - 6.1, 0, 2 * Math.PI);
121     this.ctx.stroke();
122     this.ctx.restore();
123   };
124   //灰色圆圈
125   this.grayCircle = function() {
126     this.ctx.beginPath();
127     this.ctx.lineWidth = 1;
128     this.ctx.strokeStyle = "transparent";
129     this.ctx.arc(r, r, cR + 10, 0, 2 * Math.PI);
130     this.ctx.stroke();
131     this.ctx.restore();
132     this.ctx.beginPath();
133   };
134   //橘黄色进度圈
135   this.orangeCircle = function() {
136     this.ctx.beginPath();
137     this.ctx.strokeStyle = "#B0BAEE";
138     //使用这个使圆环两端是圆弧形状
139     this.ctx.lineCap = "round";
140     this.ctx.arc(
141       r,
142       r,
143       cR - 4,
144       0 * (Math.PI / 180.0) - Math.PI / 2,
145       that.nowdata * 360 * (Math.PI / 180.0) - Math.PI / 2
146     );
147     this.ctx.stroke();
148     this.ctx.save();
149   };
150   //裁剪中间水圈
151   this.clipCircle = function() {
152     this.ctx.beginPath();
153     this.ctx.arc(r, r, cR - 10, 0, 2 * Math.PI, false);
154     this.ctx.clip();
155   };
156   var that = this;
157   this.render = function() {
158     that.ctx.clearRect(0, 0, oW, oH);
159     //最外面淡黄色圈
160     that.drawCircle();
161     //灰色圆圈
162     that.grayCircle();
163     //橘黄色进度圈
164     that.orangeCircle();
165     //裁剪中间水圈
166     that.clipCircle();
167     // 控制波幅
168 
169     if (that.data >= 0.85) {
170       if (nowrange > range / 4) {
171         var t = range * 0.01;
172         nowrange -= t;
173       }
174     } else if (that.data <= 0.1) {
175       if (nowrange < range * 1.5) {
176         var t = range * 0.01;
177         nowrange += t;
178       }
179     } else {
180       if (nowrange <= range) {
181         var t = range * 0.01;
182         nowrange += t;
183       }
184       if (nowrange >= range) {
185         var t = range * 0.01;
186         nowrange -= t;
187       }
188     }
189     if (that.data - that.nowdata > 0) {
190       that.nowdata += waveupsp;
191     }
192     if (that.data - that.nowdata < 0) {
193       that.nowdata -= waveupsp;
194     }
195     sp += 0.07;
196     // 开始水波动画
197     that.drawSine();
198     // 写字
199     if (text != "") {
200       that.drawText();
201     }
202     requestAnimationFrame(that.render);
203   };
204   this.render();
205 
206   //渲染canvas
207 }

最后附上我的实际最后的效果

 


作者:星光笔,发布于:2019/03/15
原文:https://www.cnblogs.com/starryqian/p/10535049.html