# SVG – Scalable Vector Graphics

Wenn es nur eine einzige Wahrheit gäbe, könnte man nicht hundert Bilder über dasselbe Thema malen.
Pablo Picasso, spanischer Maler, Grafiker und Bildhauer

SVG ist seit kurzer Zeit ein Schlagwort, auf das Sie an den verschiedensten Stellen stoßen werden. Was es mit SVG auf sich hat, werden Sie in diesem Unterkapitel erfahren.

# Was sind Vektoren?

Ein Hauptproblem von Grafiken, die auf Webseiten verwendet werden, ist die fehlende Flexibilität. Das rührt daher, dass eine JPEG- oder PNG-Grafik aus Pixeln aufgebaut wird. Die Anzahl der Pixel hängt von der Größe der Grafik ab. Eine Grafik mit 400 Pixel Breite und 300 Pixel Höhe besitzt also 120.000 Pixel. Für jedes dieser Pixel ist innerhalb der Grafik eine Farbe definiert. Formen wie Linien, Rechtecke oder Kreise existieren also nur, weil bestimmte Pixel in einer bestimmten Anordnung die gleiche oder eine ähnliche Farbe aufweisen.

Bei Vektoren ist dies jedoch ganz anders. Eine auf Vektoren basierende Grafik besitzt keine Pixel, sondern Punkte in einem Koordinatensystem. Ein Vektor verbindet nun zwei Punkte in diesem Koordinatensystem miteinander. Diesem Vektor wird dann eine Farbe zugewiesen, und so entsteht dann eine Linie.

Auf den ersten Blick lassen sich Pixel-Grafiken kaum von Vektor-Grafiken unterscheiden. Das gilt aber auch nur, solange die beiden Grafiken in ihrer Originalgröße dargestellt werden. Vergrößern Sie eine Pixel-Grafik, wird diese sehr grobkörnig, da die einzelnen Pixel größer werden. Die Qualität der Grafik geht dann verloren. Wird hingegen eine Vektor-Grafik vergrößert, bleibt die Qualität gleich gut. Eine Vektor-Grafik bleibt also skalierbar, eine Pixel-Grafik nicht. Daher kommt auch die Bezeichnung »Scalable Vector Graphics« (dt. skalierbare Vektor-Grafiken).

Sehen Sie sich dazu ein Beispiel an. Bei der Grafik aus Abbildung 3.1 lässt sich nicht erkennen, ob es sich um eine Pixel- oder eine Vektor-Grafik handelt, da die Grafik in ihrem Originalzustand dargestellt wird. Wie eine Vergrößerung der Grafik aussehen würde, wenn sie auf Vektoren basiert, können Sie in Abbildung 3.2 auf der linken Seite sehen. Die vergrößerte Darstellung, wenn es sich um eine Pixel-Grafik (gebräuchlichste Bezeichnung ist »Rastergrafik«) handelt, sehen Sie dann in Abbildung 3.2 auf der rechten Seite.

Die Grafik im Originalzustand. Es ist nicht erkennbar, ob sie pixel-oder vektorbasiert ist.
Abbildung 3.1: Die Grafik im Originalzustand. Es ist nicht erkennbar, ob sie pixel-oder vektorbasiert ist.

Vergrößerte Darstellung der Grafik aus Abbildung 3.1, links als Vektor-, rechts als Pixelgrafik
Abbildung 3.2: Vergrößerte Darstellung der Grafik aus Abbildung 3.1, links als Vektor-, rechts als Pixelgrafik

In Abbildung 3.2 ist der deutliche Qualitätsverlust bei Rastergrafiken zu erkennen.

Ein weiterer Vorteil von vektorbasierten Grafiken ist die geringere Dateigröße. Die Grafik in Abbildung 3.1 beansprucht mit einer Größe von 300 × 300 als Vektor-Grafik lediglich ein paar Byte (ca. 0,5 kB), während sie als pixelbasierte Grafik bis zu 300 kB belegen kann. Vektor-Grafiken sind also auch in dieser Beziehung – wenn auch nur um eine Nasenlänge – im Vorteil. Erst ab einem gewissen Detailumfang einer Vektor-Grafik kann es passieren, dass sie größer als das Pixel-Pendant ist.

Zu den bisher genannten Vorteilen der Vektor-Grafiken kommt noch einer hinzu: ihre Verformbarkeit. Während Pixel-Grafiken, wenn sie einmal erstellt worden sind, im Nachhinein nur sehr schwer bis so gut wie gar nicht veränderbar sind, können Vektor-Grafiken beliebig oft verändert werden, ohne dass mit Qualitätseinbußen gerechnet werden muss. So lässt sich z. B. die Farbe eines Textes in einer Vektor-Grafik mit zwei, drei Handgriffen verändern. Bei einer Pixel-Grafik ist dies wesentlich problematischer und bedarf oft einer zusätzlichen Nachbesserung.

Vektor-Grafiken werden im Internet schon seit geraumer Zeit in Form von Flash-Filmen (.swf) eingesetzt. Voraussetzung für die Bereitstellung von Flash-Filmen ist jedoch in der Regel die Autorensoftware Macromedia Flash, die nicht unbedingt preiswert ist. Zudem muss der Nutzer zusätzlich ein Plug-in installiert haben, damit er solche Filme auch betrachten kann. Da SVG kein proprietärer Standard ist, sondern ähnlich wie HTML oder CSS durch das W3C entwickelt wurde und noch immer entwickelt wird, ist eine teure Autorensoftware nicht notwendig. Einzig und allein über Kenntnisse von XML und der darauf aufbauenden SVG sollte man verfügen. Das Plug-in ist jedoch noch immer erforderlich, da selbst Mozilla keine native Implementierung des SVG-Standards aufweist.

Um die Beispiele in diesem Abschnitt nachvollziehen zu können, sollten Sie ein Plug-in herunterladen und installieren. Das verbreitetste Plug-in ist der SVG Viewer von Adobe, den Sie unter http://www.adobe.com/svg kostenlos beziehen können.

# Das erste SVG-Dokument

Das folgende Beispiel zeigt ein einfaches SVG-Dokument. Anschließend werde ich es Schritt für Schritt erklären. Kopieren Sie das SVG-Dokument aus Listing 3.1 in eine neue Datei, und speichern Sie die Datei unter einem Namen mit der Endung .svg ab.

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <text x="10" y="60" font-family="Tahoma" font-size="50" fill="black">Das ist SVG!</text>
</svg>

Listing 3.1: Das erste SVG-Dokument

Öffnen Sie nun das Dokument mit einem Doppelklick. Wenn Sie versuchen, das Dokument über einen Webserver zu öffnen, wird dies scheitern. Den Grund dafür werden Sie in Abschnitt 3.3 erfahren.

Ausgabe des Listings 3.1 im Microsoft Internet Explorer mit dem Adobe SVG Viewer
Abbildung 3.3: Ausgabe des Listings 58.1 im Microsoft Internet Explorer mit dem Adobe SVG Viewer

Wenn die Ausgabe in Ihrem Browser derjenigen in Abbildung 3.3 entspricht, haben Sie soeben Ihr erstes SVG-Dokument erstellt. Sehen Sie sich den Quelltext einmal genauer an. Auf die beiden ersten Zeilen des Dokuments habe ich bereits in Kapitel 1 hingewiesen. Zuerst wurde die XML-Processing-Instruction notiert, die darauf hinweist, dass nun ein Dokument folgt, das auf XML basiert. Die in der zweiten Zeile folgende DTD gibt an, welche Auszeichnungssprache genau verwendet wird und beschreibt außerdem, welche Elemente und Attribute verwendet werden dürfen.

