SVG流畅的徒手绘图

Exc*_*ion 9 javascript svg

我使用原生JS实现了一个路径的徒手画.但正如预期的那样,路径边缘不那么具有攻击性且不平滑 所以我可以选择使用simplifyJS来简化点然后重绘路径.但就像这里一样,我不是在绘图后平滑,而是试图在绘图时找到简化的边缘

这是我的代码:

    var x0, y0;

    var dragstart = function(event) {
        var that = this;
        var pos = coordinates(event);
        x0 = pos.x;
        y0 = pos.y;
        that.points = [];
    };

    var dragging = function(event) {
        var that = this;
        var xy = coordinates(event);
        var points = that.points;
        var x1 = xy.x, y1 = xy.y, dx = x1 - x0, dy = y1 - y0;
        if (dx * dx + dy * dy > 100) {
            xy = {
                x: x0 = x1, 
                y: y0 = y1
            };
        } else {
            xy = {
                x: x1, 
                y: y1
            };
        }
        points.push(xy);
    };
Run Code Online (Sandbox Code Playgroud)

但它不像上面添加的链接那样工作.仍然边缘不好.请帮忙.

在此输入图像描述 在此输入图像描述

Con*_*Fan 18

以下代码片段通过计算最后鼠标位置的平均值使曲线更平滑.平滑程度取决于保持这些值的缓冲区的大小.您可以尝试下拉列表中提供的不同缓冲区大小.使用12点缓冲区的行为有点类似于您在问题中引用的Mike Bostock的代码片段.

可以实现更复杂的技术以从缓冲区中存储的位置获得平滑点(加权平均,线性回归,三次样条平滑等),但是这种简单的平均方法可以足够精确地满足您的需要.

var strokeWidth = 2;
var bufferSize;

var svgElement = document.getElementById("svgElement");
var rect = svgElement.getBoundingClientRect();
var path = null;
var strPath;
var buffer = []; // Contains the last positions of the mouse cursor

svgElement.addEventListener("mousedown", function (e) {
    bufferSize = document.getElementById("cmbBufferSize").value;
    path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttribute("fill", "none");
    path.setAttribute("stroke", "#000");
    path.setAttribute("stroke-width", strokeWidth);
    buffer = [];
    var pt = getMousePosition(e);
    appendToBuffer(pt);
    strPath = "M" + pt.x + " " + pt.y;
    path.setAttribute("d", strPath);
    svgElement.appendChild(path);
});

svgElement.addEventListener("mousemove", function (e) {
    if (path) {
        appendToBuffer(getMousePosition(e));
        updateSvgPath();
    }
});

svgElement.addEventListener("mouseup", function () {
    if (path) {
        path = null;
    }
});

var getMousePosition = function (e) {
    return {
        x: e.pageX - rect.left,
        y: e.pageY - rect.top
    }
};

var appendToBuffer = function (pt) {
    buffer.push(pt);
    while (buffer.length > bufferSize) {
        buffer.shift();
    }
};

// Calculate the average point, starting at offset in the buffer
var getAveragePoint = function (offset) {
    var len = buffer.length;
    if (len % 2 === 1 || len >= bufferSize) {
        var totalX = 0;
        var totalY = 0;
        var pt, i;
        var count = 0;
        for (i = offset; i < len; i++) {
            count++;
            pt = buffer[i];
            totalX += pt.x;
            totalY += pt.y;
        }
        return {
            x: totalX / count,
            y: totalY / count
        }
    }
    return null;
};

var updateSvgPath = function () {
    var pt = getAveragePoint(0);

    if (pt) {
        // Get the smoothed part of the path that will not change
        strPath += " L" + pt.x + " " + pt.y;

        // Get the last part of the path (close to the current mouse position)
        // This part will change if the mouse moves again
        var tmpPath = "";
        for (var offset = 2; offset < buffer.length; offset += 2) {
            pt = getAveragePoint(offset);
            tmpPath += " L" + pt.x + " " + pt.y;
        }

        // Set the complete current path coordinates
        path.setAttribute("d", strPath + tmpPath);
    }
};
Run Code Online (Sandbox Code Playgroud)
html, body
{
    padding: 0px;
    margin: 0px;
}
#svgElement
{
    border: 1px solid;
    margin-top: 4px;
    margin-left: 4px;
    cursor: default;
}
#divSmoothingFactor
{
    position: absolute;
    left: 14px;
    top: 12px;
}
Run Code Online (Sandbox Code Playgroud)
<div id="divSmoothingFactor">
    <label for="cmbBufferSize">Buffer size:</label>
    <select id="cmbBufferSize">
        <option value="1">1 - No smoothing</option>
        <option value="4">4 - Sharp curves</option>
        <option value="8" selected="selected">8 - Smooth curves</option>
        <option value="12">12 - Very smooth curves</option>
        <option value="16">16 - Super smooth curves</option>
        <option value="20">20 - Hyper smooth curves</option>
    </select>
</div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="svgElement" x="0px" y="0px" width="600px" height="400px" viewBox="0 0 600 400" enable-background="new 0 0 600 400" xml:space="preserve">
Run Code Online (Sandbox Code Playgroud)

  • 这是一个如此惊人的答案! (6认同)
  • @ConnorsFan 非常酷的例子。我使用您的代码在 svelte 3 中创建了一个 svg 行编辑器:https://v3.svelte.technology/repl?version=3.0.0-alpha16&amp;gist=f665ec6ed549fb35ac2f9878a5c9e1c7 (2认同)