基于面向对象思想封装一个水球插件
首先上图,
需要一个环形的水球,没错,我和大家想的一样,去把插件,可是没有一个满意的插件,败兴而归啊;自己动手实践;下面对于开发思路总结:
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 }
最后附上我的实际最后的效果
优秀的人一直在路上,优秀的你一直在尝试写新bug