Dann folgt das Start-Tag des svg-Elements. svg ist das Wurzelelement und darf von keinem anderen Element umschlossen werden. Innerhalb des Start-Tags wird auch der XML-Namespace definiert. Damit wird erklärt, dass alle Elemente und Attribute, die innerhalb des Gültigkeitsbereichs des svg-Elements notiert werden, zu dem SVG-Namensraum gehören. Innerhalb des svg-Elements folgt dann ein text-Element. Letzteres erzeugt Textausgaben im Browser. x und y bestimmen die Position, an der der Text ausgegeben werden soll, font-family die Schriftart, font-size die Größe und fill die Farbe. Gewisse Ähnlichkeiten zu CSS bezüglich der Namensgebung der Attribute sind gewollt. Dazu später jedoch mehr.

Legen Sie sich jetzt am besten eine Vorlage für SVG-Dokumente an, die folgendermaßen aussehen sollte:

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <!-- ... -->
</svg>

Listing 3.2: Vorlage für ein SVG-Dokument

Anstelle des Kommentars werden die SVG-Elemente notiert, die die Grafik dann definieren.

# SVG in HTML

Wenn Sie versuchen, das SVG-Dokument aus Listing 3.1 über einen Webserver zu öffnen (also durch Angabe einer URI wie http://localhost/list3.1.svg), werden Sie feststellen, dass lediglich der Quelltext des Dokuments ausgegeben wird. Dies hängt mit dem MIME-Typ von SVG-Dokumenten zusammen. Einige Server senden nicht immer den korrekten MIME-Typ, so etwa der Apache Webserver. Anstatt dem Browser also mitzuteilen, dass nun ein Dokument vom Typ image/svg+xml folgt, geht der Server von einem ihm unbekannten Typ aus und schickt keinen MIME-Typ. Dies führt dazu, dass zwar die meisten Browser erkennen, dass es sich um ein XML-Dokument handelt, sie können aber trotzdem ohne MIME-Typ damit nicht viel anfangen und geben entweder eine Fehlermeldung oder den Quelltext aus.

Abhilfe schafft jedoch das HTML-Element object. Dieses Element ist in der Lage, jeden beliebigen Datentyp unter Angabe des MIME-Typs zu laden. Auch wenn der Webserver dann nicht den korrekten MIME-Typ sendet, wird das SVG-Dokument trotzdem dargestellt.

<html>
  <head>
    <title>Listing 3.3</title>
  </head>
  <body style="background-color:#336699;">
    <object data="list3.1.svg" type="image/svg+xml" width="100%" height="100%">
    </object>
  </body>
</html>

Listing 3.3: Einbettung eines SVG-Dokuments in ein HTML-Dokument mit Hilfe des object-Elements

Das object-Element erwartet dabei mehrere Attribute. Die beiden wichtigsten sind data und type. Mit data geben Sie die Quelle an, die dargestellt werden soll, und mit type, von welchem MIME-Typ diese Quelle ist. Zwar sind width und height optional, Sie sollten die beiden Attribute jedoch trotzdem mit angeben, da es keine Garantie gibt, dass der Browser die Breite und Höhe der darzustellenden Quelle auch korrekt erkennt.

Einbettung eines SVG-Dokuments mit Hilfe des object-Elements
Abbildung 3.4: Einbettung eines SVG-Dokuments mit Hilfe des object-Elements

Der blaue Rand und das eingebettete SVG-Dokument stammen übrigens von dem HTML-Dokument selbst, da dessen Hintergrundfarbe auf #336699 festgelegt wurde.

# Grundformen

Während Sie bei der Verwendung der GD-Library spezielle Funktionen aufrufen mussten, um Formen zu zeichnen, wird dies in SVG alles über Elemente und Attribute geregelt. Für Linien, Rechtecke und Kreise stehen verschiedene Elemente bereit, die sich durch die vielen Attribute aber deutlich besser gestalten lassen.

# Text ausgeben

Text können Sie in SVG mit dem Element text ausgeben. Der auszugebende Text wird dabei innerhalb des Gültigkeitsbereichs des Elements notiert (also genauso wie in HTML). Die Koordinaten, an denen der Text ausgegeben werden soll, werden durch die Attribute x und y definiert. Der Text wird dann mit der linken unteren Ecke an diesen Koordinaten platziert.

Beachten Sie, dass dies von der Positionierung von Text mit der GD-Library abweicht. Dort wird die linke obere Ecke des Textes an der angegebenen Position ausgerichtet.

Die Schriftart des Textes definieren Sie mit dem Attribut font-family. Während Sie in CSS einfach nur einen Schrifttyp (serif, sans-serif, monospace etc.) angeben konnten, ist dies in SVG nicht möglich. Hier müssen Sie eine bestimmte Schriftart angeben. Sie sollten sich deshalb vorerst auf weit verbreitete Schriftarten beschränken, wie etwa Arial, Times oder Courier.

Auch bei dem Attribut font-size sind Sie in Ihrem Handlungsspielraum stark eingeschränkt, da Sie die Größe der Schrift lediglich in Punkt angeben können. Da Ihnen nur diese Möglichkeit bleibt, müssen Sie jedoch keine Angaben zur Maßeinheit machen.

Die Farbe können Sie mit fill angeben. Dabei können Sie sowohl ein Farbwort wie black, yellow, lime oder Ähnliches, aber auch Hex-Tripel-Werte wie #FF0000 oder #FFFF00 angeben. Es mag verwirrend erscheinen, dass die Textfarbe nicht über color festgelegt wird. Stellen Sie sich den auszugebenden Text einfach als eine gezeichnete Fläche vor, die anschließend mit einer Farbe gefüllt wird. Darüber hinaus wird auch in verktorbasierten Grafikprogrammen wie Adobe Illustrator oder Macromedia Flash die Textfarbe mit der Füllfarbe festgelegt.

<text x="100" y="100" font-family="Arial" font-size="40"
    fill="#996633">Text (Arial,40,#996633)</text>

Dieses Beispiel würde an den Koordinaten (100,100) einen Text in der Schriftart Arial mit der Schriftgröße 40 und in der Farbe #996633 ausgeben.

Alternativ können Sie die Angaben zur Schriftformatierung auch mit dem style-Attribut vornehmen. Dies ist auch der Grund, warum die Eigenschaften zur Formatierung eine starke Ähnlichkeit zu CSS aufweisen. Es erleichtert das Lernen von SVG und vereinfacht die Erstellung von solchen Grafiken, da Sie nicht zusätzlich spezielle Bezeichner verwenden müssen. Das obige Beispiel würde dann folgendermaßen geschrieben werden:

<text x="100" y="100"
    style="font-family:Arial; font-size:40; fill:#996633">Text (Arial,40,#996633)</text>

Einen speziellen Effekt können Sie auch mit dem Attribut stroke erzeugen. Wenn Sie die Farbe von fill auf die Hintergrundfarbe setzen und die Farbe für stroke auf eine andere, erhalten Sie einen Text, der nur eine Außenlinie besitzt. Mit stroke-width können Sie dann noch die Dicke der Umrandung definieren.

<text x="100" y="100" style="font-family:Arial;   
 font-size:40; fill:#FFFFFF; stroke:#000000;   
 stroke-width:3">Text</text>

Auch die Attribute font-weight und font-style sind in SVG bekannt. So können Sie mit font-weight:bold; die Schriftdicke auf fett setzen und mit font-style:italic; den Schriftstil auf kursiv.

Sehen Sie sich dazu ein vollständiges Beispiel und dessen Ausgabe im Browser an.

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <text x="30" y="60" style="font-family:’Times New Roman’; font-size:40; fill:#999999; font-style:italic">filled/italic</text>
    <text x="30" y="100" style="font-family:Arial; font-size:40; fill:#FFFFFF; stroke:#000000">  outlined</text>
    <text x="30" y="140" style="font-family:’Courier New’; font-size:40; fill:#FFFF00; stroke:#000000; font-weight:bold">stroked/bold</text>
</svg>

Listing 3.4: Verschiedene Texte mit unterschiedlichen Formatierungen

Ausgabe des Listing 3.4 im Internet Explorer mit dem SVG Viewer
Abbildung 3.5: Ausgabe des Listing 3.4 im Internet Explorer mit dem SVG Viewer

# Linien

Linien können Sie in SVG mit dem Element line erzeugen. Dabei müssen Sie den Start- und den Endpunkt festlegen. Die Attribute x1 und y1 definieren den Startpunkt und x2 und y2 den Endpunkt. Auch hier stehen die Attribute stroke oder stroke-width zur Verfügung, um die optische Gestaltung der Linie zu beeinflussen. Mit stroke beeinflussen Sie die Farbe der Linie und mit stroke-width die Dicke. Das Element line besitzt übrigens kein Ende-Tag.

<line x1="10" y1="20" x2="200" y2="50" stroke="#000000" />  
<line x1="10" y1="40" x2="200" y2="70" stroke="#999999" stroke-width="5" />

Das erste line-Element würde eine Linie in der Farbe Schwarz vom Punkt (10,20) zum Punkt (200,50) zeichnen. Das zweite würde eine Linie vom Punkt (10,40) zum Punkt (200,70) zeichnen, diesmal in der Farbe #999999 und mit einer Dicke von 5.

Alternativ können Sie auch das Element polyline verwenden, mit dem Sie mehr als nur zwei Punkte miteinander verbinden können. Die einzelnen Punkte werden dann in der Reihenfolge x1 y1 x2 y2 ... xn yn an das Attribut points übergeben. Normalerweise werden dabei jedoch der Start- und der Endpunkt ebenfalls miteinander verbunden, und die daraus resultierende Fläche wird mit einer Farbe gefüllt. Wenn Sie dies nicht möchten, sollten Sie dem Attribut fill den Wert none zuweisen.

<polyline points="60 10 70 100 80 10" fill="none" stroke="black" stroke-width="5" />

Dieses Beispiel würde zwei Linien zeichnen. Eine vom Punkt (60,10) zum Punkt (70,100) und eine von (70,100) zum Punkt (80,10) – beide in der Farbe Schwarz und mit der Dicke 5.

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"   
 "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <line x1="10" y1="20" x2="200" y2="50" stroke="#000000" />
    <line x1="10" y1="40" x2="200" y2="70" stroke="#999999" stroke-width="5" />
    <polyline points="60 10 70 100 80 10 90 100 100 10" fill="none" stroke="black" stroke-width="5" />
</svg>

Listing 3.5: Zeichnen verschiedener Linien mit SVG

Ausgabe des Listing 3.5 im Internet Explorer mit dem SVG Viewer
Abbildung 3.6: Ausgabe des Listing 3.5 im Internet Explorer mit dem SVG Viewer

# Rechtecke

Das Element rect definiert in einer SVG-Grafik ein Rechteck. Dabei sind jedoch gewisse Mindestangaben erforderlich. Zum einen ist dies die Position, an der die linke obere Ecke des Rechtecks platziert werden soll, und zum anderen die Breite und die Höhe des Rechtecks. Natürlich sollte auch eine Farbe angegeben werden. Die Position wird mit den Attributen x und y angegeben, die Breite und Höhe mit width und height. Die Angabe einer Farbe kann entweder mit fill oder stroke bzw. mit beiden Attributen erfolgen.

<rect x="100" y="100" width="400" height="300" fill="red" />

Dieses Beispiel erzeugt, beginnend an der Position (100,100), ein Rechteck, das 400 Punkte breit und 300 Punkte hoch ist. Die Flächenfarbe des Rechtecks ist Rot.

Die Ecken eines solchen Rechtecks lassen sich auch abrunden. Dafür werden die Attribute rx und ry benötigt. Dabei beschreibt ry die Höhe der Abrundung und rx die Breite. Damit die Rundung also zu sehen ist, müssen beide Attribute mindestens einen Wert aufweisen, der größer als 0 ist. Für eine symmetrische Rundung muss sowohl rx als auch ry der gleiche Wert zugewiesen werden.

<rect x="30" y="30" rx="10" ry="20" width="100" height="100" fill="blue" />

Das Beispiel erzeugt an der Position (30,30) ein 100*100 großes, blaues Rechteck mit asymmetrisch abgerundeten Ecken.

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"   
 "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <rect x="50" y="50" width="150" height="100" fill="red" />
    <rect x="225" y="50" rx="20" ry="20" width="100" height="100" fill="none" stroke="black" stroke-width="5"/>
    <rect x="50" y="175" rx="35" ry="15" width="275" height="50" style="fill:yellow; stroke:black; stroke-width:2"/>
</svg>

Listing 3.6: Ausgabe verschiedenartiger Rechtecke

Ausgabe des Listing 3.6 im Internet Explorer mit dem SVG Viewer
Abbildung 3.7: Ausgabe des Listing 3.6 im Internet Explorer mit dem SVG Viewer

# Kreise und Ellipsen

Kreise werden mit dem Element circle definiert. Um einen Kreis zu zeichnen, müssen Sie den Mittelpunkt des Kreises und den Radius angeben. Der Mittelpunkt wird anhand der Attribute cx und cy angegeben und der Radius mit r. Natürlich sind auch hier wieder fill, stroke und stroke-width erlaubt.

<circle cx="100" cy="100" r="80" fill="green" />

Dieses Beispiel erzeugt an der Position (100,100) einen Kreis mit einem Radius von 80 in der Farbe Grün.

Für eine Ellipse müssen Sie das Element ellipse und anstelle des Attributs r die Attribute rx und ry angeben. Diese definieren den horizontalen (rx) und den vertikalen Radius (ry).

<ellipse cx="150" cy="100" rx="125" ry="75" fill="none" stroke="black" stroke-width="3" />

Zeichnet eine Ellipse mit einem schwarzen Außenrahmen. Der Mittelpunkt der Ellipse liegt an der Position (150,100). Die beiden Radien betragen horizontal 125 und vertikal 75.

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <circle cx="50" cy="50" r="30" fill="yellow" stroke="black" />
    <ellipse cx="110" cy="120" rx="100" ry="25" style="fill:none; stroke:black; stroke-width:5" />
</svg>

Listing 3.7: Ausgabe eines Kreises und einer Ellipse

Ausgabe des Listing 3.7 im Internet Explorer mit dem SVG Viewer
Abbildung 3.8: Ausgabe des Listing 3.7 im Internet Explorer mit dem SVG Viewer

# Farben

Neben den bisher vorgestellten Formatierungsmöglichkeiten wie fill, stroke oder stroke-width gibt es noch weitere, die ich an dieser Stelle kurz erläutern werde.

# Transparenz

Natürlich gibt es auch in SVG die Möglichkeit, Transparenz zu definieren. Dies gilt sowohl für die Füllfarbe als auch für die Farbe der Außenlinie. Die Transparenz der Füllfarbe wird mit fill-opacity und die Transparenz der Außenlinie mit stroke-opacity definiert. Für beide Attribute gilt ein Wertebereich von 0.0 (transparent) bis 1.0 (deckend).

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <rect x="40" y="40" width="100" height="100" fill="black" />
    <circle cx="140" cy="90" r="50" fill="yellow" fillopacity="0.8" />
</svg>

Listing 3.8: Transparenz von Füllfarben

Ausgabe des Listing 3.8 im Internet Explorer mit dem SVG Viewer
Abbildung 3.9: Ausgabe des Listing 3.8 im Internet Explorer mit dem SVG Viewer

Da die Farbe für Texte ebenfalls mit einer Füllfarbe festgelegt wird, kann auch für Text der Grad der Transparenz mit fill-opacity festgelegt werden. Testen Sie doch einmal das folgende Beispiel:

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"   
 "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <rect x="40" y="40" width="100" height="100" fill="black" />
    <circle cx="140" cy="90" r="50" fill="yellow" fillopacity="0.8" />
    <text x="100" y="100" style="font-family:Arial; font-size:40; fill:#FF0000; stroke:#000000; stroke-width:3; fill-opacity:0.7">Tranparenter Text</text>
</svg>

Listing 3.9: Transparente Formen und Texte

# Lineare Farbverläufe

Mit dem Element linearGradient können Sie einen linearen Farbverlauf erzeugen. Mit dem Attribut id müssen Sie dem Farbverlauf eine eindeutige ID geben. Diese ID wird später benötigt, um den Farbverlauf für ein Element als Füllfarbe referenzieren zu können. Mit dem Element stop werden dann die Farben für den Verlauf definiert. Der Startpunkt als Prozentwert wird mit offset angegeben und die Farbe mit stop-color.

<linearGradient id="farbverlauf1">  
    <stop offset="0%" stop-color="#FF6600" />  
    <stop offset="100%" stop-color="#FFFF66" />  
</linearGradient>

Dieses Beispiel definiert einen Farbverlauf mit der ID farbverlauf1. Der Farbverlauf beginnt bei 0 % mit der Farbe #FF6600 und endet bei 100 % mit der Farbe #FFFF66.

mit der URL angeben

Bei einer Form können Sie diesen Farbverlauf dann als Füllfarbe verwenden. Dabei wird anstelle eines Farbnamens url und in Klammern dahinter die ID des Farbverlaufs mit vorangestelltem Rautezeichen notiert:

<rect fill="url(#farbverlauf1)" x="10" y="10" width="100" height="50" />

Je mehr stop-Elemente Sie notieren, desto mehr Verläufe gibt es dann innerhalb des Farbverlaufs.

<linearGradient id="farbverlauf2">  
    <stop offset="0%" stop-color="#99CCFF" />  
    <stop offset="25%" stop-color="#003366" />  
    <stop offset="100%" stop-color="#99CCFF" />  
</linearGradient>

Dies erzeugt ebenfalls einen Farbverlauf. Bei 0  % besitzt er die Farbe #99CCFF, bei 25  % #003366 und bei 100  % des Verlaufs wieder #99CCFF.

Das folgende Listing verwendet beide Farbverläufe als Füllfarbe für je ein Rechteck.

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"   
 "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <linearGradient id="farbverlauf1">
        <stop offset="5  %" stop-color="#FF6600" />
        <stop offset="95  %" stop-color="#FFFF66" />
    </linearGradient>
    <linearGradient id="farbverlauf2">
        <stop offset="0  %" stop-color="#99CCFF" />
        <stop offset="25  %" stop-color="#003366" />
        <stop offset="100  %" stop-color="#99CCFF" />
    </linearGradient>
    <rect x="40" y="40" width="200" height="50" fill="url(#farbverlauf1)" stroke="black" stroke-width="2" />
    <rect x="40" y="100" width="200" height="50" fill="url(#farbverlauf2)" stroke="black" stroke-width="2" />
</svg>

Listing 3.10: Füllung zweier Rechtecke mit einem Farbverlauf

Ausgabe des Listing 3.10 im Internet Explorer mit dem SVG Viewer
Abbildung 3.10: Ausgabe des Listing 3.10 im Internet Explorer mit dem SVG Viewer

# Radiale Farbverläufe

Es ist auch möglich, einen radialen Farbverlauf zu definieren, und zwar mit radialGradient. Die restliche Definition unterscheidet sich nicht von der Definition eines linearen Farbverlaufs. Mit dem Attribut id wird dem Farbverlauf eine ID vergeben, und mit stop-Elementen werden dann die Farben definiert.

<radialGradient id="radFarb1">  
    <stop offset="0%" stop-color="FF6600" />
    <stop offset="100%" stop-color="FFFF66" />
</radialGradient>

Ein vollständiges Beispiel:

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <radialGradient id="radFarb1">
        <stop offset="0  %" stop-color="#FFFF66" />
        <stop offset="100  %" stop-color="#FF6600" />
    </radialGradient>
    <radialGradient id="radFarb2">
        <stop offset="0  %" stop-color="#99CCFF" />
        <stop offset="25  %" stop-color="#003366" />
        <stop offset="100  %" stop-color="#99CCFF" />
    </radialGradient>
    <circle cx="100" cy="100" r="75" fill="url(#radFarb1)" stroke="black" stroke-width="2" />
    <rect x="200" y="25" width="150" height="150" fill="url(#radFarb2)" stroke="black" stroke-width="2" />
</svg>

Listing 3.11: Zwei radiale Farbverläufe, die einem Kreis und einem Rechteck zugewiesen werden

Ausgabe des Listing 3.11 im Internet Explorer mit dem SVG Viewer
Abbildung 3.11: Ausgabe des Listing 3.11 im Internet Explorer mit dem SVG Viewer

Auch bei radialen und linearen Farbverläufen ist die Definition der Transparenz möglich. Diese Definition muss jedoch bei einem der Elemente vorgenommen werden, das den Farbverlauf verwendet. Das zu verwendende Attribut ist dann natürlich fill-opacity.

# Pfade

Zusätzlich zu den einfachen Grundformen bietet SVG jedoch auch die Möglichkeit, Pfade zu definieren.

# Einfache Pfade

Pfade sind sehr viel flexibler als Grundformen, da sie viel komplexere Figuren erzeugen können und sich nicht nur auf Linien, Rechtecke oder Kreise beschränken. Sie können mit einem Pfad sogar solche Grundformen zeichnen, auch wenn dies manchmal in einem Zahlenwirrwarr endet. Das Element zum Zeichnen eines Pfades ist path. Gezeichnet wird ein Pfad, indem mit bestimmten Steuerzeichen und Koordinaten die Verbindungen zwischen den einzelnen Punktpaaren definiert werden. Diese Steuerzeichen und Koordinaten werden an das Attribut d übergeben.

<path d="M 100 100 L 200 200" stroke="black" stroke-width="4" />

Dieses path-Beispiel zeichnet vom Punkt (100,100) zum Punkt (200,200) eine Linie mit einer Dicke von 4 und in der Farbe Schwarz. In diesem Beispiel finden Sie zwei Steuerzeichen: M und L. M ist die Abkürzung für moveto und definiert sozusagen den Startpunkt des Pfads ausgehend von der linken oberen Ecke der Zeichenfläche (also (0,0). L ist die Abkürzung für lineto und zeichnet eine gerade Linie zum angegebenen Punkt (ebenfalls in Relation zum Punkt (0,0)). Versuchen Sie sich den Pfad einfach als Stift vorzustellen, der am Punkt (100,100) angesetzt wird und dann eine Gerade zum Punkt (200,200) zeichnet.

Neben den beiden Steuerzeichen M und L gibt es natürlich noch weitere:

  • z
    Steht für »closepath« und bedeutet, dass der Startpunkt und der letzte angegebene Punkt miteinander verbunden werden
  • H, h
    Steht für »horizontal« und zeichnet eine horizontale Linie zum nächsten Punkt. H weist darauf hin, dass der folgende Punkt eine absolute Angabe ist, und h, dass der Punkt relativ zum vorherigen Punkt angegeben wird.
  • V, v
    Steht für »vertical« und zeichnet eine vertikale Linie zum nächsten Punkt. V gibt einen absoluten Punkt an und v einen zum vorherigen Punkt relativen Punkt.
  • Q, q
    Steht für »quadratic bézier curveto« und zeichnet anstelle einer geraden Linie eine Kurve vom letzten zum folgenden Punkt. Q gibt wieder einen absoluten und q einen relativen Punkt an.

Sehen Sie sich dazu ein paar Beispiele an.

<path d="M 200 100 L 300 300 L 100 300 z" fill="yellow" stroke="black" stroke-width="4" />

Zeichnet ein Dreieck, indem bei dem Punkt (200,100) angesetzt und eine erste Linie zum Punkt (300,300) gezeichnet wird. Dann folgt eine zweite Linie zum Punkt (100,300). Durch die Angabe von z werden der letzte Punkt (100,300) und der Startpunkt (200,100) miteinander verbunden, der Pfad wird also geschlossen.

<path d="M 100 100 H 300 V 300 H 100 z" fill="yellow" stroke="black" stroke-width="4" />

Dies Beispiel zeichnet ein Rechteck unter Verwendung der Steuerzeichen H und V. Der Vorteil dieser beiden Steuerzeichen ist, dass Sie, wenn Sie eine horizontale oder vertikale Linie zeichnen wollen, nur die Hälfte der Koordinate angeben müssen. Die Linie wird dann in Bezug auf den vorherigen Punkt gezeichnet. Anstatt also x und y anzugeben, müssen Sie bei einer horizontalen Linie nur x und bei einer vertikalen nur y angeben. Der Rest des Punkts wird vom vorherigen Punkt abgeleitet.

# Kurven

Das Zeichnen von Kurven ist ein klein wenig komplizierter. Die Anweisung

<path d="M 100 100 Q 200 100 200 200" fill="none" stroke="black" stroke-width="4" />

zeichnet eine Kurve vom Punkt (100,100) zum Punkt (200,200). Der Punkt (200,100), den Sie im Wert des Attributs d finden, ist der so genannte Kontrollpunkt. Wenn die Kurve gezeichnet wird, orientiert sich die Kurve an diesem Kontrollpunkt. Würde dieser Punkt fehlen, würde lediglich eine Gerade gezeichnet. Im Folgenden sehen Sie noch ein detaillierteres Beispiel zu den Kurven:

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <line x1="100" y1="100" x2="200" y2="100" stroke="gray" stroke-width="1" />
    <line x1="200" y1="100" x2="200" y2="200" stroke="gray" stroke-width="1" />
    <line x1="200" y1="200" x2="200" y2="300" stroke="gray" stroke-width="1" />
    <line x1="200" y1="300" x2="300" y2="300" stroke="gray" stroke-width="1" />
    <circle cx="200" cy="100" r="5" fill="none" stroke="red" stroke-width="1" />
    <circle cx="200" cy="300" r="5" fill="none" stroke="red" stroke-width="1" />
    <path d="M 100 100 Q 200 100 200 200 200 300 300 300" fill="none" stroke="black" stroke-width="4" />
</svg>

Listing 3.12: Zeichnen einer Kurve mit Darstellung der Kontrollpunkte

In Abbildung 3.12 können Sie die Ausgabe des Listing 3.12 sehen. Die dicke schwarze Linie ist die gezeichnete Kurve. Die dünnen grauen Linien stellen die Funktion der Kontrollpunkte dar. Die Kontrollpunkte selbst werden durch die kleinen Kreise dargestellt.

Ausgabe des Listing 3.12 im Internet Explorer mit dem SVG Viewer
Abbildung 3.12: Ausgabe des Listing 3.12 im Internet Explorer mit dem SVG Viewer

Beim Zeichnen einer solchen Kurve ist die Reihenfolge der Punkte äußerst wichtig. Nach dem Steuerzeichen Q ist jedes erste Punktpaar ein Kontrollpunkt und jedes zweite Punktpaar ein Punkt der Linie, zu dem die Kurve gezeichnet werden soll. Bei

d="M 100 100 Q 200 100 200 200 200 300 300 300"

sind also die Punkte (200,100) und (200,300) Kontrollpunkte und (200,200) und (300,300) Punkte der Kurve.

Dies wirkt anfangs sehr kompliziert und bedarf auch einiger Übung. Je öfter Sie aber solche Kurven zeichnen, desto einfacher wird später auch die Handhabung.

# Kreisbögen

Zum Zeichnen von Kreisbögen benötigen Sie das Steuerzeichen »A«, das für »elliptical arc« steht. Auch hier wird wieder zwischen Groß- und Kleinschreibung unterschieden. So gibt A an, dass mit absoluten Angaben gearbeitet wird, und a bedeutet, dass relative Angaben verwendet werden. Jedoch ist das Zeichnen von Kreis- bzw. Ellipsenbögen in SVG nicht so leicht wie in PHP oder Perl mit der GD-Library.

Nach dem Steuerzeichen erwartet SVG eine bestimmte Anzahl von Werten. Zuerst erwartet es den x- und den y-Radius der Ellipse. Soll der Bogen von einem Kreis stammen, müssen Sie ebenfalls beide Radien angeben, dann aber mit jeweils gleichen Werten. Anschließend folgt die Rotation des Kreises bzw. der Ellipse auf der x-Achse. Erlaubt sind sowohl positive als auch negative Werte. Mit zwei verschiedenen Flags wird die Ausgabe des Bogens beeinflusst. Erlaubt sind jeweils die beiden Werte 0 oder 1. Dazu etwas später mehr. Zum Schluss folgt der Punkt, bis zu dem der Kreisbogen gezeichnet werden soll. Der Startpunkt resultiert aus dem vorherigen Punkt.

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
    <path d="M 100 100 A 100 100 0 0,1 200 200" fill="none" stroke="black" stroke-width="3" />
</svg>

Listing 3.13: Ausgabe eines Kreisbogens in SVG

In der Abbildung 3.13 können Sie den Kreisbogen sehen, der durch das Listing 3.13 erzeugt wird. Zur Verdeutlichung wurden die einzelnen Punkte, zwischen denen der Kreisbogen gezeichnet wird, als graue Kreise dargestellt und die Radien mit einer grauen Linie eingezeichnet.

Ausgabe des Listings 58.11 im Browser (Die grau gezeichneten Elemente wurden nachträglich zur Verdeutlichung hinzugefügt.)
Abbildung 3.13: Ausgabe des Listings 58.11 im Browser (Die grau gezeichneten Elemente wurden nachträglich zur Verdeutlichung hinzugefügt.)

Der Kreisbogen wird durch folgende Anweisung im Attribut d des path-Elements gezeichnet:

A 100 100 0 0,1 200 200

Nach dem Steuerzeichen A folgen die beiden Radien des Kreises, dessen Werte jeweils 100 betragen. Da der Kreis nicht rotiert werden soll, wurde 0 angegeben. Dann folgen die beiden Flags, die auf 0,1 gesetzt wurden. Das Komma ist optional, d. h., Sie können es eintragen, müssen es aber nicht tun. Der Lesbarkeit halber sollten Sie es aber trotzdem notieren. Das erste Flag ist das large-arc-flag und das zweite das sweep-flag. Die beiden letzten Zahlen geben den Endpunkt des Kreisbogens an. Der Startpunkt wurde bereits durch M 100 100 definiert.

Die Flags haben bei dem Zeichnen von Kreisbögen eine ganz besondere Rolle. Stellen Sie sich einfach zwei Kreise vor. Beide Kreise schneiden sich an zwei Punkten: dem Startpunkt des Kreisbogens und dem Endpunkt des Kreisbogens.

Die Schnittpunkte der beiden Kreise bilden den Start- und den Endpunkt des Kreisbogens.
Abbildung 3.14: Die Schnittpunkte der beiden Kreise bilden den Start- und den Endpunkt des Kreisbogens.

Mit den beiden Flags wird nun definiert, welcher der Kreisbögen, die aus den Überschneidungen resultieren, gezeichnet wird. Wird das large-arc-flag auf 1 gesetzt, wird der größere der beiden Kreisbögen gezeichnet, und bei 0 der kleinere. Mit dem Setzen des sweep-flags auf 1 oder 0 wählen Sie den Kreis aus, dessen Kreisbogen gezeichnet wird. In Abbildung 3.15 finden Sie alle vier Möglichkeiten schematisch dargestellt.

Darstellung der vier Möglichkeiten, welcher Kreisbogen gezeichnet wird
Abbildung 3.15: Darstellung der vier Möglichkeiten, welcher Kreisbogen gezeichnet wird

Abbildung 3.14 und Abbildung 3.15 wurden mit SVG erzeugt. Die beiden nachfolgenden Listings sind die Basis dieser Grafiken.

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2002/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">

  <circle cx="200" cy="300" r="100" fill="none" stroke="gray" stroke-width="1" />
  <circle cx="300" cy="200" r="100" fill="none" stroke="gray" stroke-width="1" />
  <circle cx="200" cy="200" r="5" fill="none" stroke="red" stroke-width="1" />
  <circle cx="300" cy="300" r="5" fill="none" stroke="red" stroke-width="1" />
  <text x="140" y="195" font-family="Arial" font-size="12" fill="red">Startpunkt</text>
  <text x="305" y="315" font-family="Arial" font-size="12" fill="red">Endpunkt</text>

</svg>

Listing Schnittpunkte: Schnittpunkte

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2002/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg">

  <circle cx="100" cy="150" r="50" fill="none" stroke="#DDDDDD" stroke-width="1" />
  <circle cx="150" cy="100" r="50" fill="none" stroke="#DDDDDD" stroke-width="1" />
  <text x="50" y="97" font-family="Arial" font-size="10" fill="red">Startpunkt</text>
  <text x="152" y="160" font-family="Arial" font-size="10" fill="red">Endpunkt</text>
  <path d="M 100 100 A 50 50 0 0,0 150 150" fill="none" stroke="black" stroke-width="2" />
  <text x="75" y="210" font-family="Arial" font-size="10" fill="black">large-arc-flag = 0</text>
  <text x="75" y="220" font-family="Arial" font-size="10" fill="black">sweep-flag = 0</text>

  <circle cx="300" cy="150" r="50" fill="none" stroke="#DDDDDD" stroke-width="1" />
  <circle cx="350" cy="100" r="50" fill="none" stroke="#DDDDDD" stroke-width="1" />
  <text x="250" y="97" font-family="Arial" font-size="10" fill="red">Startpunkt</text>
  <text x="352" y="160" font-family="Arial" font-size="10" fill="red">Endpunkt</text>
  <path d="M 300 100 A 50 50 0 0,1 350 150" fill="none" stroke="black" stroke-width="2" />
  <text x="275" y="210" font-family="Arial" font-size="10" fill="black">large-arc-flag = 0</text>
  <text x="275" y="220" font-family="Arial" font-size="10" fill="black">sweep-flag = 1</text>

  <circle cx="100" cy="350" r="50" fill="none" stroke="#DDDDDD" stroke-width="1" />
  <circle cx="150" cy="300" r="50" fill="none" stroke="#DDDDDD" stroke-width="1" />
  <text x="50" y="297" font-family="Arial" font-size="10" fill="red">Startpunkt</text>
  <text x="152" y="360" font-family="Arial" font-size="10" fill="red">Endpunkt</text>
  <path d="M 100 300 A 50 50 0 1,0 150 350" fill="none" stroke="black" stroke-width="2" />
  <text x="75" y="410" font-family="Arial" font-size="10" fill="black">large-arc-flag = 1</text>
  <text x="75" y="420" font-family="Arial" font-size="10" fill="black">sweep-flag = 0</text>

  <circle cx="300" cy="350" r="50" fill="none" stroke="#DDDDDD" stroke-width="1" />
  <circle cx="350" cy="300" r="50" fill="none" stroke="#DDDDDD" stroke-width="1" />
  <text x="250" y="297" font-family="Arial" font-size="10" fill="red">Startpunkt</text>
  <text x="352" y="360" font-family="Arial" font-size="10" fill="red">Endpunkt</text>
  <path d="M 300 300 A 50 50 0 1,1 350 350" fill="none" stroke="black" stroke-width="2" />
  <text x="275" y="410" font-family="Arial" font-size="10" fill="black">large-arc-flag = 1</text>
  <text x="275" y="420" font-family="Arial" font-size="10" fill="black">sweep-flag = 1</text>

</svg>

Listing Kreisbögen: Vier Möglichkeiten für Kreisbögen

Das sweep-flag ist jedoch ein wenig trickreich. Es orientiert sich immer in Zeichenrichtung des Bogens. Die Zeichenrichtung selbst bestimmt sich durch den Start- und den Endpunkt. Es wird also immer vom Start- zum Endpunkt gezeichnet. Stellen Sie sich nun einfach vor, Sie würden auf dem Startpunkt stehen und in Richtung Endpunkt gucken. Setzen Sie dann das sweep-flag auf 0, wird der vom Startpunkt aus gesehen rechte Bogen gezeichnet, Bei 1 wird der vom Startpunkt aus gesehen linke Bogen gezeichnet.

Bis jetzt wurde immer ein Kreisbogen gezeichnet. Was ist aber, wenn Sie einen Kreissektor zeichnen möchten? Dies ermöglichen Ihnen das Steuerzeichen L, mit dem Sie eine Linie zeichnen können, und das Steuerzeichen z, das den Startpunkt und den letzten Punkt mit einer geraden Linie verbindet.

Um nun z.B. ein Viertelsegment eines Kreises zu zeichnen, müssen Sie nach der Definition des Kreisbogens lediglich eine Linie zum Mittelpunkt des Kreises definieren und das Ganze mit z abschließen.

<path d="M 200 100 A 100 100 0 0,1 300 200 L 200 200 z" fill="yellow" stroke="black" stroke-width="2" />

Dieses Beispiel bewegt den Zeichenstift zuerst zum Punkt (200,100). Dann folgt die Definition des Kreisbogens. Die beiden Radien des Kreises erhalten als Wert jeweils 100. Da der Kreis nicht auf der x-Achse rotiert werden soll, wird 0 angegeben. Das large-arc-flag wird auf 0 gesetzt, so dass der kleinere der beiden Kreisbögen gezeichnet wird, und das sweep-flag erhält 1, da vom Startpunkt aus gesehen der linke Kreisbogen gezeichnet werden soll. Der Endpunkt des Kreisbogens ist der Punkt (300,200). Dann wird eine Linie zum Mittelpunkt des Kreises gezogen. Der Mittelpunkt weist die Koordinaten (200,200) auf, und der Pfad wird nun mit z abgeschlossen. Abbildung 3.16 zeigt die Ausgabe dieses Pfades im Browser.

Ein Kreissegment, das mit Hilfe eines Pfades und eines Kreisbogens gezeichnet wurde
Abbildung 3.16: Ein Kreissegment, das mit Hilfe eines Pfades und eines Kreisbogens gezeichnet wurde

# SVG mit PHP

Ähnlich wie die Ausgabe von HTML mit PHP und der echo-Anweisung ist es auch möglich, SVG-Dokumente zu erzeugen und auszugeben. Dies ist natürlich auch mit Perl zu realisieren, und die folgenden Beispiele und Erklärungen lassen sich problemlos in die Perl-Syntax umsetzen.

Gerade SVG eignet sich zur Ausgabe von Diagrammen aufgrund der hohen Skalierbarkeit einer SVG-basierten Grafik. Ich möchte an dieser Stelle auch an die Ausgabe eines Kreisdiagramms mit Hilfe der GD-Library anknüpfen. Wie bereits erwähnt, reicht es bei der GD-Funktion imageArc aus, lediglich den Start- und den Endwinkel anzugeben. Bei SVG sind jedoch der Start- und der Endpunkt erforderlich. Diese Punkte lassen sich mit ein wenig Trigonometrie berechnen. Alles, was dann dafür gebraucht wird, sind der Radius und ein Winkel, der sich aus der Gradzahl ergibt.

Da ich an dieser Stelle nicht in reine Mathematik verfallen möchte, werde ich Ihnen eine vereinfachte Variante darstellen. Sehen Sie sich dazu die Abbildung 3.17 an.

Schematische Darstellung zur Berechnung von Punkten auf einem Kreis
Abbildung 3.17: Schematische Darstellung zur Berechnung von Punkten auf einem Kreis

Wichtig zur Berechnung der Punkte auf der Kreisbahn ist der Winkel a und der Radius des Kreises r. Für jeden beliebigen Punkt auf der Kreisbahn lässt sich ein rechtwinkliges Dreieck zeichnen. Die längste Seite des Dreiecks, also die Gerade, die den Mittelpunkt mit dem Punkt auf der Kreisbahn verbindet, ist die Hypotenuse. Sie entspricht dem Radius des Kreises. Mit Sinus und Kosinus lässt sich nun die Verschiebung des Mittelpunktes auf der x- und auf der y-Achse berechnen.

Die Formel

x = cos(a) × r

berechnet die Verschiebung auf der x-Achse und die Formel

y = sin(a) × r

die Verschiebung auf der y-Achse. Der Winkel a hängt vom Start- und Endwinkel des Kreisbogens ab und bildet sich aus der Differenz dieser beiden Winkel. Der Startwinkel des Kreisbogens beträgt 30 und der Endwinkel 90. Somit ist der Winkel a = 60. Wenn Sie nun den Winkel a = 60 und den Radius r = 175 sowohl in die Formel zum Berechnen von x als auch von y einsetzen, kommen Sie zu folgenden Ergebnissen:

x = cos(60) × 175 = 0,5 × 175 = 87,5  
y = sin(60) × 175 = 0,866 × 175 = 151,5

Abhängig davon, in welchem Quadranten des Kreises der Punkt liegt, müssen Sie x bzw. y addieren oder subtrahieren. Die Überprüfung des Quadranten selbst ist kein größeres Problem. Liegt der Winkel zwischen 0 und 90, ist es der erste bzw. linke untere Quadrant, liegt der Winkel zwischen 90 und 180; ist es der zweite bzw. rechte untere Quadrant usw. Spezialfälle sind jedoch die Winkel 0, 90, 180, 270 und 360. Der Kosinus dieser Winkel ist immer 0, und alles, was mit 0 multipliziert wird, ergibt ebenfalls 0. Diese Bedingungs- bzw. Werteprüfung ufert sehr schnell aus. PHP kann jedoch Abhilfe schaffen. Es hält nämlich eine Funktion bereit, die Gradangaben in das Bogenmaß umrechnet. Dabei können auch negative Werte zurückgegeben werden, und selbst bei Winkeln wie 0, 90, 180, 270 und 360 ergibt der Kosinus der Winkel nicht 0, sondern 1. Diese Funktion ist deg2rad.

double deg2rad(double)

Die Funktion wandelt die übergebene Gradzahl in das Bogenmaß um. Den Rückgabewert können Sie an die Funktionen cos oder sin übergeben. Sie erhalten dann immer einen Wert, den Sie nur addieren müssen.

Das Script aus Listing 3.14 nimmt Werte entgegen, die mit der POST-Methode von einem HTML-Formular übermittelt wurden, und zeichnet dazu passend ein Kreisdiagramm im SVG-Format.

<?php
    /* Variablen definieren */
    $cx = $_POST['cx'];
    $cy = $_POST['cy'];
    $cr = $_POST['cr'];
    $values = $_POST['value'];
    $descriptions = $_POST['description'];
    $colors = $_POST['color'];

    /* Gesamtsumme bilden */
    $value_sum = 0;
    for($i=0; $i<count($values); $i++)
    {
        $value_sum += $values[$i];
    }

    /* Header und SVG-Kopf ausgeben */
    header('Content-Type: image/svg+xml');
    echo "<?xml version=\"1.0\"?>\n";
    echo "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n";
    echo "<svg xmlns=\"http://www.w3.org/2000/svg\">\n";

    /* Start- und Endwinkel setzen */
    $ang_start = 270;
    $ang_end = 270;

    /* Kreissegmente ausgeben */
    for($i=0; $i<count($values); $i++)
    {
        // Berechnung der Winkel
        $ang_start = $ang_end;
        $ang_part = $values[$i] / $value_sum * 360;
        $ang_end = $ang_start + $ang_part;

        // Berechnung des Startpunkts auf der Kreisbahn
        $psx = round(cos(deg2rad($ang_start)) * $cr + $cx);
        $psy = round(sin(deg2rad($ang_start)) * $cr + $cy);

        // Berechnung des Endpunkts auf der Kreisbahn
        $pex = round(cos(deg2rad($ang_end)) * $cr + $cx);
        $pey = round(sin(deg2rad($ang_end)) * $cr + $cy);

        // Ausgabe des Kreissegments in SVG-Notation
        echo "<path d=\"M $cx,$cy L $psx,$psy A $cr,$cr 0 0,1 $pex,$pey Z\" fill=\"$colors[$i]\" stroke=\"black\" stroke-width=\"2\"/>\n";
    }

    /* Startpunkte festlegen */
    $desc_x = $cx + $cr + 50;
    $desc_y = 50;

    /* Bezeichnungen ausgeben */
    for($i=0; $i<count($descriptions); $i++)
    {
        echo "<text x=\"$desc_x\" y=\"$desc_y\" font-size=\"14\" fill=\"$colors[$i]\">$descriptions[$i]$values[$i]</text>\n";
        $desc_y += 18;
    }

    /* SVG-Fuss ausgeben */
    echo '</svg>';
?>

Listing 3.14: Zeichnen eines Kreisdiagramms im SVG-Format mit PHP

Das PHP-Script aus Listing 3.14 erwartet verschiedene Parameter vom aufrufenden HTML-Formular. Das folgende Listing zeigt dessen Aufbau.

<html>
  <head>
    <title>SVG-Kreisdiagramm</title>
  </head>
  <body>
    <h1>SVG-Kreisdiagramm</h1>
    <form action="list3.14.php" method="post">
      <table cellpadding="5" cellspacing="0">
        <tr>
          <th>Bezeichnung</th>
          <th>Wert</th>
          <th>Farbe</th>
        </tr>
        <tr>
          <td><input type="text" name="description[]" value="a"></td>
          <td><input type="text" name="value[]" value="355"></td>
          <td><input type="text" name="color[]" value="#CC0000"></td>
        </tr>
        <tr>
          <td><input type="text" name="description[]" value="b"></td>
          <td><input type="text" name="value[]" value="342"></td>
          <td><input type="text" name="color[]" value="#00CC00"></td>
        </tr>
        <tr>
          <td><input type="text" name="description[]" value="c"></td>
          <td><input type="text" name="value[]" value="782"></td>
          <td><input type="text" name="color[]" value="#0000CC"></td>
        </tr>
        <tr>
          <td><input type="text" name="description[]" value="d"></td>
          <td><input type="text" name="value[]" value="453"></td>
          <td><input type="text" name="color[]" value="#CCCC00"></td>
        </tr>
        <tr>
          <td><input type="text" name="description[]" value="e"></td>
          <td><input type="text" name="value[]" value="535"></td>
          <td><input type="text" name="color[]" value="#CC00CC"></td>
        </tr>
        <tr>
          <td><input type="text" name="description[]" value="f"></td>
          <td><input type="text" name="value[]" value="333"></td>
          <td><input type="text" name="color[]" value="#00CCCC"></td>
        </tr>
      </table>
      <table cellpadding="5" cellspacing="0">
        <tr>
          <th>x-Position</th>
          <th>y-Position</th>
          <th>Radius</th>
        </tr>
        <tr>
          <td><input type="text" name="cx" value="200"></td>
          <td><input type="text" name="cy" value="200"></td>
          <td><input type="text" name="cr" value="175"></td>
        </tr>
      </table>
      <input type="submit" value="Anzeigen"> <input type="reset" value="Zur&uuml;cksetzen">
    </form>
  </body>
</html>

Listing 3.14 - Formular: Das HTML-Formular zur Übermittlung der Daten

Die ersten drei Variablen $cx, $cy und $cr erhalten den Mittelpunkt des Kreises und den Durchmesser. Zu den einzelnen Kreissegmenten werden sowohl eine Bezeichnung als auch ein Wert und eine Farbe übergeben, in der das Segment dargestellt werden soll. Diese werden jeweils als Array übergeben. Die Werte werden im Array $values, die Bezeichnungen im Array $descriptions und die Farben im Array $color gespeichert.

Im nächsten Schritt wird die Summe der einzelnen Werte des Arrays $values gebildet und in der Variablen $value_sum gespeichert. Dieser Wert wird benötigt, um später die Winkel der Kreisbögen zu errechnen.

Dann wird der konstante Teil des SVG-Dokuments ausgegeben: zuerst der MIME-Typ des Dokuments (image/svg+xml) und anschließend die XML-Processing-Instruction, die DTD und das Start-Tag des Wurzelelements svg.

Danach werden der Startwinkel $ang_start und der Endwinkel $ang_end festgelegt. Beide werden zu Beginn auf den Wert 270 gesetzt. Dies führt dazu, dass mit dem Zeichnen der Kreissegmente nicht bei 3 Uhr, sondern bei 12 Uhr, also oben, begonnen wird.

Die nun folgende for-Schleife arbeitet nun jeden Wert des Arrays $values einzeln ab, erzeugt den entsprechenden Pfad und sendet das Ganze mit einer echo-Anweisung an den Browser. Diese Schleife wird durchlaufen, solange Elemente im Array $values enthalten sind. Zu Beginn jedes Schleifendurchlaufs wird der Startwinkel auf den Endwinkel gesetzt. Der Grund ist, dass Sie somit pro Durchlauf immer nur den neuen Endwinkel berechnen müssen, da der letzte Endwinkel dem neuen Startwinkel entspricht. Dann wird der neue Endwinkel berechnet. Dafür wird ein ganz normaler Dreisatz verwendet, denn die Summe aller Werte des Arrays $values verhält sich zum 360°-Winkel wie der aktuelle Wert zum Winkel a. Der Winkel a wird in diesem Fall dann in der Variablen $ang_part gespeichert. Das Ergebnis wird dann zu $ang_start addiert und anschließend in $ang_end gespeichert. $ang_end enthält nun den neuen Endwinkel. Im nächsten Schritt erfolgt die Berechnung des Start- und Endpunkts. Die Koordinaten x und y der Punkte werden dabei getrennt berechnet, da einmal Sinus und einmal Kosinus verwendet werden muss. Die Winkel werden dabei in das Bogenmaß umgewandelt und an die Funktion sin bzw. cos übergeben. Das Ergebnis wird dann mit dem Radius multipliziert, und es wird entweder $cx oder $cy hinzuaddiert.

$psx = round(cos(deg2rad($ang_start)) * $cr + $cx);  
$psy = round(sin(deg2rad($ang_start)) * $cr + $cy);  
$pex = round(cos(deg2rad($ang_end)) * $cr + $cx);  
$pey = round(sin(deg2rad($ang_end)) * $cr + $cy);

$psx und $psy enthalten nun die Koordinaten für den Startpunkt und $pex und $pey die Koordinaten für den Endpunkt des Kreissegments. Am Ende der Schleife werden dann die errechneten Koordinaten in das vorgefertigte path-Konstrukt eingefügt und ausgegeben.

Der nun folgende Schritt gibt lediglich die Bezeichnungen der Kreissegmente mit Werten in der entsprechenden Farbe unterhalb des Kreises aus. Am Ende des Scripts wird dann noch das Ende-Tag des svg-Elements ausgegeben.

In Abbildung 3.18 können Sie die Ausgabe des Scripts mit den Werten aus Tabelle 3.1 sehen. Der Mittelpunkt des Kreises wurde auf (200,200) festgesetzt und der Radius auf 175.

Bezeichnung Wert Farbe
Segment a 355 #CC0000
Segment b 342 #00CC00
Segment c 782 #0000CC
Segment d 453 #CCCC00
Segment e 535 #CC00CC
Segment f 333 #00CCCC

Tabelle 3.1: Werte für das Kreisdiagramm aus Abbildung 3.18

Ausgabe des PHP-Scripts aus Listing 3.14 mit den Werten aus der Tabelle 3.1
Abbildung 3.18: Ausgabe des PHP-Scripts aus Listing 3.14 mit den Werten aus der Tabelle 3.1

# Zusammenfassung

  • SVG ist ein auf Vektoren basierendes Grafik-Format und insbesondere zum Einsatz im Internet entwickelt worden.
  • SVG wurde mit XML definiert und unterliegt den gleichen strikten Regeln.
  • Texte werden mit dem text-Element ausgegeben.
  • Grundformen wie Linien, Kreise und Rechtecke werden mit den Elementen line, circle und rect ausgegeben.
  • Mit dem Attribut fill können Sie eine Füllfarbe für eine Form bestimmen und mit stroke und stroke-width eine Rahmenfarbe und -dicke.
  • linearGradient und radialGradient ermöglichen einen linearen oder radialen Farbverlauf. Mit stop-Elementen werden die einzelnen Farben des Verlaufs definiert.
  • Pfade ermöglichen weitaus komplexere Formen als Linien, Rechtecke und Kreise. Dadurch sind auch Vielecke oder Kreissegmente möglich. Selbst Bézier-Kurven lassen sich schnell und einfach definieren.
  • SVG-Grafiken können sowohl mit PHP als auch mit Perl dynamisch erzeugt werden.

# Fragen und Übungen

  1. Wie lautet der MIME-Typ einer SVG-Grafik?
  2. Mit welchem Element lässt sich eine SVG-Grafik in ein HTML-Dokument einbinden?
  3. Definieren Sie einen linearen Farbverlauf mit der Farbe #FFCC99 bei 0 % und #663300 bei 100 %. Zeichnen Sie ein Rechteck, das den definierten Farbverlauf als Füllfarbe erhält.
  4. Zeichnen Sie einen beliebigen Kreissektor, und füllen Sie ihn mit einem Farbverlauf Ihrer Wahl.
  5. Setzen Sie das PHP-Script aus Listing 3.14 dieses Kapitels in ein Perl-Script um. Dieses Perl-Script soll ebenfalls Daten von einem HTML-Formular entgegennehmen und darauf aufbauend ein Kreisdiagramm in SVG erzeugen. Beachten Sie dabei Folgendes: Im HTML-Dokument müssen Sie bei den Werten für die name-Attribute der Eingabefelder die eckigen Klammern [ und ] entfernen. Außerdem kennt Perl die Funktion round nicht. Ignorieren Sie diese, da Sie in Perl keine ähnliche Funktion mit der gleichen Aufgabe benötigen. Außerdem kennt Perl keine Funktion, um Grad in Bogenmaß umzurechnen. Eine entsprechende Subroutine müssen Sie selbst definieren. Diese lautet:
    sub deg2rad
    {
        my $deg = shift;
        $rad = ($deg * 3.1415926535897932) / 180;
        return $rad;
    }