2012-03-13 15 views
8

Dado un elemento de ruta SVG, ¿cómo puedo convertir todos los comandos de ruta en coordenadas absolutas? Por ejemplo, convertir esta ruta:Convertir ruta SVG a comandos absolutos

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

en este camino equivalentes:

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

Esta pregunta fue motivada por this question.

Respuesta

11

Aquí está el código JavaScript que se me ocurrió:

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

Se utiliza como tal con la ruta de la pregunta

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

Editar: Aquí está la página de prueba con un camino que incluye cada comando (absoluto y relativo) entrelazado y muestra que la conversión funciona en las versiones actuales de IE, Chrome, FF y Safari.
http://phrogz.net/svg/convert_path_to_absolute_commands.svg

+0

seg.pathSegTypeAsLetter siempre devuelve una letra mayúscula incluso si tengo comandos de letras pequeñas en la ruta. Cualquier otra idea detrás de las declaraciones de interruptor – rajkamal

+0

Si no es un problema que no conserve todo tipo de segmentos preservados, entonces también es una opción para usar la funcionalidad incorporada en svg, [pathElm.normalizedPathSegList] [1] que le da moveto absoluto, lineto, curvato y cierre. [1]: http://www.w3.org/TR/SVG11/paths.html#__svg__SVGAnimatedPathData__normalizedPathSegList –

+0

@ ErikDahlström Yo quería usar eso, pero 'normalizedPathSegList' no existe en WebKit (siempre devuelve' undefined') – Phrogz

8

Si tiene Raphaël, que tienen tanto Raphael.pathToRelative y Raphael._pathToAbsolute.

Raphael._pathToAbsolute no está en la documentación (like pathToRelative) y se utiliza en muchos lugares en la fuente de Raphael internamente. Pero puede usarse también externamente, si agrega _ antes del nombre de la función de esta manera: Raphael._pathToAbsolute.

conversión en línea: http://jsbin.com/mudusiseta

El uso es el mismo que en relación uno:

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

No sé qué pathToAbsolute no se encuentra en la documentación. Debería.

Si desea que esto funcione en Web Workers (para acelerar el código), es fácil obtener la función deseada de Raphael (que debe estar permitida por la licencia) y utilizarla como un método libre de DOM. Raphael es una biblioteca manipuladora de DOM (además de jQuery) y no se puede usar en Workers porque DOM no es compatible con Workers. Si tiene rutas muy complejas, el navegador puede bloquearse y evitar que Web Workers proporcione una solución en los navegadores modernos.

1

Aquí está la biblioteca para la ruta svg (d attr) manipulaciones: https://github.com/fontello/svgpath.

+0

¿Cómo podemos utilizar esta biblioteca en una página html, no en un nodo? – Kpym

+0

@Kpym puede agrupar el paquete del navegador con http://browserify.org/, por ejemplo. – Vitaly

Cuestiones relacionadas