Canvas draws water balloon
To draw a water balloon map by using canvasApi, we continue to be familiar with the basic use of Canvas and cubic Bezier curve, and at the same time introduce new canvas clipping function and anti-aliasing skills. The renderings are as follows: Gitee source code, Github source code
Analysis of preparation
Analysis of the whole water sphere diagram, waveform drawing is the biggest difficulty of the whole drawing process. Drawing waveform, the first difficulty is the shape of ripple, in fact, you can choose two methods to draw, the first one, to adopt the form of arc splicing; The second method is to use cubic Bezier curve to draw the curve. In order to get familiar with the drawing process of the cubic Bezier curve again, method two is adopted. The second difficulty of waveform drawing is how to draw waveform in a circle, which requires the use of clip, Save and restore functions. The details can be found in MDN documents.
The second difficulty of drawing water balloon map is how to draw the effect of water diffuse text. We observed the effect of the water diffuse text, not the water diffuse part is the top color, otherwise it is white. Therefore, we can consider drawing a text with a background color first, and then using the cropping effect to draw the white part of the water.
- First draw a text with a background color
clip
After clipping, draw an identical white text in the same position
We drew a total of three layers of water ripples, in each layer of water ripples need to draw the white part, otherwise someone behind the waves will cover the text. But text with a background color only needs to be drawn when the lowest ripple is drawn.
Finally, in the water polo after the completion of the drawing, we will find that the circle of the lateral is not smooth, into a jagged, at this point, we need to use the canvas anti-aliasing skills, anti-aliasing actually very simple, just like everyone in the pool is very close to the wall, you may find that metope is bumpy, but stand far, metope can feel very smooth. Because we can’t see details from a distance, our brain automatically thinks that the wall is flat. The same principle can be used for anti-aliasing. As long as you can’t see the real edge, the edge will look smoother. Therefore, it is necessary to use the shadow to blur the edge, and use the attributes of shadowColor shadowBlur shadowOffsetX shadowOffsetY.
Code sample
See the source repository posted at the beginning of the article for complete source code
function WaterCahrt(id, data) {
let canvas = document.getElementById(id)
let ctx = canvas.getContext('2d')
let canvasWidth = canvas.width > canvas.height ? canvas.height : canvas.width
let r = canvasWidth * 0.8 / 2
let offset = [0.20.40]
this.canvas = canvas
this.ctx = ctx
this.data = data
this.r = r / / circle radius
this.center = canvasWidth / 2 // Center x (y)
this.intervalId = null
Object.defineProperty(this.'offset', { // Define the offset of the water chart, automatically trigger the update when the offset changes
enumerable: false.configurable: false.get() {
return offset
},
set(val) {
offset = val
this.refresh()
}
})
}
Copy the code
The offset is set as an array so that the three waves move at different speeds.
/** * draw the water wave map *@param {number} The initial x value of the BASex ripple *@param {number} The starting point of the Basey ripple y value *@param {strign} Color The color of the ripple *@param {boolean} Flag whether to draw text with the same color as the ripple. In theory, only the lowest ripple needs to draw */
WaterCahrt.prototype.drawWater = function(basex, basey, color, flag) {
let bezier = this.getBezierPoints(basex, basey) // Generate a cubic Bezier curve
this.ctx.save() // Store the brush state
// Draw the waveform
this.ctx.beginPath()
this.ctx.moveTo(this.center - this.r, this.center + this.r)
this.ctx.lineTo(bezier.x, bezier.y)
bezier.points.forEach((item) = > {
this.ctx.bezierCurveTo(item.cp1x, item.cp1y, item.cp2x, item.cp2y, item.x, item.y)
})
this.ctx.lineTo(this.center + this.r, this.center + this.r)
this.ctx.closePath()
this.ctx.fillStyle = color
this.ctx.shadowColor = color / / anti-aliasing
this.ctx.shadowBlur = 2
this.ctx.fill()
this.ctx.shadowBlur = 0
// Draw text with a background color
this.ctx.font = `normal The ${this.r * 0.2}px blod`
this.ctx.textAlign = "center"
if(flag)
this.ctx.fillText(`The ${(this.data * 100).toFixed(1)}% `.this.center, this.center)
// Draw the white part of the text
this.ctx.clip() // Crop according to the path drawn
this.ctx.fillStyle = '#ffffff'
this.ctx.fillText(`The ${(this.data * 100).toFixed(1)}% `.this.center, this.center)
this.ctx.restore() // Restore the brush state, i.e., to the unclipped state
return this
}
Copy the code
The generation of points of cubic Bezier curves is not described here, and the detailed generation principle can be referred to the article “Method for Determining Control Points of Bezier Curves”.
conclusion
The drawing of the water balloon map is mainly to try the methods related to clip, save and restore, and also introduces a small skill of anti-aliasing. There is not much computation in overall drawing, and there is no interactive effect. There is only an animation effect, which can be realized by drawing animation frames with setInterval interval. It’s not too difficult overall.