2012-03-13 103 views
8

给定SVG Path元素,如何将所有路径命令转换为绝对坐标?例如,转换该路径:将SVG路径转换为绝对命令

<path d="M17,42 l100,0 v100 h-100 z"/> 

这个等效路径:

<path d="M17,42 L117,42 V142 H17 Z"/> 

对此问题予以this question动机。

回答

11

这是我想出了JavaScript代码:

function convertToAbsolute(path){ 
    var x0,y0,x1,y1,x2,y2,segs = path.pathSegList; 
    for (var x=0,y=0,i=0,len=segs.numberOfItems;i<len;++i){ 
    var seg = segs.getItem(i), c=seg.pathSegTypeAsLetter; 
    if (/[MLHVCSQTA]/.test(c)){ 
     if ('x' in seg) x=seg.x; 
     if ('y' in seg) y=seg.y; 
    }else{ 
     if ('x1' in seg) x1=x+seg.x1; 
     if ('x2' in seg) x2=x+seg.x2; 
     if ('y1' in seg) y1=y+seg.y1; 
     if ('y2' in seg) y2=y+seg.y2; 
     if ('x' in seg) x+=seg.x; 
     if ('y' in seg) y+=seg.y; 
     switch(c){ 
     case 'm': segs.replaceItem(path.createSVGPathSegMovetoAbs(x,y),i);     break; 
     case 'l': segs.replaceItem(path.createSVGPathSegLinetoAbs(x,y),i);     break; 
     case 'h': segs.replaceItem(path.createSVGPathSegLinetoHorizontalAbs(x),i);   break; 
     case 'v': segs.replaceItem(path.createSVGPathSegLinetoVerticalAbs(y),i);    break; 
     case 'c': segs.replaceItem(path.createSVGPathSegCurvetoCubicAbs(x,y,x1,y1,x2,y2),i); break; 
     case 's': segs.replaceItem(path.createSVGPathSegCurvetoCubicSmoothAbs(x,y,x2,y2),i); break; 
     case 'q': segs.replaceItem(path.createSVGPathSegCurvetoQuadraticAbs(x,y,x1,y1),i); break; 
     case 't': segs.replaceItem(path.createSVGPathSegCurvetoQuadraticSmoothAbs(x,y),i); break; 
     case 'a': segs.replaceItem(path.createSVGPathSegArcAbs(x,y,seg.r1,seg.r2,seg.angle,seg.largeArcFlag,seg.sweepFlag),i); break; 
     case 'z': case 'Z': x=x0; y=y0; break; 
     } 
    } 
    // Record the start of a subpath 
    if (c=='M' || c=='m') x0=x, y0=y; 
    } 
} 

使用像这样从问题的路径:

var path = document.querySelector('path'); 
convertToAbsolute(path); 
console.log(path.getAttribute('d')); 
// M 17 42 L 117 42 V 142 H 17 Z 

编辑:这里有一个路径的测试页包括每个命令(绝对和相对)交错,并显示转换工作在当前版本的IE,Chrome,FF和Safari中。
http://phrogz.net/svg/convert_path_to_absolute_commands.svg

+0

seg.pathSegTypeAsLetter总是返回一个大写字母,即使我在路径中有小写字母命令。 switch语句背后的任何其他想法 – rajkamal 2012-03-13 07:35:55

+0

如果没有保留所有类型段的问题,那么它也是使用svg [pathElm.normalizedPathSegList] [1]中的内置功能的一个选项,它可以为您提供绝对moveto,lineto,curveto和close。 [1]:http://www.w3.org/TR/SVG11/paths.html#__svg__SVGAnimatedPathData__normalizedPathSegList – 2012-03-13 10:34:38

+0

@ErikDahlström我想使用它,但'normalizedPathSegList'在WebKit上不存在(总是返回'undefined' )。 – Phrogz 2012-03-13 12:47:40

8

如果你有拉斐尔,你有两个Raphael.pathToRelativeRaphael._pathToAbsolute

Raphael._pathToAbsolute不在文档中(like pathToRelative),并在内部许多地方使用Raphael源。但是,如果在函数名称之前添加_,则也可以在外部使用:Raphael._pathToAbsolute

在线转换: http://jsbin.com/mudusiseta

用法是一样的相对之一:

<script src="raphael.js"></script> 
<script> 
    // ... 

    var paper = Raphael(10, 50, 320, 200); 
    var path_string = "M10 10 L 20 20 L 100 10"; // Original coordinates 
    var path = paper.path(path_string); 

    // To relative coordinates 
    var path_string_rel = Raphael.pathToRelative(path_string); 
    console.log(path_string_rel); 

    // To absolute coordinates 
    var path_string_abs = Raphael._pathToAbsolute(path_string_rel); 
    console.log(path_string_abs); 

    // ...  
</script> 

我不知道为什么pathToAbsolute不在文档。这应该。

如果你想在Web Workers中工作(加速代码),很容易从Raphael获得所需的功能(应该被许可证允许)并将其用作DOM自由方法。 Raphael是一个DOM操作库(以及jQuery),并且它不能在Worker中使用,因为在Worker中不支持DOM。如果您的路径非常复杂,浏览器可能会挂起并阻止Web Workers在现代浏览器中提供解决方案。

1

这是用于svg路径(d attr)操作的库:https://github.com/fontello/svgpath

+0

我们如何在html页面中使用这个库,而不是在节点中? – Kpym 2015-12-14 07:58:43

+0

@Kpym例如,您可以将浏览器软件包与http://browserify.org/捆绑在一起。 – Vitaly 2015-12-14 11:25:30