Abbildungen, die im Vektorformat definiert sind, können in Webanwendungen erhebliche Vorteile gegenüber Pixel basierten Grafiken bieten:
SVG, der W3C Standard für Vektorgrafik im WWW, ist die Methode der Wahl, um Vektorgrafiken in eine Webanwendung einzubetten. Als Gründe sehe ich:
Die Verwendung des use-Elements ist zunächst einmal sehr einfach. Per ID wird auf eine Gruppe von Anweisungen referenziert:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> : <!-- Definition einer Gruppe von grafischen Anweisungen --> <symbol id="someID"> <g> : grafische Anweisungen </g> </symbol> : <!-- Einbindung der Anweisung per use-Element --> <use xlink:href="#someID" /> : </svg>Die in someID genutzten Koordinatenangaben beziehen sich dabei auf den ersten erreichbaren Rendering Kontext. In diesem Falle wäre das der Kontext der Einbettung der gesamten SVG (und dort zum Beispiel die Angaben im viewBox-Attribut), dann steht fest, auf welche Breite und Höhe sich die Koordinaten beziehen. Das ist in keinem Fall erwünscht und deshalb müssen immer Angaben im viewBox-Attribut den Rendering Kontext vorgeben:
: <symbol id="someID" viewBox="-50 -50 100 100"> <g> : grafische Anweisungen </g> </symbol> :Die ersten beiden Zahlen repräsentieren die Position des Koordinatenursprungs der Viewbox dieser Grafik, die letzten beiden Zahlen die Breite und Höhe der Umgebung, auf die sich ein Rendern der Grafik zu beziehen hat. Im Beispiel werden damit alle Koordinatenangaben auf den "Mittelpunk" der Grafik bezogen. Das ist sehr praktisch, wenn man grafische Elemente mit Symmetrien definiert (viele Koordinaten werden dann einfach gespiegelt) oder wenn man die Grafik vor dem Verwenden um ihr Zentrum drehen oder an einer Symmetrieachse spiegeln möchte.
Fazit: Grafiken, die für Wiederverwendung entworfen werden
Ein use-Element
: <use xlink:href="#someID" x=".." y=".." width=".." height=".." transform=".."/> :hat drei verschiedene Stellen, die eine Transformation der referenzierten Grafik zur Folge haben können:
Die Reihenfolge der Transformationen ist diese:
T * translate(x y) * scale(s_x s_y) * translate(-vb_x -vb_y)
Als Lösung wird x=y="0" gewählt und die Transformation T umgeschrieben in
T = scale(s_x s_y) * T' * translate(vb_x vb_y) * scale(1/s_x 1/s_y)T' kann nun mit Bezug auf die referenzierte Grafik und deren Koordinatenursprung definiert werden. Die Verschiebung der Grafik an den Punkt (x,y) wird dann noch mit einer abschließenden Translation erledigt:
T = translate(x y) * scale(s_x s_y) * T' * translate(vb_x vb_y) * scale(1/s_x 1/s_y)Im fertigen use-Element kommt der Rezeptcharakter klarer zum Vorschein: Der Audruck
<use xlink:href="#someID" width="w" height="h" transform="translate(x y) scale(s_x s_y) T' translate(vb_x vb_y) scale(1/s_x 1/s_y)"/>rendert eine Grafik mit viewBox="vb_x vb_y vb_w vb_h" in den Maßen w und h mit dem Koordinatenursprung der Grafik bei (x y). T' steht für eine Nutzer-definierte Transformation, die sich auf die Koordinaten der referenzierten Grafik bezieht. Sieht komplizierter aus als es ist, aber die Werte für vb_x, vb_y, s_x=w/vb_w und s_y=h/vb_h sind ja fest vorgegeben und müssen nur blind eingesetzt werden. Darüber hinaus gibt es keine einfachere Variante, da die unglückliche Reihenfolge der automatisch angewendeten Transformationen nicht zu ändern ist.
Kann die Grafik in originaler Größe dargestellt werden, so vereinfacht sich das Rezept. Dann ist s_x=w/vb_w=1 und s_y=h/vb_h=1 und man erhält
<use xlink:href="#someID" width="vb_w" height="vb_h" transform="translate(x y) T' translate(vb_x vb_y)"/>
Zunächst definieren wir eine Grafik für ein stilisiertes Flugzeug, mit seinem (angenommenen) Schwerpunkt bei (0,0), das wir anschließend skaliert, verschoben und rotiert wiederverwenden wollen:
<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 800 200"> <!-- ein Flugzeug-Icon mit dem Schwerpunkt bei (0,0) --> <symbol id="airplane.icon" viewBox="-50 -50 100 100"> <!-- Alle Koordinatenangaben beziehen sich auf die angegebene Viewbox --> <polygon points="-13,38 -13,32 -3,30 -3,11 -45,7 -45,-5 -4,-10 -4,-21 0,-25 4,-21 4,-10 45,-5 45,7 3,11 3,30 13,32 13,38" style="fill:grey;stroke-width:4;stroke-linejoin:round"/> <line x1="-8" y1="-24" x2="8" y2="-24" style="stroke:grey;stroke-width:2;stroke-linecap:round"/> <line x1="-15" y1="0" x2="15" y2="0" style="stroke:black;stroke-width:2;stroke-linecap:round"/> <line x1="0" y1="-15" x2="0" y2="15" style="stroke:black;stroke-width:2;stroke-linecap:round"/> <circle cx="-42" cy="-2" r="2" fill="red" /> <circle cx="42" cy="-2" r="2" fill="green" /> </symbol> <!-- Nutzung mit dem use-Element --> <use xlink:href="#airplane.icon" width="200" height="200"/> <!-- Koordinatenachsen zur Besseren Orientierung --> <g id="coordgrid" style="stroke:black;stroke-width:0.5" transform="scale(2)"> <line x1="0" y1="10" x2="100" y2="10"/> : 16 mehr davon <line y1="0" x1="90" y2="100" x2="90"/> </g> </svg>
Wie erwartet sehen wir die Grafik nicht bei (0,0), sondern bei (100,100). Denn nach dem gegebenen Rezept haben wir eigentlich
: <use xlink:href="#airplane.icon" width="200" height="200" transform="translate(100 100) scale(2) translate(-50 -50) scale(0.5)"/> :Um das Flugzeug zu rotieren testen wir
: <use xlink:href="#airplane.icon" width="200" height="200" transform="rotate(45)"/> :
und erhalten das falsche Ergebnis: die Rotation bezieht sich auf die Koordinaten des use-Elements was in den meisten Situationen nutzlos erscheint. Mit dem angegebenen Rezept erhalten wir jedoch das gewünschte Ergebnis:
: <use xlink:href="#airplane.icon" width="200" height="200" transform="translate(150 100) scale(2) rotate(45) translate(-50 -50) scale(0.5)"/> <use xlink:href="#airplane.icon" width="100" height="100" transform="translate(50 50) rotate(90) translate(-50 -50) "/> <use xlink:href="#airplane.icon" width="50" height="50" transform="translate(100 100) scale(0.5) rotate(180) translate(-50 -50) scale(2)"/> :
Grafiken können in SVG mit dem symbol - use Konstrukt wiederverwendet werden. Erst das angegebene Rezept erlaubt es jedoch
translate(x y) * scale(s_x s_y) * Twäre. Das ist sie aber nicht.