Recently, I need to use a progress display component for the effect of water wave ball. After consulting some materials, I learned from others’ codes and finally completed the requirements

Effect:

It is mainly implemented through canvas, which can dynamically set the following contents:

Parameters:

props meaning type Value range default
rate Numerical proportion Number 0 ~ 1 0.6
bSize The width of a ball high Number 1 ~ 12 100(unit: px)
waveColor The waves color String Hexadecimal only ‘#1c86d1’
fontColor The font color String Hexadecimal or RGB ‘#8B008B’
fontSize The font size Number 26(unit: px)
speed Wave speed Number 1 ~ 12 3
flat Wave smoothness Number 200 ~ 600 400
distance Wave offset Number 0 ~ 200 150
wave Degree of undulation Number 5 ~ 60 10
opacity Transparency of undulation Number 200 ~ 600 0.5

The code is as follows:

<template> <div class="content" :style="{ width: bSize + 'px', height: bSize + 'px', borderColor: waveColor, }" > <canvas id="canvas"></canvas> <p class="value" :style="{ color: fontColor, fontSize:fontSize = 'px' }">{{ rate * 100 }}%</p> </div> </template> <script> export default { data() { return {} }, Props: {rate: {type: Number, // Scale min=0 Max =1 default: 0.6,}, bSize: {type: Number, // width of the ball default: 100,}, waveColor: {type: String, // waveColor can only be hexadecimal default: '#D8BFD8',}, fontColor: {type: String, // fontColor default: {type: String, // fontColor default: '#8B008B',}, speed: {type: Number, // wave speed min=1 Max =12 default: 3,}, flat: {type: Number, // wave smoothness min=200 Max =600 default: 400,}, distance: {type: Number, // wave smoothness min=0 Max =200 default: 400,}, distance: {type: Number, // wave smoothness min=0 Max =200 default: Opacity: 0, opacity: 0, opacity: 0, opacity: 0, opacity: 0, opacity: 0, opacity: 0, opacity: 0, opacity: 0, opacity: 0, opacity: 0, opacity: 0 FontSize: {type:Number, // fontSize default:26,}}, methods: DrawSin (CTX, mW, color1, wav, dY) {ctx.save() ctx.beginPath() ctx.moveto (0, mW) ctx.lineto (0, mW) ctx.beginPath() ctx.moveto (0, mW) ctx.lineto (0, mW) dY) ctx.quadraticCurveTo(mW / 4, dY - wav, mW / 2, dY) ctx.lineTo(mW / 2, dY) ctx.quadraticCurveTo((mW * 3) / 4, dY + wav, mW, dY) ctx.lineTo(mW, mW) ctx.lineTo(0, mW) ctx.fillStyle = color1 ctx.fill() ctx.restore() }, Var canvas1 = document.getelementById ('canvas') var mW = canvas1.clientWidth // Sets the height of the Canvas element Canvas1. width = canvas1.height = mW var canvas2 = document.createElement('canvas'), ctx2 = canvas2.getContext('2d') canvas2.width = mW canvas2.height = mW var canvas3 = document.createElement('canvas'), ctx3 = canvas3.getContext('2d') canvas3.width = mW canvas3.height = mW var { flat, speed, rate, distance, wave, waveColor, opacity } = this var x = 0 var ctx1 = canvas1.getContext('2d') this.drawSin(ctx2, mW, waveColor, waveColor, wave, mW - mW * rate) this.drawSin(ctx3, mW, `${this.sixteenToRgba(waveColor, opacity)}`, null, wave, mW - mW * rate) var rate1 = rate, wave1 = wave function animation() { if (rate ! == rate1 || wave1 ! == wave) { ctx2.clearRect(0, 0, mW, mW) ctx3.clearRect(0, 0, mW, mW) rate1 = rate wave1 = wave this.drawSin(ctx2, mW, waveColor, waveColor, wave, mW - mW * rate) this.drawSin(ctx3, mW, `${this.sixteenToRgba(waveColor, opacity)}`, null, wave, mW - mW * rate) } ctx1.clearRect(0, 0, mW, mW) ctx1.drawImage(canvas2, x, 0, mW + flat, mW) ctx1.drawImage(canvas2, x - mW - flat, 0, mW + flat, mW) ctx1.drawImage(canvas3, x + distance, 0, mW + flat, mW) ctx1.drawImage(canvas3, x - mW + distance - flat, 0, mW + flat, mW) x >= mW - speed + flat ? (x = 0) : (x += speed) requestAnimationFrame(animation)} animation()}, // Hex color to rgba transparency sixteenToRgba(sixteen, opacity) { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/ var sColor = sixteen if (sColor && reg.test(sColor)) { if (sColor.length === 4) { var sColorNew = '#' for (var i = 1; i < 4; i += 1) { sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, Var sColorChange = [] for (var I = 1; i < 7; i += 2) { sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2))) } return 'rgba(' + sColorChange.join(',') + `,${opacity})` } else { return sColor } }, }, mounted() { this.init() }, } </script> <style lang='less' scoped> .content { position: relative; border-radius: 50%; border: 1px solid #1c86d1; overflow: hidden; padding: 8px; box-sizing: border-box; .value { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); font-size: 24px; // font-weight: bold; } canvas { width: 100%; height: 100%; border-radius: 50%; } } </style>Copy the code

Used as a component:

   <wave-ball
      class="ball"
      :rate="0.36"
      :bSize="120"
      :waveColor="'Thistle'"
      :fontColor="'#8B008B'"
      :fontSize="28"
    ></wave-ball>
Copy the code

Finally:

Although it is still very simple, but I hope to help the people in need, also welcome big guy to improve ~

Reference: https://segmentfault.com/a/1190000021043704