# 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.
Abbildung 3.1: Die Grafik im Originalzustand. Es ist nicht erkennbar, ob sie pixel-oder vektorbasiert ist.
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.
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.
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
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
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
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
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
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
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
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 werdenH
,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, undh
, 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 undv
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 undq
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.
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.
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.
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.
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.
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.
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ü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
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
undrect
ausgegeben. - Mit dem Attribut
fill
können Sie eine Füllfarbe für eine Form bestimmen und mitstroke
undstroke-width
eine Rahmenfarbe und -dicke. linearGradient
undradialGradient
ermöglichen einen linearen oder radialen Farbverlauf. Mitstop
-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
- Wie lautet der MIME-Typ einer SVG-Grafik?
- Mit welchem Element lässt sich eine SVG-Grafik in ein HTML-Dokument einbinden?
- 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. - Zeichnen Sie einen beliebigen Kreissektor, und füllen Sie ihn mit einem Farbverlauf Ihrer Wahl.
- 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 Funktionround
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; }