2013-01-06 7 views
6

Bei einem SVG-Pfadelement, wie kann ich alle Pfadbefehle in relative Koordinaten umwandeln? Zum Beispiel konvertiert diesen Pfad (die jeden Befehl, absoluten und relativen, verschachtelt umfaßt):SVG-Pfad in relative Befehle konvertieren

<path d="M3,7 L13,7 m-10,10 l10,0 V27 H23 v10 h10 
     C33,43 38,47 43,47 c0,5 5,10 10,10 
     S63,67 63,67  s-10,10 10,10 
     Q50,50 73,57  q20,-5 0,-10 
     T70,40    t0,-15 
     A5,5 45 1 0 40,20 a5,5 20 0 1 -10,-10 
     Z" /> 

in diesen Ersatzpfad:

<path d="m3,7 l10,0 m-10 10 l10,0 v10 h10 v10 h10 
     c0,6 5,10 10,10 c0,5 5,10 10,10 
     s10,10 10,10  s-10,10 10,10 
     q-23,-27 0,-20  q20,-5 0,-10 
     t-3,-7    t0-15 
     a5,5 45 1 0 -30,-5 a5,5 20 0 1 -10,-10 
     z"/> 

Diese Frage wurde von this question motiviert.

Antwort

6

Snap.SVG hat Snap.path.toRelative().

var rel = Snap.path.toRelative(abspathstring); 

Fiddle

+0

Beachtenswert: zumindest die Snap.SVG Die hier verlinkte Version (http://cdn.jsdelivr.net/snap.svg/0.3.0/snap.svg.js) behält nicht die Koordinatengenauigkeit von Ihrer Eingabe bei, sondern wird auf drei Dezimalstellen für alle Koordinaten gerundet. – ecmanaut

7

I Phrogz' convertToAbsolute in diese convertToRelative Funktion gezwickt:

function convertToRelative(path) { 
    function set(type) { 
    var args = [].slice.call(arguments, 1) 
     , rcmd = 'createSVGPathSeg'+ type +'Rel' 
     , rseg = path[rcmd].apply(path, args); 
    segs.replaceItem(rseg, i); 
    } 
    var dx, dy, 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 (/[MLHVCSQTAZz]/.test(c)) { 
     if ('x1' in seg) x1 = seg.x1 - x; 
     if ('x2' in seg) x2 = seg.x2 - x; 
     if ('y1' in seg) y1 = seg.y1 - y; 
     if ('y2' in seg) y2 = seg.y2 - y; 
     if ('x' in seg) dx = -x + (x = seg.x); 
     if ('y' in seg) dy = -y + (y = seg.y); 
     switch (c) { 
     case 'M': set('Moveto',dx,dy);     break; 
     case 'L': set('Lineto',dx,dy);     break; 
     case 'H': set('LinetoHorizontal',dx);   break; 
     case 'V': set('LinetoVertical',dy);    break; 
     case 'C': set('CurvetoCubic',dx,dy,x1,y1,x2,y2); break; 
     case 'S': set('CurvetoCubicSmooth',dx,dy,x2,y2); break; 
     case 'Q': set('CurvetoQuadratic',dx,dy,x1,y1); break; 
     case 'T': set('CurvetoQuadraticSmooth',dx,dy); break; 
     case 'A': set('Arc',dx,dy,seg.r1,seg.r2,seg.angle, 
         seg.largeArcFlag,seg.sweepFlag); break; 
     case 'Z': case 'z': x = x0; y = y0; break; 
     } 
    } 
    else { 
     if ('x' in seg) x += seg.x; 
     if ('y' in seg) y += seg.y; 
    } 
    // store the start of a subpath 
    if (c == 'M' || c == 'm') { 
     x0 = x; 
     y0 = y; 
    } 
    } 
    path.setAttribute('d', path.getAttribute('d').replace(/Z/g, 'z')); 
} 

Gebrauchte wie so mit dem Weg von der Frage:

var path = document.querySelector('path'); 
convertToRelative(path); 
console.log(path.getAttribute('d')); 
// m 3 7 l 10 0 m -10 10 l 10 0 v 10 h 10 v 10 h 10 c 0 6 5 10 10 10 c 0 5 5 10 10 10 s 10 10 10 10 s -10 10 10 10 q -23 -27 0 -20 q 20 -5 0 -10 t -3 -7 t 0 -15 a 5 5 45 1 0 -30 -5 a 5 5 20 0 1 -10 -10 z 

Ich habe auch ein wenig PhantomJS Dienstprogramm Shell svg2rel, die in alle Pfade transformiert eine Svg auf diese Weise (es gibt eine entsprechende svg2abs im gleichen Sinne, für ein gutes Maß).

+0

'pathSegList' ist jetzt veraltet: https://stackoverflow.com/questions/34352624/alternative-for-deprecated-svg-pathseglist –

+0

Da diese Antwort nicht mehr richtig nach oben erwähnt API-Abkehr in Chrome (und anderen Browsern), ich wechsle zum Snap-Hack - oder eine ähnliche Lösung in seinem älteren Geschwister Rafael: http://jsbin.com/voxemav/ – ecmanaut