Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing lines with continuously varying line width on HTML canvas

I'm trying to draw a line that starts as a thin line and then gadually widens until the end. I need to draw semi-smooth curves (composite out of several straight lines) and I'm having problems finding a way to solve this task.

This fiddle shows my problem:

http://jsfiddle.net/ZvuQG/1/

When you call stroke(), the currently set lineWidth is used to stroke the entire line. My first thought was to draw each line piece individually, but of course, this leaves noticeable gaps in the line at the corners.

What is my best option here? Should I resort to drawing polygons (trapezoids) to get the corners right?

Is there an easier way?

(Edit: Note that I am not trying to actually draw ellipses or any other basic shapes; I'm trying to plot mathematical functions, using line thickness to represent velocity)

like image 843
Valdemar Avatar asked Oct 11 '12 16:10

Valdemar


People also ask

How do I draw a line on a canvas in HTML?

To draw a line on a canvas, you use the following steps: First, create a new line by calling the beginPath() method. Second, move the drawing cursor to the point (x,y) without drawing a line by calling the moveTo(x, y) . Finally, draw a line from the previous point to the point (x,y) by calling the lineTo(x,y) method.

How do you make a line width in HTML?

HTML | <hr> width Attribute The HTML <hr> width attribute is used to specify the width of the horizontal line in terms of pixels or percent. Attribute Values: pixels: It sets the width of <hr> attribute in terms of pixels. %: It sets the width of <hr> attribute in terms of percentage (%).

Which two methods are used to draw straight lines on a canvas?

There are the following methods to draw a straight line on the canvas. beginPath(): This method is used to begin the path that we are going to draw. It does not take any arguments. moveTo(): This method takes two arguments which will be the starting point of any path.

How do I change the width and height of a dynamic canvas?

To do it, simply set the width and height properties of the Canvas object, and then redraw the canvas contents: Canvas . width = 600 ; Canvas . height = 500 ; drawScreen ();


1 Answers

For those interested, I have come up with two solutions to my problem.

The first idea was to actually draw each point as a corner, using canvas to draw a neat angle. A demo can be seen at:

http://jsfiddle.net/7BkyK/2/

var ctx = document.getElementById('canvas1').getContext('2d');
var points = [null, null, null];

for(var i=0; i<24; i++)
{
    var width = 0.5 + i/2;

    var m = 200;

    var x = Math.cos(i/4) * 180;
    var y = Math.sin(i/4) * 140;

    points[0] = points[1];
    points[1] = points[2];
    points[2] = { X:x, Y:y};

    if(points[0] == null)
        continue;

    var px0 = (points[0].X + points[1].X) / 2;
    var py0 = (points[0].Y + points[1].Y) / 2;

    var px1 = (points[1].X + points[2].X) / 2;
    var py1 = (points[1].Y + points[2].Y) / 2;

    ctx.beginPath();
    ctx.lineWidth = width;
    ctx.strokeStyle = "rgba(0,0,0,0.5)";
    ctx.moveTo(m+px0,m+py0);
    ctx.lineTo(m+points[1].X,m+points[1].Y);
    ctx.lineTo(m+px1,m+py1);
    ctx.stroke();
}
​

The second and much prettier solution, as suggested by Shmiddty, is to use bezier curves. This proved to be a great solution:

http://jsfiddle.net/Ssrv9/1/

// 1.
// Varying line width, stroking each piece of line separately
var ctx = document.getElementById('canvas1').getContext('2d');
var points = [null, null, null, null];

for(var i=-1; i<25; i = i +1)
{
    var width = 0.5 + i/2;

    var m = 200;


    var x = Math.cos(i/4) * 180;
    var y = Math.sin(i/4) * 140;

    points[0] = points[1];
    points[1] = points[2];
    points[2] = { X:x, Y:y};

    if(points[0] == null)
        continue;


    var p0 = points[0];
    var p1 = points[1];
    var p2 = points[2];

    var x0 = (p0.X + p1.X) / 2;
    var y0 = (p0.Y + p1.Y) / 2;

    var x1 = (p1.X + p2.X) / 2;
    var y1 = (p1.Y + p2.Y) / 2;

    ctx.beginPath();
    ctx.lineWidth = width;
    ctx.strokeStyle = "black";

    ctx.moveTo(m+x0, m+y0);
    ctx.quadraticCurveTo(m+p1.X, m+p1.Y, m+x1, m+y1);
    ctx.stroke();
}

like image 131
Valdemar Avatar answered Sep 22 '22 11:09

Valdemar