简体   繁体   English

SVG流畅的徒手绘图

[英]SVG smooth freehand drawing

I implemented a freehand drawing of a path using native JS. 我使用原生JS实现了一个路径的徒手画。 But as expected path edges are little aggressive and not smooth. 但正如预期的那样,路径边缘不那么具有攻击性且不平滑 So I have an option of using simplifyJS to simplify points and then redraw path. 所以我可以选择使用simplifyJS来简化点然后重绘路径。 But like here , instead of smoothening after drawing, I am trying to find simplified edges while drawing 但就像这里一样,我不是在绘图后平滑,而是试图在绘图时找到简化的边缘

Here is my code: 这是我的代码:

    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);
    };

But it is not working as in the link added above. 但它不像上面添加的链接那样工作。 Still edges are not good. 仍然边缘不好。 Please help. 请帮忙。

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

The following code snippet makes the curve smoother by calculating the average of the last mouse positions. 以下代码片段通过计算最后鼠标位置的平均值使曲线更平滑。 The level of smoothing depends on the size of the buffer in which these values are kept. 平滑程度取决于保持这些值的缓冲区的大小。 You can experiment with the different buffer sizes offered in the dropdown list. 您可以尝试下拉列表中提供的不同缓冲区大小。 The behavior with a 12 point buffer is somewhat similar to the Mike Bostock's code snippet that you refer to in the question. 使用12点缓冲区的行为有点类似于您在问题中引用的Mike Bostock的代码片段

More sophisticated techniques could be implemented to get the smoothed point from the positions stored in the buffer (weighted average, linear regression, cubic spline smoothing, etc.) but this simple average method may be sufficiently accurate for your needs. 可以实现更复杂的技术以从缓冲区中存储的位置获得平滑点(加权平均,线性回归,三次样条平滑等),但是这种简单的平均方法可以足够精确地满足您的需要。

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

There are already some implementations for this on github eg https://github.com/epistemex/cardinal-spline-js 在github上已有一些实现,例如https://github.com/epistemex/cardinal-spline-js

You dont have to change anything on your input for that and can only change the draw function, that the line between the points is smooth. 您不必为此输入更改任何内容,只能更改绘图功能,点之间的线条是平滑的。 With that the points dont slip a bit during the simplification. 因此,在简化过程中,这些点不会滑动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM