用画布绘制流畅的线条

问题描述 投票:0回答:3

到目前为止,平滑线上的所有螺纹均不正确。

如何使用javascript HTML5 canvas 通过N个点绘制平滑曲线?

在画布上平滑用户绘制的线条

两者都会产生锯齿状线条。我所说的平滑是指使用 x,y 点作为控制点来使线条平滑。该线不需要穿过这些点。它只需要在给定 n 个点的情况下画一条平滑的线。

基本上我正在记录每个线段,然后当用户向上移动鼠标时,它会平滑该线。

我已经尝试使用 bezierCurveTo 自己的方法,但这只能平滑所有其他点,然后连接点仍然很粗糙。互联网似乎认为我正在寻找的东西称为 B 样条曲线。我尝试应用线性代数矩阵来解决这个问题,但我失败了,哈哈。

这是我能得到的最佳曲线(图片)。红色线是“平滑”线,您可以看到它平滑了所有其他点,但不连续。这是使用来自

的代码

如何使用javascript HTML5 canvas 通过N个点绘制平滑曲线?

我的代码做了同样的事情

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

感谢您的帮助!

javascript canvas drawing bezier smoothing
3个回答
4
投票

您需要在线下面的点中保持相同的切线。检查http://jsfiddle.net/FHKuf/4/

编辑:

抱歉,今天才注意到您的评论。刚好在测试相关的东西并记住了你的问题。碰巧我过去确实写了一些代码来插入一些行。它被称为Catmull-Rom(只是我用谷歌搜索到的一个参考),它经过中间的控制点。我确实将代码更改为我的测试,并认为您可能会对它有所用处。请参阅 http://jsfiddle.net/FHKuf/6/


1
投票

我正在探索所有技术,但没有找到任何在画布上平滑自由绘图的适当解决方案。然后我简单地使用了具有不同逻辑的quadraticCurveTo,而不使用原始的鼠标点。

我首先计算控制点(中点)并用控制点替换旧的鼠标移动点。我这样做了两次,最后将quadraticCurveTo应用于最终的数组,我得到了超级平滑的绘图。

太棒了。我在没有使用这个沉重的 paper.js 和其他平滑库的情况下做到了。

这是我的代码:

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 = [];

0
投票

@Manoj Verma 使用线点作为控制点是个好主意!我对你的代码做了一些改进。线条仍然很流畅,没有不必要的操作。我还修复了绘图错误直到最后一点

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

        let x, y

        for (let i = 0; i < queue.length - 1; i++) {
            x = (queue[i].x + queue[i + 1].x) / 2;
            y = (queue[i].y + queue[i + 1].y) / 2;
            currentCanvas.quadraticCurveTo(queue[i].x, queue[i].y, x, y);
        }
        const lastPoint = queue[queue.length - 1]

        currentCanvas.quadraticCurveTo(lastPoint.x, lastPoint.y, lastPoint.x, lastPoint.y)

        currentCanvas.stroke();

© www.soinside.com 2019 - 2024. All rights reserved.