我使用原生JS实现了一个路径的徒手画。但正如预期的那样,路径边缘不那么具有攻击性且不平滑所以我可以选择使用simplifyJS来简化点然后重绘路径。但是像here一样,我不是在绘图后平滑,而是在绘制时尝试找到简化的边缘
这是我的代码:
$property->save(); // as default
但它不像上面添加的链接那样工作。仍然边缘不好。请帮忙。
答案 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;
答案 1 :(得分:0)
在github上已有一些实现,例如https://github.com/epistemex/cardinal-spline-js
您不必为此输入更改任何内容,只能更改绘图功能,点之间的线条是平滑的。因此,在简化过程中,这些要点不会滑动。