I would like to share with you the effect of the picture below that I have recently implemented.
If we want to draw the animation of the curve below
If you draw a short line to connect each time, the picture below is divided into five segments.
Read ten more paragraphs
If the number of divided segments is enough, drawing one segment at a time will look like a curved trajectory.
quadratic bezier curve/** * Quadratic Bezier curve animation* @param {Array<number>} start starting point coordinates* @param {Array<number>} curvature point coordinates (that is, the turning point, not exact coordinates, just approximate direction) * @param {Array<number>} end end point coordinates * @param {number} percent drawing percentage (0-100) */ function drawCurvePath(start, point, end, percent){ ctx.beginPath(); //Start drawing lines ctx.moveTo(start[0], start[1]); //Move the pen to the starting point for (var t = 0; t <= percent / 100; t += 0.005 ) { //Get the coordinates of each time point var x = quadraticBezier(start[0], point[0], end[0], t); var y = quadraticBezier(start[1], point[1], end[1], t); ctx.lineTo(x, y); //Draw a straight line from the previous time point to the current time point} ctx.stroke(); //Stroke} /** * Quadratic Bezier curve equation* @param {Array<number>} start starting point* @param {Array<number>} curvature point* @param {Array<number>} end end point * @param {number} drawing progress (0-1) */ function quadraticBezier(p0, p1, p2, t) { var k = 1 - t; return k * k * p0 + 2 * (1 - t) * t * p1 + t * t * p2; }
For more detailed Bezier curve content, please refer to this blog
into complete code
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <meta name=viewport content=width=device-width, initial-scale=1.0> <meta http-equiv=X-UA -Compatible content=ie=edge> <title>Quadratic Bezier curve animation</title> <style> body { background: #0f1632; } #canvas { border: 1px solid #ccc; } #img { display: none; <!--Just hide the img directly, it will be quoted directly later--> } </style></head><body> <canvas id=canvas width=1500 height =750></canvas> <img id=img src=https://s3.imgsha.com/2019/04/22/light.png> <script> var ctx = document.getElementById('canvas').getContext('2d'); var img = document.getElementById('img'); var percent = 0; var data = { start: [400, 200], point: [ 300, 100], end: [100, 400], department: 'data 1', value: 4321 } function init(){ percent = 0; //Reset the process each time draw(); } function draw(){ ctx.clearRect(0, 0, 1500, 750); //Clear the canvas each time ctx.strokeStyle = '# ffffff'; //Set the line style drawCurvePath(data.start, data.point, data.end, percent); percent += 0.8; //As the process increases, this controls the animation speed if (percent <= 100) { //Continue calling if the drawing is not completed. If the drawing is completed, the progress will be reset requestAnimationFrame(draw); }else{ init() } } function drawCurvePath(start, point, end, percent) //... } function quadraticBezier( p0, p1, p2, t) { //... } </script></body></html>
The animation comes out
As mentioned before, the point
parameter in drawCurvePath(start, point, end, percent)
function is not a specific point of curvature, but a general direction.
Let’s take a look at the situation when point
is changed to [200,200]
If you want to achieve the effect of falling, you need to add a gradient effect to the line from high to low, from far to near.
/** * Create a linear gradient* @param {Array<number>} start starting point* @param {Array<number>} curvature point* @param {Array<number>} end end point* @param {number} drawing progress ( 0-1) */function createLinearGradient(start,end,startColor,endColor){ var lineGradient = ctx.createLinearGradient(...start, ...end); lineGradient.addColorStop(0, startColor); // lineGradient.addColorStop(0.3, '#fff'); lineGradient.addColorStop(1, endColor); return lineGradient}//The draw function needs some adjustments function draw(){ // ctx.strokeStyle = '#ffffff'; ctx.strokeStyle = createLinearGradient(data.start, data.end, 'rgba(255,255,255,.2)', '#fff' ); //...}
For details on canvas gradient, please refer to MDN
Head halo To add a head halo, you need to draw a circle and set a radial gradient. Use the drawCurvePath
function to get x, y and reset the position of the circle.
function createHeadLight(x,y){ ctx.beginPath(); //Create radial gradient var radialGradient = ctx.createRadialGradient(x, y, 0, x, y, 20); radialGradient.addColorStop(0, rgba(255,255,255, 1)); radialGradient.addColorStop(.2, rgba(255,255,255,.8)); radialGradient.addColorStop(1, transparent); ctx.fillStyle = radialGradient; //Draw a circle ctx.arc(x, y, 20, 0, 2 * Math .PI, false); ctx.fill();}//The drawCurvePath function needs some adjustments function drawCurvePath(start, point, end, percent){ //... ctx.stroke(); // Stroke createHeadLight(x,y) // Draw a circle just like drawing a line frequency}
For details arc
parameters for drawing circles, please refer to MDN
Adding text is very similar to adding head halo. Both use the drawCurvePath
function to obtain x, y and reset the position of the text block.
/** * Create text* @param {String} department data* @param {Number} data* @param {Number} x-axis coordinate* @param {Number} y-axis coordinate*/function drawText(department, value, x, y) { ctx.fillStyle = '#fff' ctx.font = 22px Microsoft Yahei; ctx.fillText(department, x + 30, y + 20); //In order to make the text in the lower right corner of the halo x, the y axis needs to be offset by some distance var width = ctx.measureText(value).width; //Get the width of the text ctx.fillStyle = createLinearGradient([x + 30, 0], //The rendering range of the text gradient x-axis is [x+30,x+30+text width], [x + 30 + width, 0], //Here y is set to 0 because there is no API for obtaining text height. Writing 0 is also acceptable '#fffd00', '#ff6d00' ); ctx.fillText(value.toLocaleString(), x + 30, y + 50 ); } //The drawCurvePath function needs some adjustments function drawCurvePath(start, point, end, percent, department, value) { //... createHeadLight(x,y) drawText(department, value, x, y) }Add text and pictures at the end position after the animation is completed
Please note that when adding text and pictures after the animation is completed, you need to clean the canvas immediately after the curve animation is completed, and then add text and pictures.
/** * Create picture* @param {Number} x-axis coordinate* @param {Number} y-axis coordinate*/function drawImg(x, y) { ctx.drawImage(img, x - img.width / 2, y - img.height); }//The draw function needs some adjustments draw(){ //... if (percent <= 100) { requestAnimationFrame(draw); }else{ ctx.clearRect(0, 0, 1500, 750); //Clear the canvas immediately after the curve animation is completed drawText(data.department, //Render text data.value, data.end[0], data.end[1 ]) drawImg(data.end[0], data.end[1]) //Render the image setTimeout(function(){ //Redraw init() after 2000ms },2000) } }Finish
The complete code of this example
The complete code of the example in the first picture of the article
Reference article: Use canvas to draw a curve animation - in-depth understanding of Bezier curves
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.