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

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

提前致谢。

4

2 回答 2

2

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

如果您避免这种情况并改用 SVG DOM,那么大多数浏览器(例如 Firefox)的性能会更高。代码将变为:

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

相同的注释适用于 endDrawTouch 函数。

于 2013-09-20T07:04:24.453 回答
1

也许您可以尝试 if<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确实是需要的,请参阅规格

于 2013-09-20T11:45:51.927 回答