Reputation: 11035
How can I have a line be two different sizes with canvas?
I have a line I am drawing with canvas
that I would like to start out with a width of 30
and gradually(proportionally) reduce down to a size of 15
, so that it reaches 15 right at the end of the line.
I though that perhaps if I set context.lineWidth
in two places (start and end) it would work.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(100, 150);
context.lineWidth = 30;
context.lineTo(450, 50);
context.lineWidth = 15;
context.stroke();
</script>
</body>
</html>
Upvotes: 2
Views: 207
Reputation: 19294
I once wondered about building such a variable-width line, and i ended building my own solution, and wrote a blog post out of it.
I'll copy the first part of it here, the rounded version can also be found here :
https://gamealchemist.wordpress.com/2013/08/28/variable-width-lines-in-html5-canvas/
Variable width lines in html5
Drawing such a [variable width] line is quite easy once we realize that what we need to draw is not a line : in fact it is a polygon.
If the line segment we want to draw is (A,B), the situation looks like this :
What we want to draw in fact is the A1,A2,B2,B1 polygon.
If we call N the normal vector (drawn on the scheme), and w1 and w2 the width in A and B respectively, we have :
A1 = A + N * w1/2
A2 = A – N * w1/2
B1 = B + N * w2/2
B2 = B – N * w2/2
So how do we find this normal vector N ?
Maths says that if (x,y) defines a vector V , its normal vector coordinates are (-y, x).
N, the vector normal to AB will hence have ( – ( yB – yA ) , ( xB – xA ) ) as coordinates.
But there is an annoying thing about this vector : it depends on AB length, which is not
what we want : we need to normalize this vector, i.e. have it to a standard length of 1, so when we later multiply this vector by w1/2, we get the right length vector added.
Vector normalisation is done by dividing the x and y of the vector by the vector length. Since the length is found using phytagore’s theorem, that makes 2 squares, one square root, and finally 2 divides to find the normalized vector N :
// computing the normalized vector normal to AB
length = Math.sqrt( sq (xB-xA) + sq (yB - yA) ) ;
Nx = - (yB - yA) / length ;
Ny = (xB - xA) / length ;
So now that we can compute the four points, let us link them by a poly-line, and fill the resulting shape : here comes our variable width segment !
Here is the javascript code :
// varLine : draws a line from A(x1,y1) to B(x2,y2)
// that starts with a w1 width and ends with a w2 width.
// relies on fillStyle for its color.
// ctx is a valid canvas's context2d.
function varLine(ctx, x1, y1, x2, y2, w1, w2) {
var dx = (x2 - x1);
var dy = (y2 - y1);
w1 /= 2; w2 /= 2; // we only use w1/2 and w2/2 for computations.
// length of the AB vector
var length = Math.sqrt(sq(dx) + sq(dy));
if (!length) return; // exit if zero length
dx /= length ; dy /= length ;
var shiftx = - dy * w1 // compute AA1 vector's x
var shifty = dx * w1 // compute AA1 vector's y
ctx.beginPath();
ctx.moveTo(x1 + shiftx, y1 + shifty);
ctx.lineTo(x1 - shiftx, y1 - shifty); // draw A1A2
shiftx = - dy * w2 ; // compute BB1 vector's x
shifty = dx * w2 ; // compute BB1 vector's y
ctx.lineTo(x2 - shiftx, y2 - shifty); // draw A2B1
ctx.lineTo(x2 + shiftx, y2 + shifty); // draw B1B2
ctx.closePath(); // draw B2A1
ctx.fill();
}
So let us see the result on a small example : drawing variable width segments within a circle with nice hsl colors :
(About @MarkE's (interesting) remark on chaining line segments, i fear this is a quite difficult goal, since there are many specific cases depending on line length/ w1 /w2 / angle in between segments. I quite solved it using force fields and marching cubes, but i fear this is completely off-topic !! :-) )
Upvotes: 4