7
votes

So far none of the threads here on smooth lines are correct.

how to draw smooth curve through N points using javascript HTML5 canvas?

Smooth user drawn lines in canvas

Both result in jagged lines. By smooth I mean using the x,y points as control points to make the line smooth. The line does NOT need to go through the points. It simply has to draw a smooth line given n points.

Basically I'm recording each line segment, then when the user mouses up, it wil smooth the line.

I've tried my own method using bezierCurveTo but that only smooths every other point, and then the connecting points are harsh still. The internet seems to think what I'm looking for is called B-Spline curves. I tried applying a linear algebra matrix to the problem, but I failed at that lol.

Here is the best curve I can get, (image). The line in red is the "smoothed" line, as you can see it smooths every other point, but not continuous. This is using the code from

how to draw smooth curve through N points using javascript HTML5 canvas?

My code does the same thing

http://www.square-bracket.com/images/smoothlines.png

Thanks for your help!

2

2 Answers

3
votes

You need to keep the same tangent in the points bellowing in the line. Check http://jsfiddle.net/FHKuf/4/.

Edit:

Sorry, just noticed your comment today. Just happened to be testing something related and remembered your question. It happens that in the past I did wrote some code to interpolate some lines. It is called Catmull-Rom(just a ref. that I googleed) it passes by the middle control points. I did changed the code to my test and thought that you may have some use to it. See at http://jsfiddle.net/FHKuf/6/.

1
votes

I was exploring all techniques but did not get any proper solution for smooth free drawing on canvas. Then I simply used quadraticCurveTo with different logic without using original mouse points.

I first calculated control point(mid-point) and replace old mouse move point with the control point. I did this 2 times and finally applied quadraticCurveTo to the final array and I got super smooth drawing.

It was amazing. I did it without using this heavy paper.js and other smoothing libraries.

Here is my code:

currentCanvas.beginPath();
        currentCanvas.lineCap = 'round';
        currentCanvas.strokeStyle = "black";
        currentCanvas.lineWidth = "2";
        currentCanvas.moveTo(queue[0].x, queue[0].y);

        //queue is an array of original points which were stored while onmousemove event callback

        var tempQueue1 = [queue[0]];
        for (var i = 1; i < queue.length - 1;  i = i+1) {
            //if((Math.abs(queue[i].x - queue[i-1].x) >3 || Math.abs(queue[i].x - queue[i-1].x)<1) &&  (Math.abs(queue[i].y - queue[i-1].y) >3 || Math.abs(queue[i].y - queue[i-1].y)<1)){
                var c = (queue[i].x + queue[i + 1].x) / 2;
                var d = (queue[i].y + queue[i + 1].y) / 2;
                //tempQueue.push(queue[i]);
                tempQueue1.push({x:c, y:d});
                //currentCanvas.quadraticCurveTo(queue[i].x, queue[i].y, c, d);
            //}
        }

        var tempQueue2 = [tempQueue1[0]];
        for (var i = 1; i < tempQueue1.length - 1;  i = i+1) {
            //if((Math.abs(queue[i].x - queue[i-1].x) >3 || Math.abs(queue[i].x - queue[i-1].x)<1) &&  (Math.abs(queue[i].y - queue[i-1].y) >3 || Math.abs(queue[i].y - queue[i-1].y)<1)){
                var c = (tempQueue1[i].x + tempQueue1[i + 1].x) / 2;
                var d = (tempQueue1[i].y + tempQueue1[i + 1].y) / 2;
                //tempQueue.push(queue[i]);
                tempQueue2.push({x:c, y:d});
                //currentCanvas.quadraticCurveTo(queue[i].x, queue[i].y, c, d);
            //}
        }

        var tempQueue = [tempQueue2[0]];
        for (var i = 1; i < tempQueue2.length - 1;  i = i+1) {
            //if((Math.abs(queue[i].x - queue[i-1].x) >3 || Math.abs(queue[i].x - queue[i-1].x)<1) &&  (Math.abs(queue[i].y - queue[i-1].y) >3 || Math.abs(queue[i].y - queue[i-1].y)<1)){
                var c = (tempQueue2[i].x + tempQueue2[i + 1].x) / 2;
                var d = (tempQueue2[i].y + tempQueue2[i + 1].y) / 2;
                //tempQueue.push(queue[i]);
                tempQueue.push({x:c, y:d});
                //currentCanvas.quadraticCurveTo(queue[i].x, queue[i].y, c, d);
            //}
        }

        for (var i = 1; i < tempQueue.length - 2;  i = i+1) {
            //if((Math.abs(queue[i].x - queue[i-1].x) >3 || Math.abs(queue[i].x - queue[i-1].x)<1) &&  (Math.abs(queue[i].y - queue[i-1].y) >3 || Math.abs(queue[i].y - queue[i-1].y)<1)){
                var c = (tempQueue[i].x + tempQueue[i + 1].x) / 2;
                var d = (tempQueue[i].y + tempQueue[i + 1].y) / 2;
                currentCanvas.quadraticCurveTo(tempQueue[i].x, tempQueue[i].y, c, d);
            //}
        }

        // For the last 2 points
        currentCanvas.quadraticCurveTo(
        tempQueue[i].x,
        tempQueue[i].y,
        tempQueue[i+1].x,
        tempQueue[i+1].y
        );
        currentCanvas.stroke();
        queue = [];