So as some of you might already know, I’m experimenting a bit with SVG lately. Especially the part of procedural generated SVG I find very interesting.
One aspect of drawing in SVG is generating smooth lines through several points. You can simply draw bezier curves to get smooth lines, but how do you know where to put the anchor points? In this article I’ll show you how I manage to draw a smooth bezier line to several points with basic math.
The setup
The first thing to do of course, is plot some random points on your canvas. Something like this:
Placing some random points is fairly simple, I simply used a for -loop to get the job done:
1 2 3 4 5 |
$steps = 10; $points = array(); for ($i = 0; $i <= $steps; $i += 1) { $points[] = array('x' => $i * 60, 'y' => rand(0, 200)); } |
To visualise the line we want to smooth, I also drawn some lines from point to point:
Calculate the angle of your curves
To smoothen my lines, I want to know what angle I need to set my bezier curves to. To do this, I need to calculate an imaginary line from point to
and calculate it’s angle. Let’s visualise this imaginary line:
To calculate it’s angle we can simply calculate it’s normals:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Get the direction of the line $dirX = $points[$i + 2]['x'] - $points[$i]['x']; $dirY = $points[$i + 2]['y'] - $points[$i]['y']; // Get the distance of the line: $distance = sqrt(pow($dirX, 2) + pow($dirY, 2)); // Get it's unit vector: $unitX = $dirX / $distance; $unitY = $dirY / $distance; // Get it's normals: $normal1 = array('x' => -$unitY, 'y' => $unitX); $normal2 = array('x' => $unitY, 'y' => -$unitX); // Finally, get the angle for the anchor points: $angle1 = atan2($normal1['y'], $normal1['x']) + pi() / 2; $angle2 = atan2($normal2['y'], $normal2['x']) + pi() / 2; |
Now we’ve got the angles we can create the anchor points. There is just one question left: Just how long should these anchor points be? To tackle this problem, I set the distance of the anchor points to a portion of the length of the imaginary line. I found that a rough estimate of 20% looks quite smooth:
1 2 3 4 5 6 7 8 |
$anchor1 = array( 'x' => $points[$i + 1]['x'] + cos($angle1) * ($distance / 5), 'y' => $points[$i + 1]['y'] + sin($angle1) * ($distance / 5) ); $anchor2 = array( 'x' => $points[$i + 1]['x'] + cos($angle2) * ($distance / 5), 'y' => $points[$i + 1]['y'] + sin($angle2) * ($distance / 5) ); |
So let’s have a look at our anchor points:
The result
Now we have all this precious data, the steps towards creating a smooth line that runs through all the points are simple. And to put proof by the word, here is the resulting image if I add it all up:
Needless to say: although this example is written in PHP, the Math of course applies to any other given language out there.
Visitors give this article an average rating of 4.4 out of 5.
How would you rate this article?
★ ★ ★ ★ ★
Hi Giel
I’m trying out this example, but i don’t get it to work correctly. Would it be possible to add the whole script, that I can have a look at it and maybe debug my problem. I tried to do it in JavaScript. https://jsfiddle.net/Lg965kqc/3/
Thanks
Thanks for this article, which put me on the path. I did it in javascript here: https://codepen.io/francoisromain/pen/XabdZm