我想在画布上用鼠标绘制SVG路径。 我不希望像rapheal.js这样的库来绘制形状,我想要纯粹的JS。
我已经创造了JS:
var svgCanvas = document.getElementById("svgCanvas");
var svgPath;
svgCanvas.addEventListener("touchstart", startDrawTouch, false);
svgCanvas.addEventListener("touchmove", continueDrawTouch, false);
svgCanvas.addEventListener("touchend", endDrawTouch, false);
function startDrawTouch(event)
{
var touch = event.changedTouches[0];
svgPath = createSvgElement("path");
svgPath.setAttribute("fill", "none");
svgPath.setAttribute("shape-rendering", "geometricPrecision");
svgPath.setAttribute("stroke-linejoin", "round");
svgPath.setAttribute("stroke", "#000000");
svgPath.setAttribute("d", "M" + touch.clientX + "," + touch.clientY);
svgCanvas.appendChild(svgPath);
}
function continueDrawTouch(event)
{
if (svgPath)
{
var touch = event.changedTouches[0];
var pathData = svgPath.getAttribute("d");
pathData = pathData + " L" + touch.clientX + "," + touch.clientY
svgPath.setAttribute("d", pathData);
}
}
function endDrawTouch(event)
{
if (svgPath)
{
var pathData = svgPath.getAttribute("d");
var touch = event.changedTouches[0];
pathData = pathData + " L" + touch.clientX + "," + touch.clientY
svgPath.setAttribute("d", pathData);
svgPath = null;
}
}
function createSvgElement(tagName)
{
return document.createElementNS("http://www.w3.org/2000/svg", tagName);
}
这需要时间在平板电脑上绘制路径。遇到性能问题,万一你有更好的想法请分享。
提前致谢。
答案 0 :(得分:2)
您正在重构每个continueDrawTouch调用中的path元素。这意味着将它从内部表示转换为字符串,然后附加到字符串并再次将其转换回来。
如果你避免这种情况并使用SVG DOM,那么大多数浏览器(例如某些版本的Firefox)会更高效。代码将成为:
if (svgPath)
{
var touch = event.changedTouches[0];
var newSegment = svgPath.createSVGPathSegLinetoAbs(touch.clientX, touch.clientY);
svgPath.pathSegList.appendItem(newSegment);
}
相同的注释适用于endDrawTouch函数。
答案 1 :(得分:1)
也许您可以尝试<polyline>
及其.points
属性,并且可以为您提供更好的效果。未经测试的代码修改:
var svgCanvas = document.getElementById("svgCanvas");
var svgPolyline;
svgCanvas.addEventListener("touchstart", startDrawTouch, false);
svgCanvas.addEventListener("touchmove", continueDrawTouch, false);
svgCanvas.addEventListener("touchend", endDrawTouch, false);
function startDrawTouch(event)
{
var touch = event.changedTouches[0];
svgPolyline = createSvgElement("polyline");
svgPolyline.setAttribute("fill", "none");
svgPolyline.setAttribute("shape-rendering", "geometricPrecision");
svgPolyline.setAttribute("stroke-linejoin", "round");
svgPolyline.setAttribute("stroke", "#000000");
svgCanvas.appendChild(svgPolyline);
continueDrawTouch(event);
}
function continueDrawTouch(event)
{
if (svgPolyline)
{
var touch = event.changedTouches[0];
var point = svgPolyline.ownerSVGElement.createSVGPoint();
point.x = touch.clientX;
point.y = touch.clientY;
var ctm = event.target.getScreenCTM();
if (ctm = ctm.inverse())
{
point = point.matrixTransform(ctm);
}
svgPolyline.points.appendItem(point);
}
}
function endDrawTouch(event)
{
continueDrawTouch(event);
svgPolyline = null;
}
function createSvgElement(tagName)
{
return document.createElementNS("http://www.w3.org/2000/svg", tagName);
}
编辑 .clientX/Y
不一定能为您提供所需的坐标,具体取决于文档的结构,滚动或转换。因此,我在another question (但使用相关联。方法名.screenX/Y
的情况下编辑了代码,这应该更适合与.getScreenCTM
).getScreenCTM()
给我带来了一些困惑。 .clientX/Y
确实是需要的,see the specs。