用鼠标绘制svg路径

时间:2013-09-20 05:03:22

标签: javascript performance svg

我想在画布上用鼠标绘制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 个答案:

答案 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