SVG流畅的徒手绘图

时间:2016-10-29 22:29:01

标签: javascript svg

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

这是我的代码:

$property->save(); // as default

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

enter image description here enter image description here

2 个答案:

答案 0 :(得分:15)

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

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



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);
    }
};
&#13;
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;
}
&#13;
<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">
&#13;
&#13;
&#13;

答案 1 :(得分:0)

在github上已有一些实现,例如https://github.com/epistemex/cardinal-spline-js

您不必为此输入更改任何内容,只能更改绘图功能,点之间的线条是平滑的。因此,在简化过程中,这些要点不会滑动。