用鼠标绘制SVG路径

4
我希望在画布上使用鼠标绘制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);
}

这需要在平板上花费时间来绘制路径。由于性能问题,如果您有更好的想法,请分享。

提前感谢。

2个回答

2

在每个continueDrawTouch调用中,您正在重构路径元素。这意味着将其从内部表示转换为字符串,然后将其附加到字符串并再次转换。

大多数浏览器(例如Firefox)如果避免这种操作并使用SVG DOM,性能会更好。代码将变为:

if (svgPath)
{
    var touch = event.changedTouches[0];
    var newSegment = svgPath.createSVGPathSegLinetoAbs(touch.clientX, touch.clientY);
    svgPath.pathSegList.appendItem(newSegment);
}

同样的评论也适用于endDrawTouch函数。

谢谢回复。我会尝试并告诉你。 - Narando
我发现,在Android默认浏览器中,svgPath.createSVGPathSegLinetoAbs无法正常工作。:( - Narando

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根据文档的结构、滚动或变换可能不会给出您想要的坐标。因此,我从另一个问题中获得了一些灵感,并编辑了代码(但使用.screenX/Y,这应该更适合与.getScreenCTM一起使用)。方法名.getScreenCTM()让我有些困惑。.clientX/Y确实是所需的,请参阅规格说明

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接