This is the sixth day of my participation in the More text Challenge. For details, see more text Challenge
preface
Bessel curves are everywhere in our daily development:
- Curves in SVG (level 2, Level 3 support)
- Draw bezier curves on canvas
- Bezier curves are used in almost all front-end 2D or 3D graph libraries (Echarts, D3, three.js)
So the bezier curve is a must-have. This article is mainly for practical use, and will not introduce the knowledge related to Bezier. If you are not very clear about Bezier curves, you can check out my article – In-depth understanding of SVG
Draw a Bezier curve
The first step is to create a second order Bezier curve with CTX. The second order Bessel curve has one control point, one starting point and one ending point.
const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = '# 000';
ctx.moveTo(100.100)
ctx.quadraticCurveTo(180.50.200.200)
ctx.stroke();
Copy the code
So we have a Bezier curve.
Draw bezier curve animation
Who wouldn’t draw a line? Next comes the body of the article. So first of all if you think about animation we must be drawing a curve step by step, right? But is there a problem with this CTX drawing us all. Let’s take a look at the second order Bezier curve implementation animation and see if we have any ideas.
We can see from the graph that the bezier curve is related to T, and t is between 0 and 1. Can we use the second order Bezier curve equation to figure out each point? The technical term is discretization, but this is not accurate, so let’s do it this way.
Let’s look at the equation:
We simulate the code as follows:
// This is the second order Bezier curve equation
function twoBezizer(p0, p1, p2, t) {
const k = 1 - t
return k * k * p0 + 2 * (1 - t) * t * p1 + t * t * p2
}
/ / the discrete
function drawWithDiscrete(ctx, start, control, end,percent) {
for ( let t = 0; t <= percent / 100; t += 0.01 ) {
const x = twoBezizer(start[0], control[0], end[0], t)
const y = twoBezizer(start[1], control[1], end[1], t)
ctx.lineTo(x, y)
}
}
Copy the code
Let’s look at the effect:
It’s almost exactly the same as what we drew. We’ll start our animation with a requestAnimationFrame and give you the following code:
let percent = 0
function animate() {
ctx.clearRect( 0.0.800.800 );
ctx.beginPath();
ctx.moveTo(100.100)
drawWithDiscrete(ctx,[100.100], [180.50], [200.200],percent)
ctx.stroke();
percent = ( percent + 1 ) % 100;
id = requestAnimationFrame(animate)
}
animate()
Copy the code
The two things to notice here is that I’m incrementing percent by 1 and 100, so percent keeps going back and forth from 1 to 100, OK so we have to do a sub-region cleanup before animation, ctx.clearRect(0, 0, 800, 800); So we can go back and forth from start to finish, and here’s the effect:
Doesn’t it look good hahaha 😸.
Draw bezier curve animation method 2
You think that’s the end of it? Of course not is there really no way we can draw a Bezier curve for a particular T? Currently not, here is the derivation of the second order Bessel equation:
At any point on the second order Bessel curve, you can get the same ratio. At any point between these two points, it satisfies a first order Bessel curve, a first order Bessel curve satisfies a linear change. Let me give you the following equation
function oneBezizer(p0,p1,t) {
return p0 + (p1-p0) * t
}
Copy the code
And as you can see from the graph THAT I’ve drawn, we just have to keep finding A and C to draw bezier at some point in time.
Here’s the code and the renderings:
function drawWithDiscrete2(ctx, start, control, end,percent) {
const t = percent/ 100;
// Find point A
const A = [];
const C = [];
A[0] = oneBezizer(start[0],control[0],t);
A[1] = oneBezizer(start[1],control[1],t);
C[0] = twoBezizer(start[0], control[0], end[0], t)
C[1] = twoBezizer(start[1], control[1], end[1], t)
ctx.quadraticCurveTo(
A[ 0 ], A [ 1 ],
C[ 0 ], C[ 1]); }Copy the code
Fireworks 🎉 animation
Above, we realized a Bezier line. We took the starting point of this Bezier curve as the center of a circle, and then calculated different ending points according to a certain degree. I’m going to do a random color, and I’m going to have a fireworks effect, and I’m going to code it,
for(let i=0; i<count; i++) {
const angle = Math.PI * 2 / count * i;
const x = center[ 0 ] + radius * Math.sin( angle );
const y = center[ 1 ] + radius * Math.cos( angle );
ctx.strokeStyle = colors[ i ];
ctx.beginPath();
drawWithDiscrete(ctx, center,[180.50],[x,y],percent)
ctx.stroke();
}
function getRandomColor(colors, count) {
// Generate random colors
for ( let i = 0; i < count; i++ ) {
colors.push(
'rgb( ' +
( Math.random() * 255 >> 0 ) + ', ' +
( Math.random() * 255 >> 0 ) + ', ' +
( Math.random() * 255 >> 0 ) +
' )'); }}Copy the code
Let’s take a look at the animation:
At the end
That’s the end of this article. If it helps you, please click 👍 and follow. Your support is the biggest motivation for me to keep updating. All the code is on my Github. Finally I wish you a happy Dragon Boat Festival!