{"id":55001132,"date":"2018-06-01T00:00:00","date_gmt":"2020-05-13T21:19:44","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1132"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"SVG_als_Grafikkomponente","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/","title":{"rendered":"SVG als Grafikkomponente"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg06.met.vgwort.de\/na\/1e321b90619e4317aab6c90914dcb8dc\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>In zwei Beitr&auml;gen rund um das Thema &#8220;&#8220;HTML5 als Grafikkomponente&#8220;&#8220; erfuhren Sie, wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen. &uuml;ber eine andere Schnittstelle, n&auml;mlich SVG, l&auml;sst sich dasselbe erreichen, wobei hier nicht Pixel-, sondern Vektorgrafiken erzeugt werden, die deutlich mehr Interaktivit&auml;t zulassen und nachtr&auml;glich bearbeitbar sind. <\/b><\/p>\n<h2>Referenz<\/h2>\n<p>Die Ausf&uuml;hrungen dieses Beitrags setzen jene aus dem Artikel <b>HTML5 als Grafikkomponente<\/b> in der Ausgabe <b>01\/2018<\/b> fort. Dort sind die Grundlagen zum Einsatz des <b>Webbrowser-Steuerelements<\/b> im Verein mit <b>HTML5<\/b> beschrieben, auf die hier deshalb nicht noch einmal eingegangen wird.<\/p>\n<h2>SVG als Alternative zu HTML5<\/h2>\n<p>&uuml;ber <b>HTML5<\/b> k&ouml;nnen Sie unter Access im Webbrowser-Steuerelement Bilder anlegen, indem Sie dessen zugrundeliegendes <b>HTML<\/b>-Objektmodell steuern. Als Ergebnis erhalten Sie eine Pixelgrafik als Summe der Grafikoperationen, deren Schritte sich nicht mehr r&uuml;ckg&auml;ngig machen oder bearbeiten lassen.<\/p>\n<p>Lediglich das Abspeichern als Bilddatei oder im <b>BLOB<\/b>-Feld einer Tabelle steht Ihnen dann noch offen. Ganz anders bei <b>SVG<\/b>, wo die Grafik im Vektorformat entsteht, auf deren einzelne Elemente jederzeit zugegriffen werden kann. Solche Grafiken rendert der Browser dann zur Laufzeit.<\/p>\n<p>Es verwundert eigentlich, dass diese flexible L&ouml;sung noch von niemand aufgegriffen und umgesetzt wurde &#8211; dachte ich! Tats&auml;chlich findet, w&auml;hrend ich dies zu Papier bringe, in Wien die zweite <b>Access-DevCon<\/b> statt, eine internationale Entwicklerkonferenz, welche unter anderem Vortr&auml;ge von Experten zu verschiedenen Themenstellungen rund um Access anbietet. Und der litauische Entwickler <b>Alexandru Tofan<\/b>, ein bisher weitgehend unbeschriebenes Blatt, demonstriert dort ebenfalls seine L&ouml;sungen zum Einsatz von <b>SVG<\/b> als Grafik-Engine. Ich bin gespannt, welche &auml;hnlichkeit seine Ausf&uuml;hrungen zu den hier ganz unabh&auml;ngig vorgestellten haben werden, falls sie ver&ouml;ffentlicht werden&#8230;<\/p>\n<p>Der Hauptgrund daf&uuml;r, dass eine Implementierung von <b>SVG<\/b> im <b>Webbrowser Control <\/b>noch nicht stattfand, ist wohl darin zu suchen, dass Microsoft dem <b>Internet Explorer<\/b> erst sp&auml;t den Umgang mit diesem Format beibrachte. Und da das Webbrowser-Steuerelement im Rohzustand nur die Version <b>7<\/b> des Browsers emuliert, welche noch kein <b>SVG<\/b> kannte, laufen die sehr wohl im <b>HTML<\/b>-Objektmodell enthaltenen zugeh&ouml;rigen Methodenaufrufe ins Leere. Erst die Modifikation des Webbrowsers &uuml;ber die VBA-Routine <b>PrepareBrowser<\/b>, die, wie im oben angef&uuml;hrtem Beitrag, schon mehrmals erl&auml;utert wurde, l&auml;sst ihn im Gewand des <b>IE 11<\/b> erscheinen. Danach akzeptiert er anstandslos auch alle <b>SVG<\/b>-Methoden.<\/p>\n<h2>SVG als Format<\/h2>\n<p><b>SVG<\/b> (<b>Scalable Vector Graphics<\/b>) ist an sich ein auf <b>XML<\/b> basierendes Dateiformat, welches seit dem Jahr 2001 existiert und kontinuierlich weiterentwickelt wurde. Dateien mit der Endung <b>.svg<\/b> k&ouml;nnen etwa mit dem Open Source-Programm <b>Inkscape<\/b> angezeigt oder erstellt werden, welches sich fast schon zum Standard gemausert hat. Aber auch andere Vektorzeichenprogramme beherrschen meist den Export in dieses Format. <\/p>\n<p>Inzwischen hat es sich aber vor allem im Web als wichtigste Schnittstelle zur Anzeige von Vektorgrafiken etabliert. Der Vorteil von Vektorgrafiken gegen&uuml;ber Pixelbildern ist ja die verlustfreie Skalierbarkeit, denn solche Grafiken werden grunds&auml;tzlich erst zur Laufzeit beim Rendern in Pixel &uuml;bersetzt. Bei technischen Zeichnungen, Organigrammen, Charts oder Karten ist es deshalb das Format der Wahl.<\/p>\n<p>Einst ging es in erster Linie um die Anzeige solcher <b>SVG<\/b>-Grafikdateien, f&uuml;r die bis dahin nur ein spezielles in die Website eingebettetes <b>Adobe<\/b>-ActiveX-Steuerelement infrage kam. Doch seit der Implementierung direkt im Browser kam auch die dynamische Steuerung der einzelnen Elemente der Grafik hinzu.<\/p>\n<p>So lassen sich <b>SVG<\/b>-Grafiken nun auch ohne jeglichen Bezug zu einer Datei etwa &uuml;ber <b>Javascript<\/b> anlegen und beeinflussen. Und gl&uuml;cklicherweise hat Microsoft im <b>HTML<\/b>-Objektmodell des Internet Explorers alle Elemente von <b>Javascript<\/b> nach <b>COM<\/b> &uuml;bersetzt, womit auch unter VBA Zugriff auf die entsprechenden Klassen und Methoden besteht, ohne dass Sie sich mit einer anderen Skriptsprache besch&auml;ftigen m&uuml;ssen.<\/p>\n<p>Die <b>SVG<\/b>-Grafiken stellen nun einfach eine Folge von Grafikanweisungen dar, die im <b>XML<\/b>-Format abgelegt sind. Der Browser interpretiert diese und rendert sie anhand der &uuml;bergebenen Parameter. Daf&uuml;r gibt es das neue <b>Tag<\/b> <b>svg<\/b>, welches allerdings nur dann korrekt interpretiert wird, wenn ein bestimmtes <b>Namespace<\/b>-Attribut mit <b>xmlns<\/b> hinzugef&uuml;gt wird:<\/p>\n<pre>&lt;svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\"&gt; (Inhalt) &lt;svg&gt;<\/pre>\n<p>Innerhalb dieses <b>Tags<\/b> befinden sich dann die Anweisungen. Das k&ouml;nnen Linien sein, Rechtecke, Kreise, Ellipsen, Polygone, Bezier-Kurven, Text, F&uuml;llungen, Pixeldaten oder Verweise auf Bilddateien. All diese Elemente k&ouml;nnen &uuml;ber Attribute mit diversen Parametern versehen werden, die deren Gestalt bestimmen. Der Clou aber sind mehrere Grafikfilter, die Sie auf einfache Weise anlegen und nach Belieben auf diese Elemente anwenden k&ouml;nnen. So kann etwa gef&uuml;llter Kreis mit einem <b>Blur<\/b>-Filter verwaschen werden, dessen Parameter Sie ebenfalls steuern k&ouml;nnen.<\/p>\n<p>Eine einfache Line erzeugen Sie etwa &uuml;ber dieses Konstrukt:<\/p>\n<pre>&lt;svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\r\n     height=\"300\" width=\"500\"&gt;\r\n&lt;line x1=\"0\" y1=\"0\" x2=\"200\" y2=\"200\"\r\n     style=\"stroke:black;stroke-width:2\"\/&gt;\r\n&lt;\/svg&gt;<\/pre>\n<p>Hier sind dem <b>svg<\/b>-Tag gleich die Attribute <b>width<\/b> und <b>height<\/b> zugeordnet, die die Abmessungen der Grafikfl&auml;che (<b>500&#215;300 <\/b>Pixel) festlegen. Die Linie erzeugen Sie &uuml;ber das <b>line<\/b>-Tag. Die Koordinatenpunkte der Linie sind &uuml;ber die Werte der Attributparameter <b>x1<\/b>, <b>y1<\/b>, <b>x2<\/b>, <b>y2<\/b> definiert. Das Aussehen der Linie bestimmt nun das <b>style<\/b>-Attribut, welches seinerseits eine Menge weiterer Definitionen aufnehmen kann, die sich aus dem Fundus der <b>HTML-Styles <\/b>ableiten, die Sie eventuell auch abseits von <b>SVG<\/b> kennen. So gibt <b>stroke<\/b> etwa an, welche Farbe die Line haben soll, was hier auf Schwarz (<b>black<\/b>) festgelegt ist.<\/p>\n<p>Nat&uuml;rlich sind hier auch beliebige andere &uuml;ber Hexadezimalwerte definierte Farben m&ouml;glich, wie <b>#A0A0A0<\/b>, oder &uuml;ber die <b>rgb<\/b>-Funktion ermittelte: <\/p>\n<pre>stroke:rgb(40,20,105)<\/pre>\n<p>Die Breite der Linie steht schlie&szlig;lich im Parameter <b>stroke-width<\/b> (2 Pixel).<\/p>\n<p>&uuml;brigens k&ouml;nnen Sie innerhalb des <b>svg<\/b>&#8211;<b>Tags<\/b> wiederum ein oder mehrere <b>svg-Tags<\/b> einbetten, was zu verschachtelten Zeichenfl&auml;chen f&uuml;hrt.<\/p>\n<h2>SVG dynamisch unter VBA erzeugen<\/h2>\n<p>Der Witz am <b>HTML-Objektmodell <\/b>ist aber ja, dass Sie den HTML-Text nicht unbedingt per String-Verkettung generieren m&uuml;ssen, sondern sich der passenden HTML-Klassen bedienen, deren Eigenschaften Sie dann einstellen. So gibt es zur Linie etwa das Element <b>SVGLineElement<\/b>, welches Sie so erzeugen:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>oDoc<span style=\"color:blue;\"> As <\/span>HTMLDocument\r\n<span style=\"color:blue;\">Dim <\/span>oSVGLine<span style=\"color:blue;\"> As <\/span>SVGLineElement\r\n<span style=\"color:blue;\">Set<\/span> oDoc = WebCtl.Object.Document \r\n<span style=\"color:blue;\">Set<\/span> oSVGLine = oDoc.createElementNS( _\r\n                \"http:\/\/www.w3.org\/2000\/svg\", \"line\")<\/pre>\n<p>Das HTML-Dokument <b>oDoc<\/b> erhalten Sie hier &uuml;ber die <b>Document<\/b>-Eigenschaft des Webbrowser-Steuerelements <b>WebCtl<\/b>. Normalerweise reicht die Methode <b>createElement<\/b> aus, um auf der Website ein neues HTML-Element zu erzeugen. Hier allerdings wird die Alternative <b>createElementNS<\/b> ben&ouml;tigt, weil auf den <b>SVG-Namespace<\/b> Bezug genommen werden muss, damit der Webbrowser erkennt, um welches <b>line<\/b>-Element es sich genau handelt.<\/p>\n<p>So erzeugt stellen Sie nun die Eigenschaften des <b>SVGLineElements<\/b> ein:<\/p>\n<pre>oSVGLine.x1 = 0: oSVGLine.y1 = 0\r\noSVGLine.x2 = 200: oSVGLine.y2 = 200<\/pre>\n<p>Leider sind das auch schon alle Eigenschaften, die diese Klasse bei Microsoft direkt anbietet. Alle anderen m&uuml;ssen Sie &uuml;ber die Methode <b>setAttribute<\/b> belegen:<\/p>\n<pre>oSVGLine.setAttribute \"stroke\", \"black\"\r\noSVGLine.setAttribute \"stroke-width\", \"2\"<\/pre>\n<p>Die Methode <b>setAttribute<\/b> finden Sie im Objektkatalog nicht unter der Klasse <b>SVGLineElement<\/b>, und trotzdem funktioniert sie. Das liegt daran, dass sich ein <b>SVGLineElement<\/b> versteckt vom allgemeineren <b>IHTMLElement<\/b> ableitet, welches diese Methode aufweist. <\/p>\n<h2>SVG-Grafik-Beispiel<\/h2>\n<p>Das Formular <b>frmSVGTest<\/b> der Demodatenbank vereint die wesentlichen Techniken, die f&uuml;r den Einsatz von <b>SVG<\/b> als Grafikgenerator zum Zuge kommen. Bild 1 zeigt es zur Laufzeit, nachdem auf die Schaltfl&auml;che <b>SVG erzeugen<\/b> geklickt wurde.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_03\/frmSVGTest_Simple.png\" alt=\"Eine im Webbrowser-Steuerelement per VBA generierte SVG-Grafik\" width=\"500\" height=\"439,0805\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Eine im Webbrowser-Steuerelement per VBA generierte SVG-Grafik<\/span><\/b><\/p>\n<p>Das Formular enth&auml;lt lediglich ein Webbrowser-Steuerelement mit dem Namen <b>ctlIE<\/b>, dessen Steuerelementinhalt im Entwurf auf <b>&#8222;=about:blank&#8220;<\/b> festgelegt ist und einen Button, der die Anlage der <b>SVG<\/b>-Grafik ausl&ouml;st. Damit das Webbrowser-Control mit <b>SVG<\/b> umgehen kann, muss zuvor die Routine <b>PrepareBrowser<\/b> des Moduls <b>mdlWebControl<\/b> aufgerufen worden sein, welche Einstellungen der Registry modifiziert, wie dies bereits ersch&ouml;pfend in den Beitr&auml;gen zu <b>HTML5<\/b> erl&auml;utert wurde.<\/p>\n<p>Der Klick auf den Button <b>cmdCreate<\/b> l&auml;sst die Ereignisprozedur in Listing 1 ablaufen. Hier kommt es zun&auml;chst zum Aufruf der Hilfsroutine <b>NavigateBlank<\/b>, die weiter unten abgebildet ist. Sie stellt per <b>Navigate2<\/b>-Methode sicher, dass im Webbrowser <b>ctlIE<\/b> ein leeres Dokument angelegt ist. Nachdem dieses erfolgreich fertiggestellt ist, was die <b>Do-Loop<\/b>-Schleife mit Abfrage der <b>ReadyState<\/b>-Eigenschaft kontrolliert, kann die modulweit deklarierte Objektvariable <b>oDoc<\/b> auf dieses Dokument gesetzt werden. Das <b>WithEvents<\/b> in der Deklaration erm&ouml;glicht, dass auf Ereignisse der gesamten Website, wie Mausklicks, reagiert werden kann.<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents oDoc<span style=\"color:blue;\"> As <\/span>HTMLDocument\r\n<span style=\"color:blue;\">Private <\/span>WithEvents oSVG<span style=\"color:blue;\"> As <\/span>SVGSVGElement\r\n<span style=\"color:blue;\">Private <\/span>oEvent<span style=\"color:blue;\"> As <\/span>IHTMLEventObj\r\n<span style=\"color:blue;\">Private Sub <\/span>cmdCreate_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>oSVGElement<span style=\"color:blue;\"> As <\/span>SVGCircleElement\r\n     <span style=\"color:blue;\">Dim <\/span>oElement<span style=\"color:blue;\"> As <\/span>IHTMLElement\r\n     \r\n     NavigateBlank\r\n     oDoc.head.innerHTML = \"&lt;head&gt;&lt;meta http-equiv=\"\"X-UA-Compatible\"\"\/&gt;&lt;\/head&gt;\"\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> oSVG = oDoc.createElementNS(\"http:\/\/www.w3.org\/2000\/svg\", \"svg\")\r\n     <span style=\"color:blue;\">With<\/span> oSVG\r\n         .Width.baseVal.Value = 300\r\n         .Height.baseVal.Value = 250\r\n         .Style.backgroundColor = \"#e0e0e0\"\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> oSVGElement = oDoc.createElementNS(\"http:\/\/www.w3.org\/2000\/svg\", \"circle\")\r\n     <span style=\"color:blue;\">With<\/span> oSVGElement\r\n         .setAttribute \"id\", \"Kreis\"\r\n         .setAttribute \"cx\", \"50\"\r\n         .setAttribute \"cy\", \"50\"\r\n         .setAttribute \"r\", \"40\"\r\n         .setAttribute \"stroke\", \"darkblue\"\r\n         .setAttribute \"stroke-width\", \"4\"\r\n         .setAttribute \"fill\", \"red\"\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     oSVG.appendChild oSVGElement\r\n     \r\n     oDoc.body.appendChild oSVG\r\n     <span style=\"color:blue;\">Debug.Print<\/span> oDoc.all(0).outerHTML\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Sub <\/span>NavigateBlank()\r\n     ctlIE.Object.Navigate2 \"about:blank\"\r\n     Do\r\n         DoEvents\r\n     <span style=\"color:blue;\">Loop<\/span> Until ctlIE.Object.ReadyState = 4\r\n    <span style=\"color:blue;\">Set<\/span> oDoc = ctlIE.Object.Document\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Der wesentliche Code-Teil des Formulars frmSVGTest erzeugt im Click-Ereignis die Grafik<\/span><\/b><\/p>\n<p>Im <b>Header<\/b> des Dokuments muss anschlie&szlig;end eine <b>meta<\/b>-Eigenschaft hinterlegt werden, die <b>X-UA-Compatible<\/b> lautet, damit der Browser die <b>SVG<\/b>-Anweisungen auch umsetzt. Dies geschieht durch Beschreiben des Tags &uuml;ber die Methode <b>innerHTML<\/b> des <b>head<\/b>-Objekts.<\/p>\n<p>Und nun kann bereits die <b>SVG<\/b>-Zeichenfl&auml;che im Dokument mit <b>createElementNS<\/b> angelegt werden, wobei hier das Element-Tag <b>svg<\/b> als String &uuml;bergeben wird. Das Element landet in der Objektvariablen <b>oSVG<\/b> vom Typ <b>SVGSVGElement<\/b>, die ebenfalls im Kopf des Moduls mit <b>WithEvents<\/b> deklariert ist, damit auf Ereignisse speziell der Zeichenfl&auml;che reagiert werden kann.<\/p>\n<p>Die Zeichenfl&auml;che ist damit zwar erstellt, hat bislang jedoch noch keine definierten Abmessungen. Dies holt der folgende <b>With<\/b>-Block auf die Objektvariable nach.  Um die Breite des <b>svg<\/b>-Elements einzustellen, k&ouml;nnen Sie zwei Methoden einsetzen. Die eine ist das Setzen des <b>width<\/b>-Attributs &uuml;ber die Methode <b>setAttribute<\/b>, die andere die Nutzung der eingebauten Eigenschaft <b>Width<\/b> der Objektklasse. Letztes geschieht hier. Allerdings handelt es sich bei <b>Width<\/b> nicht etwa um einen Integer-Wert, sondern um einen speziellen zusammengesetzten <b>SVG<\/b>-Datentyp, dessen Eigenschaft <b>baseVal.Value<\/b> verwendet werden muss. Sie bekommt den Wert <b>300<\/b> Pixel zugewiesen. &auml;hnliches erfolgt f&uuml;r die H&ouml;he der Fl&auml;che und <b>Height<\/b>. Und dann erh&auml;lt die Zeichenfl&auml;che noch eine Hintergrundfarbe, die &uuml;ber das <b>Style<\/b>-Attribut <b>backgroundColor<\/b> mit einem hexadezimalen Grau-Wert versehen wird. Das <b>SVG<\/b>-Objekt wird erst in das Dokument geschrieben und damit sichtbar, wenn es am Ende der Routine &uuml;ber <b>appendChild<\/b> an den <b>Body<\/b> <b>oDoc.body <\/b>angeh&auml;ngt wird. Zuvor muss jedoch noch der <b>SVG<\/b>-Kreis erzeugt und an das <b>SVG<\/b>-Objekt selbst angeh&auml;ngt sein.<\/p>\n<p>Deshalb generiert <b>createElementNS<\/b> nun ein Element <b>circle<\/b> und weist es als Objekt der Variablen <b>oSVGElement<\/b> vom <b>MSHTML<\/b>-Typ <b>SVGCircleElement<\/b> zu. Sie verweist nun auf ein abstraktes Kreis-Objekt, dessen Eigenschaften erst noch eingestellt werden m&uuml;ssen. Der folgende <b>With<\/b>-Block mit den <b>setAttribute<\/b>-Anweisungen &uuml;bernimmt dies. Die Mittelpunktkoordinate wird mit <b>cx<\/b> und <b>cy<\/b> festgelegt, der Radius in <b>r<\/b> &#8211; ohne dezidierte Angabe von Einheiten geht der Browser dabei von Pixeln aus. Dem Element wird ein eindeutiger Bezeichner <b>Kreis<\/b> &uuml;ber die <b>id<\/b> spendiert, damit es sp&auml;ter identifizierbar und damit sogar auch dynamisch bearbeitbar ist. Die Farbe des Kreises steht in <b>stroke<\/b>, die Linienbreite in <b>stroke-width<\/b> und die F&uuml;llfarbe im Attribut <b>fill<\/b>. Das Kreiselement wird schlie&szlig;lich mit <b>appendChild<\/b> an das <b>SVG<\/b>-Fl&auml;chenelement <b>oSVG<\/b> angeh&auml;ngt, welches selbst dann in den <b>Body<\/b> geschrieben wird. Ab nun ist die Grafik tats&auml;chlich sichtbar.<\/p>\n<p>Obwohl wir nur mit <b>MSHTML<\/b>-Objekten hantieren und keinerlei String-Bearbeitung einsetzen, &uuml;bersetzt sich das Ganze automatisch in g&uuml;ltigen <b>HTML<\/b>-Text. Die <b>Debug.Print<\/b>-Anweisung verdeutlicht, was dabei herauskommt und gibt im VBA-Direktfenster diesen String aus, der hier der &uuml;bersicht halber mit Einr&uuml;ckungen formatiert wurde:<\/p>\n<pre>&lt;html&gt;\r\n   &lt;head&gt;&lt;meta http-equiv=\"X-UA-Compatible\"\"\/&gt;&lt;\/head&gt;\r\n     &lt;body&gt;\r\n       &lt;svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\"\r\n         style=\"background-color: rgb(224, 224, 224);\"\r\n         width=\"300\" height=\"250\"&gt;\r\n           &lt;circle id=\"Kreis\" \r\n             fill=\"red\" stroke=\"darkblue\" stroke-width=\"4\"\r\n             cx=\"50\" cy=\"50\" r=\"40\" \/&gt;\r\n       &lt;\/svg&gt;\r\n     &lt;\/body&gt;\r\n&lt;\/html&gt;<\/pre>\n<h2>SVG Knowledgebase<\/h2>\n<p>Es liegt weit au&szlig;erhalb des Radius dieses Beitrags, alle <b>SVG<\/b>-Elemente mit ihren Parametern darzustellen. Empfehlung: Schauen Sie sich etwa auf der deutschen Seite <b>SELFHTML<\/b> um, die unter der Rubrik <b>SVG<\/b> mit vielen Beispielen ersch&ouml;pfend Auskunft gibt. Dort sind die m&ouml;glichen Elemente und ihre Attribute gut erl&auml;utert. Das Vorgehen zur &uuml;bersetzung der <b>HTML-Tags<\/b> nach VBA ist dann immer dasselbe. Sie erzeugen ein Element &uuml;ber die Funktion <b>createElementNS<\/b> unter Angabe des Element-Tags, weisen es einer Objektvariablen zu, die den generellen Typ <b>SVGElement<\/b> haben kann &#8211; oder auch schlicht <b>Object<\/b> -, und setzen dessen Eigenschaften am besten &uuml;ber <b>setAttribute<\/b>-Anweisungen innerhalb eines <b>With<\/b>-Blocks.<\/p>\n<h2>SVG-Filter<\/h2>\n<p>Das Formular <b>frmSVGTest<\/b> enth&auml;lt noch eine weitere Schaltfl&auml;che <b>Komplexes SVG<\/b>, deren Bet&auml;tigung zur Grafik in Bild 2 f&uuml;hrt. Hier sind genau zwei SVG-Elemente angelegt, n&auml;mlich ein gelber Kreis mit gr&uuml;ner Umrandung und das Bild einer Tulpe aus einer JPG-Datei. Auf das Bild wird aber ein Weichzeichnenfilter angewandt, auf den Kreis ein Turbulenzfilter. Hier kommen neue Techniken ins Spiel.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_03\/frmSVGTest_Complex.png\" alt=\"Einsatz von Filtern f&uuml;r die komplexere SVG-Grafik per VBA\" width=\"500\" height=\"439,0805\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Einsatz von Filtern f&uuml;r die komplexere SVG-Grafik per VBA<\/span><\/b><\/p>\n<p>Das Prinzip ist allerdings das gleiche, wie im vorigen Beispiel. Ein <b>SVG<\/b>-Element wird angelegt und an den <b>Body<\/b> des &uuml;ber <b>about:blank<\/b> erzeugten Dokuments geh&auml;ngt. Das Vorgehen, um die Bilddatei in die Grafik zu bekommen, ist hier nicht trivial. Zwar k&ouml;nnte man das Attribut <b>href<\/b> des <b>image<\/b>-Elements mit dem absoluten Pfad zur Datei belegen, doch beim Verschieben der Datenbank und der Bilddatei t<b>ulpe.jpg<\/b> in ein anderes Verzeichnis w&auml;re der Bezug verloren. Deshalb wird aus der Bilddatei ein sogenanntes bin&auml;res <b>data-URI<\/b> erzeugt und dessen Inhalt dem Bildelement unmittelbar &uuml;bergeben. Hintergrund daf&uuml;r ist zus&auml;tzlich, dass sich so auch Dateien, die etwa in <b>OLE-Feldern<\/b> von in Tabellen abgespeichert sind, ebenfalls zur Ansicht bringen lassen. Das <b>data-URI <\/b>kommt dabei als <b>base64<\/b>-kodierter String in das Dokument. Diese Funktionalit&auml;t kam bereits im fr&uuml;heren Beitrag zum <b>Zeichnen und Malen mit HTML5<\/b> zum Einsatz.<\/p>\n<p>Einen Teil der Ereignisprozedur <b>cmdCreateComplex_Click<\/b> zeigt Listing 2. Die Bilddatei wird zuerst mit der <b>Open<\/b>-Anweisung in das Byte-Array <b>bin<\/b> eingelesen. Dann wird das leere <b>SVG<\/b>-Bildelement &uuml;ber das Tag <b>image<\/b> erzeugt.<\/p>\n<pre>...\r\n     Open CurrentProject.Path & \"\\tulpe.jpg\" For Binary Access Read<span style=\"color:blue;\"> As <\/span>#1\r\n     ReDim bin(LOF(1) - 1)\r\n     Get #1, , bin\r\n     Close #1\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> oSVGElement = oDoc.createElementNS(\"http:\/\/www.w3.org\/2000\/svg\", \"image\")\r\n     <span style=\"color:blue;\">With<\/span> oSVGElement\r\n         .setAttribute \"id\", \"dataimage\"\r\n         .setAttribute \"width\", \"200\"\r\n         .setAttribute \"height\", \"200\"\r\n         .setAttribute \"href\", \"data:image\/jpeg;base64,\" & EncodeBase64(bin)\r\n         .setAttribute \"crossOrigin\", \"anonymous\"\r\n         .setAttribute \"filter\", \"url(#blur)\"\r\n     End <span style=\"color:blue;\">With<\/span>\r\n     oSVG.appendChild oSVGElement\r\n...<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Einlesen der Bilddatei in ein Byte-Array und &uuml;bergeben desselben an das SVG-image-Element<\/span><\/b><\/p>\n<p>Es bekommt die <b>id<\/b> <b>dataimage<\/b>, die Breite und H&ouml;he <b>200px<\/b> (<b>width<\/b>, <b>height<\/b>), und die Bilddaten &uuml;ber <b>href<\/b> aus einem Hexadezimal-String, der mittels der Hilfsfunktion <b>EncodeBase64<\/b> im Modul <b>mdlHelper<\/b> aus dem Array erzeugt wird. Der <b>Internet Explorer<\/b> zeigt das Bild dann allerdings aus Sicherheitsgr&uuml;nden erst an, wenn zus&auml;tzlich die Eigenschaft <b>crossOrigin<\/b> auf <b>anonymous<\/b> gesetzt wird, weil sonst die Herkunft der Bin&auml;rdaten f&uuml;r ihn ungekl&auml;rt ist.<\/p>\n<p>Das Weichzeichnen kommt schlie&szlig;lich zustande, indem Sie der <b>filter<\/b>-Eigenschaft den Ausdruck <b>url(#blur)<\/b> &uuml;bergeben. Darin verweist der Bezeichner <b>blur<\/b> auf einen <b>SVG-Filter<\/b>, der allerdings schon eigenst&auml;ndig angelegt sein muss. Auch dies l&auml;sst sich &uuml;ber <b>SVG<\/b>-Objekte bewerkstelligen. Im ersten Schritt wird das <b>Filter<\/b>-Objekt erzeugt:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oSVGFilter = oDoc.createElementNS( _\r\n     \"http:\/\/www.w3.org\/2000\/svg\", \"filter\")\r\noSVGFilter.setAttribute \"id\", \"blur\"<\/pre>\n<p>Er bekommt als Eigenschaft lediglich die <b>id<\/b> <b>blur<\/b>. Denn das Filter-Objekt bewirkt selbst noch keinen Filtereffekt und stellt nur einen <b>Container<\/b> f&uuml;r einen oder mehrere Effekte dar. Ein <b>SVG<\/b>-Element kann nur &uuml;ber diesen etwas umst&auml;ndlichen Weg mit einem Bildeffekt versehen werden. Dem Element muss im Attribut <b>filter<\/b> der Name des Filters &uuml;bergeben werden, wobei die Syntax <b>url(#<id>)<\/b> verwendet wird. Das <b>Filter<\/b>-Element wiederum ben&ouml;tigt als Kindelement ein <b>Filtereffekt<\/b>-Element.<\/p>\n<p>Das geschieht in der Prozedur so:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oSVGEffect = oDoc.createElementNS( _\r\n     \"http:\/\/www.w3.org\/2000\/svg\", \"feGaussianBlur\")\r\noSVGEffect.setAttribute \"in\", \"SourceGraphic\"\r\noSVGEffect.setAttribute \"stdDeviation\", \"10\"\r\noSVGFilter.appendChild oSVGEffect\r\noSVG.appendChild oSVGFilter<\/pre>\n<p>Das <b>SVG<\/b>-Element ist hier vom Typ <b>feGaussianBlur<\/b> und erzeugt einen Gaussschen Weichzeichner. Seine Eigenschaft <b>stdDeviation<\/b> bestimmt den Radius des Weichzeichnens &#8211; je h&ouml;her, desto verwischter. Das Attribut <b>in<\/b> gibt an, woher die Ausgangsgrafik kommt. Mit dem Wert <b>sourceGraphic<\/b> bestimmen Sie, dass das <b>SVG<\/b>-Element selbst daf&uuml;r herangezogen wird. Das Effektobjekt h&auml;ngen Sie schlie&szlig;lich an das Filterobjekt an und dieses selbst an das <b>SVG<\/b>-Objekt, also die generelle <b>SVG<\/b>-Fl&auml;che.<\/p>\n<p><!--30percent--><\/p>\n<p>Dabei spielt es keine Rolle, in welcher Reihenfolge Sie vorgehen. Sie k&ouml;nnen erst das Filterobjekt erzeugen und dann das <b>SVG<\/b>-Zeichenelement, oder umgekehrt. <b>MSHTML<\/b> analysiert die Sache selbst und generiert aus den Objekten die funktionierenden <b>HTML<\/b>-Anweisungen.<\/p>\n<p>Mit dem Turbulenzfilter f&uuml;r das Kreiselement wird es nochmals komplizierter. Hier m&uuml;ssen n&auml;mlich zwei Effekte miteinander kombiniert werden. Der eine SVG-Effekt erzeugt einen Turbulenzgenerator:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oSVGFilter = oDoc.createElementNS( _\r\n     \"http:\/\/www.w3.org\/2000\/svg\", \"filter\")\r\noSVGFilter.setAttribute \"id\", \"turb\"\r\n     \r\n<span style=\"color:blue;\">Set<\/span> oSVGEffect = oDoc.createElementNS( _\r\n     \"http:\/\/www.w3.org\/2000\/svg\", \"feTurbulence\")\r\noSVGEffect.setAttribute \"type\", \"fractalNoise\"\r\noSVGEffect.setAttribute \"baseFrequency\", \"0.03\"\r\noSVGEffect.setAttribute \"numOctaves\", \"3\"\r\noSVGEffect.setAttribute \"stitchTiles\", \"stitch\"\r\noSVGFilter.appendChild oSVGEffect<\/pre>\n<p>Der neue Filter bekommt die willk&uuml;rliche <b>id<\/b> <b>turb<\/b>. Ihm wird ein Effekt des Typs <b>feTurbulence<\/b> spendiert, auf dessen Parameter wir nicht weiter eingehen. Sie sind andernorts ausf&uuml;hrlich dargestellt. Nun handelt es sich bei diesem Effekt lediglich um eine Art abstrakten Generator, der ein zweidimensionales Rauschen hervorbringt. Auf ein <b>SVG<\/b>-Element angewandt w&uuml;sste der Browser noch nicht, was er mit dem Rauschen anfangen soll. Denn der Generator besitzt keinen Eingang <b>in<\/b>! Darum muss an den Filter noch ein weiterer Effekt angeh&auml;ngt werden, wobei wir hier einen Verschiebeeffekt nutzen, der die Pixel des Ausgangselements um den Wert eines Rauschens verschiebt:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oSVGEffect = oDoc.createElementNS( _\r\n     \"http:\/\/www.w3.org\/2000\/svg\", \"feDisplacementMap\")\r\noSVGEffect.setAttribute \"in\", \"SourceGraphic\"\r\noSVGEffect.setAttribute \"in2\", \"turbulence\"\r\noSVGEffect.setAttribute \"scale\", \"50\"\r\noSVGFilter.appendChild oSVGEffect<\/pre>\n<p>Der <b>SVG<\/b>-Effekt tr&auml;gt den Namen <b>feDisplacementMap<\/b>. Er besitzt zwei Eing&auml;nge, mit <b>in<\/b> die Herkunft der Grafik, auf die der Effekt angewandt werden soll, und mit <b>in2<\/b> den Turbulenzeffekt. Zus&auml;tzlich kann mit <b>scale<\/b> noch angegeben werden, wie stark sich der Effekt aus <b>in2<\/b> ausdehnt, also skaliert. Auch dieser Effekt wird dem Filterelement angeh&auml;ngt. Erst jetzt kann der Filter dem Kreis &uuml;bergeben werden:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oSVGElement = oDoc.createElementNS( _\r\n     \"http:\/\/www.w3.org\/2000\/svg\", \"circle\")\r\n<span style=\"color:blue;\">With<\/span> oSVGElement\r\n     .setAttribute \"id\", \"displacedcircle\"\r\n     .setAttribute \"cx\", \"50\"\r\n     .setAttribute \"cy\", \"50\"\r\n     .setAttribute \"r\", \"40\"\r\n     .setAttribute \"stroke\", \"green\"\r\n     .setAttribute \"stroke-width\", \"4\"\r\n     .setAttribute \"fill\", \"yellow\"\r\n     .setAttribute \"filter\", \"url(#turb)\"\r\nEnd <span style=\"color:blue;\">With<\/span>\r\noSVG.appendChild oSVGElement<\/pre>\n<p>Im letzten Attribut wird der Filter <b>turb<\/b> angewiesen, und schon verzerren sich der Kreis und dessen F&uuml;llung entsprechend dem Turbulenzgenerator.<\/p>\n<p>Dies sind nur zwei Beispiele f&uuml;r <b>SVG<\/b>-Filter, die die grunds&auml;tzliche Vorgehensweise verdeutlichen sollen. Insgesamt kennt <b>SVG<\/b> aktuell 16 solcher Filtereffekte, wobei bei diesen weniger an Bildbearbeitung gedacht wurde, als an die f&uuml;r Zeichnungen und Texte n&uuml;tzliche. Deshalb handelt es sich bei vielen um solche f&uuml;r Farbkombinationen oder -verschiebungen oder Elementkombinationen. Die entsprechende <b>SELFHTML<\/b>-Seite zu <b>SVG\/Filter<\/b> gibt eine gute &uuml;bersicht.<\/p>\n<p>Um es nochmals deutlich zu machen: Sie k&ouml;nnen die Filter auf jedes beliebige <b>SVG<\/b>-Grundelement anwenden! Also nicht nur auf Kreise, Rechtecke, Linien, Polygonz&uuml;ge oder Kurven, sondern etwa auch auf Text. Allerdings muss es sich dann bei Letzterem um <b>SVG<\/b>-Textelemente handeln. Ein Textelement legen Sie dergestalt an:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oSVGElement = oDoc.createElementNS( _\r\n     \"http:\/\/www.w3.org\/2000\/svg\", \"text\")\r\n<span style=\"color:blue;\">With<\/span> oSVGElement\r\n     .setAttribute \"x\", 20\r\n     .setAttribute \"y\", 30\r\n     .setAttribute \"style\", _\r\n        \"font-family:Calibri;font-size:12px;fill:#404040;\"\r\n     .innerText = \"Ein SVG-Textelement\"\r\nEnd <span style=\"color:blue;\">With<\/span><\/pre>\n<p>Das Element <b>text<\/b> platziert sich auf der <b>SVG<\/b>-Fl&auml;che an der Koordinate <b>20\/30<\/b> (linke obere Ecke des Textblocks) und hat den &uuml;ber <b>style<\/b> definierten Schriftstil <b>Calibri<\/b> mit der H&ouml;he <b>12 Pixel<\/b>. Die Schriftfarbe steht in <b>fill<\/b> mit einem hexadezimalen Dunkelgrau. Den eigentlichen Text schreiben Sie dann in die Eigenschaft <b>innerText<\/b>.<\/p>\n<h2>SVG-Ereignisse<\/h2>\n<p>Imgrunde kann jedes <b>HTML<\/b>-Element Events, wie Mausklicks, ausl&ouml;sen, die Sie in Klassenmodulen abfangen k&ouml;nnen, wenn Sie eine modulweit per <b>WithEvents<\/b> deklarierte Objektvariable auf sie setzen. Das verh&auml;lt sich bei <b>SVG<\/b>-Elementen ebenso. Allerdings leiten sich die dabei verf&uuml;gbaren Ereignisse praktisch alle von der allgemeinen Klasse <b>HTMLElement<\/b> ab, die allen <b>SVG<\/b>-Elementen untergeschoben ist. Aber gerade hier haben <b>SVG<\/b>-Grafiken einen enormen Vorteil gegen&uuml;ber <b>HTML5<\/b>-Grafiken. Da die Elemente alle zur Laufzeit gerendert werden, kann jederzeit auf sie Bezug genommen werden. Ein Element k&ouml;nnen Sie etwa zur Laufzeit l&ouml;schen oder &uuml;ber seine Attributparameter ver&auml;ndern.<\/p>\n<p>Nun ist es etwas m&uuml;hsam allen <b>SVG<\/b>-Elementen bei komplexeren Grafiken jeweils eine Objektvariable zuzuweisen, um auf deren Ereignisse zu reagieren. Da verliert man schon mal die &uuml;bersicht. Das ist indessen auch gar nicht n&ouml;tig, weil es eine kompaktere L&ouml;sung gibt. Dabei wird etwa f&uuml;r einen Mausklick lediglich das entsprechende Event des HTML-Dokuments selbst abgefangen und erst innerhalb dieser Ereignisprozedur das Element abgefragt, welches das Ereignis ausl&ouml;ste. Im Formular <b>frmSVGTest<\/b> ist auch dies implementiert.<\/p>\n<p>Der Ausgangspunkt ist dabei das <b>HTML<\/b>-Dokument, welches der Variablen <b>oDoc<\/b> zugewiesen wird:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents oDoc<span style=\"color:blue;\"> As <\/span>HTMLDocument<\/pre>\n<p>Der Klick auf irgendeine Stelle im fertigen Dokument l&ouml;st dann ein <b>Click<\/b>-Ereignis aus, das von einer Ereignisprozedur verarbeitet werden kann:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>oDoc_onclick()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> oEvent = oDoc.parentWindow.event\r\n     <span style=\"color:blue;\">If <\/span>oEvent.Button = 0<span style=\"color:blue;\"> Then<\/span>\r\n         Select Case oEvent.srcElement.ID\r\n         <span style=\"color:blue;\">Case <\/span>\"Kreis\"\r\n             <span style=\"color:blue;\">MsgBox<\/span> \"Kreis angeklickt\", vbExclamation\r\n         <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Der Trick ist hier, dass eine weitere Objektvariable <b>oEvent<\/b> auf die <b>Event<\/b>-Eigenschaft des Browser-Fensters gesetzt wird. Sie ist so deklariert:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>oEvent<span style=\"color:blue;\"> As <\/span>IHTMLEventObj<\/pre>\n<p>Und dieser Objekttyp kennt unter anderen die Methode <b>Button<\/b>, die Auskunft &uuml;ber die Maustaste gibt, welche gedr&uuml;ckt wurde. Eine <b>0<\/b> bedeutet dabei linke Maustaste. Die Bedingung in der Prozedur wertet dies aus und entscheidet dann &uuml;ber ein <b>Select-Case<\/b>-Statement auf die <b>ID<\/b> des ausl&ouml;senden Elements (<b>srcElement<\/b>), wie weiter verfahren wird. Handelt es sich um den <b>SVG<\/b>-Kreis, der zuvor generiert wurde und dessen <b>id<\/b> <b>Kreis<\/b> lautet, dann erscheint eine Meldung. In den <b>Select-Case<\/b>-Block k&ouml;nnen Sie nun beliebig viele Elemente abfragen und individuell auf sie reagieren. Voraussetzung ist nat&uuml;rlich, dass alle mit einem eindeutigen <b>id<\/b>-Attribut ausgestattet wurden.<\/p>\n<p>M&ouml;chten Sie dennoch auf ein Element direkt zugreifen, dann geschieht das so, wie beim Tulpenbild im Formular:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>WithEvents oSVGImage<span style=\"color:blue;\"> As <\/span>SVGImageElement \r\n...\r\n<span style=\"color:blue;\">Private Function <\/span>oSVGImage_onclick()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">MsgBox<\/span> \"SVG Bild angeklickt\"\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Nat&uuml;rlich muss dazu die Objektvariable auf das angelegte SVG-Bildelement verweisen, was sinnvollerweise bereits beim Erzeugen per <b>createElementNS<\/b> geschieht.<\/p>\n<p>Ein etwas speziellerer Fall ist das Ereignis bei der rechten Maustaste. Das f&auml;ngt man eher nicht mit dem <b>onclick<\/b>-Ereignis ab, sondern mit dem daf&uuml;r vorgesehenen <b>oncontextmenu<\/b>, weil die Aktion in der Regel ein Kontextmen&uuml; hervorruft:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>oSVGImage_oncontextmenu()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">MsgBox<\/span> \"Statt svg image Kontextmen&uuml;\"\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Wenn Sie diese Ereignisprozedur einsetzen, so erscheint also eine Meldung, nicht aber das Kontextmen&uuml;. Grund hierf&uuml;r ist der Umstand, dass es sich um eine Funktion handelt, der Sie einen <b>Boolean<\/b>-Wert zuweisen k&ouml;nnen. Ohne weitere Programmierung ist der R&uuml;ckgabewert deshalb <b>False<\/b>. Tats&auml;chlich k&ouml;nnen Sie dies aber &auml;ndern, indem Sie statt der <b>Msgbox<\/b> diese Zeile einf&uuml;gen:<\/p>\n<pre>oSVGImage_oncontextmenu = <span style=\"color:blue;\">True<\/span><\/pre>\n<p>Nun erscheint beim Rechtsklick auf das Tulpenbild tats&auml;chlich das Kontextmen&uuml;.<\/p>\n<p>Einfacher aber ist es wieder, sich das globale Kontextmen&uuml; des Dokuments zunutze zu machen:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>oDoc_oncontextmenu()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> oEvent = oDoc.parentWindow.event\r\n     Select Case oEvent.srcElement.ID\r\n     <span style=\"color:blue;\">Case <\/span>\"displacedcircle\"\r\n         oDoc_oncontextmenu = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Case <\/span>\"Kreis\"\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Kreis rechtsgeklickt\", vbInformation\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Auch hier wird wieder das <b>Event<\/b>-Objekt befragt und anhand der <b>id<\/b> des ausl&ouml;senden Elements entschieden, welche Aktion ausgel&ouml;st wird. Beim einfachen Kreis kommt es zu einer Meldung ohne Kontextmen&uuml;. Bei Turbulenzkreis des zweiten Beispiels, der die <b>id<\/b> <b>displacedcircle<\/b> tr&auml;gt, wird stattdessen das Kontextmen&uuml; des Dokuments aktiviert.<\/p>\n<p>Das Kontextmen&uuml; des Dokuments l&auml;sst sich allerdings nur mit gro&szlig;em Aufwand modifizieren oder mit eigenen Eintr&auml;gen best&uuml;cken. Die <b>MSHTML<\/b>-Bibliothek reicht daf&uuml;r nicht aus, und die in fr&uuml;heren Beitr&auml;gen eingesetzte Bibliothek <b>oleexp.tlb<\/b> m&uuml;sste her, weil es hier um den Umgang mit speziellen Interfaces geht. Das lassen wir au&szlig;en vor. Es ist dann aber fraglich, ob das Standardkontextmen&uuml; in einer <b>SVG<\/b>-Grafik etwas zu suchen hat und den Anwender eher verwirrt. Schalten Sie es einfach ab, indem Sie die obige Ereignisfunktion einsetzen, aber keinerlei Code in sie schreiben.<\/p>\n<h2>Diagramme mit SVG<\/h2>\n<p>Im Beitrag zu <b>HTML5<\/b> lernten Sie die Anlage von Balken- und Tortendiagrammen auf Basis der Daten eines <b>Recordsets<\/b> kennen. In der Beispieldatenbank zum aktuellen Beitrag bilden wir exakt dieselbe Funktionalit&auml;t ab und versuchen dabei auch m&ouml;glichst die gleichen Prozedurnamen zu verwenden. Eingesetzt wird nun jedoch nicht <b>HTML5<\/b>, sondern <b>SVG<\/b>.<\/p>\n<p>Rufen Sie dazu das Formular <b>frmSVGDiagram<\/b> auf klicken auf <b>Erzeuge Diagramm<\/b>. Es entsteht ein Balkendiagramm, welches genau der Version unter <b>HTML5<\/b> entspricht (siehe Bild 3), egal, ob Sie das Diagramm f&uuml;r Monatsums&auml;tze oder Umsatz nach L&auml;ndern ausw&auml;hlen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_03\/frmSVGDiagram_Bars1.png\" alt=\"Die Balkendiagramme des Formulars frmSVGDiagram pr&auml;sentieren sich wie ein Ebenbild der HTML5-Version (frmHTML5Diagram)\" width=\"700\" height=\"473,6736\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Die Balkendiagramme des Formulars frmSVGDiagram pr&auml;sentieren sich wie ein Ebenbild der HTML5-Version (frmHTML5Diagram)<\/span><\/b><\/p>\n<p>Nur das Tortendiagramm weicht in seiner Gestalt etwa ab, weil hier auf die Texte zus&auml;tzlich ein zusammengesetzter <b>SVG<\/b>-Effekt angewendet wird, der zu Demonstration einen <b>DropShadow<\/b>-Schatten nachbildet (siehe Bild 4). Tats&auml;chlich entspricht der Entwurf des Formulars genau der <b>HTML5<\/b>-Version. Und auch der Code zeigt nur wenige Abweichungen. Statt der f&uuml;r das Generieren des Balkendiagramms verantwortlichen Klasse <b>clsHTML5Diagram<\/b> kommt nun das neue Klassenmodul <b>clsSVGDiagram<\/b> zum Zug, f&uuml;r die Tortengrafik das Klassenmodul <b>clsSVGPieChart<\/b>. <\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_03\/frmSVGDiagram_Pie.png\" alt=\"Auch die SVG-Tortengrafiken entsprechen den HTML5-Versionen, zeigen bei den Texten jedoch zus&auml;tzlich einen bl&auml;ulichen Schatten\" width=\"700\" height=\"473,6736\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Auch die SVG-Tortengrafiken entsprechen den HTML5-Versionen, zeigen bei den Texten jedoch zus&auml;tzlich einen bl&auml;ulichen Schatten<\/span><\/b><\/p>\n<p>Deren Prozeduren haben deshalb auch die gleichen Namen, so dass die Versionen schnell austauschbar w&auml;ren. Die neuen Klassen instanziieren sich ebenfalls im <b>Load<\/b>-Ereignis des Formulars:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>CDgm<span style=\"color:blue;\"> As <\/span>clsSVGDiagram\r\n<span style=\"color:blue;\">Private <\/span>CDgmPie<span style=\"color:blue;\"> As <\/span>clsSVGPieChart\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Set<\/span> CDgm = <span style=\"color:blue;\">New<\/span> clsSVGDiagram\r\n     <span style=\"color:blue;\">Set<\/span> CDgmPie = <span style=\"color:blue;\">New<\/span> clsSVGPieChart\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Zu besprechen ist folglich nicht das neue Formular selbst, sondern die neuen Klassenmodule. Dabei wird jedoch nur auf das eingegangen, was die Module von den <b>HTML5<\/b>-Versionen unterscheidet und sich zuv&ouml;rderst in der Prozedur <b>PaintData<\/b> niederschl&auml;gt.<\/p>\n<p>Das Diagramm wird im Webbrowser-Steuerelement &uuml;ber die Prozedur <b>CreateDiagramDoc<\/b> erzeugt, der Sie lediglich &uuml;ber den Objektparameter einen Verweis auf den Browser &uuml;bergeben. Der Rest erfolgt automatisch. Nat&uuml;rlich &uuml;bernimmt diese Prozedur nun nicht mehr die Anlage eines <b>HTML5-Canvas<\/b> im Dokument, sondern die eines <b>SVG<\/b>-Elements, wie Listing 3 verdeutlicht. Es ist wieder in einen <b>DIV<\/b>-Bereich eingebettet, der es im Zweifel einfacher gestattet, die Grafik im Dokument zu verschieben, ohne die eigentliche <b>SVG<\/b>-Grafik anzufassen.  Der Teil zum Erzeugen der Diagrammelemente ist in die Prozedur <b>PaintData<\/b> ausgegliedert, die hier abschlie&szlig;end aufgerufen wird. Ihre 120 Zeilen k&ouml;nnen wir hier nicht in einem Listing abbilden und beschr&auml;nken uns auf die f&uuml;r <b>SVG<\/b>-Elemente relevanten Teile aus ihr.<\/p>\n<pre><span style=\"color:blue;\">Function <\/span>CreateDiagramDoc(Browser<span style=\"color:blue;\"> As <\/span>WebBrowser) \r\n     <span style=\"color:blue;\">Dim <\/span>oDiv<span style=\"color:blue;\"> As <\/span>HTMLDivElement\r\n     <span style=\"color:blue;\">Dim <\/span>oElmt<span style=\"color:blue;\"> As <\/span>IHTMLElement\r\n     \r\n     <span style=\"color:blue;\">On Error GoTo<\/span> Fehler\r\n     <span style=\"color:blue;\">Set<\/span> oDoc = Browser.Document\r\n     oDoc.body.setAttribute \"bgColor\", ColorToStr(vbWhite)\r\n     oDoc.head.innerHTML = _\r\n         \"&lt;meta http-equiv=\"\"X-UA-Compatible\"\"\/&gt;\"\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> oDiv = oDoc.createElement(\"div1\")\r\n     oDiv.ID = \"div1\"\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> oSVG = CreateSVGElement(\"svg\")\r\n     oSVG.setAttribute \"id\", \"svgimage\"\r\n     oSVG.setAttribute \"width\", CStr(m_Width)\r\n     oSVG.setAttribute \"height\", CStr(m_Height)\r\n     oDiv.appendChild oSVG\r\n     oDoc.body.appendChild oDiv\r\n     PaintData\r\n     CreateDiagramDoc = <span style=\"color:blue;\">True<\/span>\r\nEnde:\r\n     <span style=\"color:blue;\">Exit Function<\/span>\r\nFehler:\r\n     <span style=\"color:blue;\">MsgBox<\/span> Err.Description, <span style=\"color:blue;\">vbCr<\/span>itical\r\n     Resume Ende\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Die Routine legt ein Dokument samt SVG im Browser an.<\/span><\/b><\/p>\n<p>Der Diagrammrahmen wird &uuml;ber ein Rechteckelement erzeugt:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> oSVGElement = CreateSVGElement(\"rect\")<\/pre>\n<p>Weil die wiederholte &uuml;bergabe des <b>Namespace<\/b>-Arguments an die <b>MSHTML<\/b>-Methode <b>createElementNS<\/b> etwas erm&uuml;dend ist, gibt es die Hilfefunktion <b>CreateSVGElement<\/b>, der Sie nur noch das Element-<b>Tag<\/b> &uuml;bergeben. Die Hilfsfunktion f&uuml;gt den <b>Namespace<\/b> hinzu:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>CreateSVGElement( _\r\n     ByVal tag<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As <\/span>SVGElement\r\n     <span style=\"color:blue;\">Set<\/span> CreateSVGElement = oDoc.createElementNS( _\r\n         \"http:\/\/www.w3.org\/2000\/svg\", tag)\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Diese Funktion wird anschlie&szlig;end auch f&uuml;r alle weiteren <b>SVG<\/b>-Elemente verwendet. Die Eigenschaften des Elementobjekts erfahren ebenfalls eine Spezialbehandlung. Teilweise werden sie nicht &uuml;ber die Methode <b>setAttribute<\/b> direkt gesetzt, sondern &uuml;ber eine Hilfsfunktion <b>BaseValueLen<\/b>. Das gilt f&uuml;r alle Eigenschaften, die Ma&szlig;e betreffen, weil die bei <b>SVG<\/b>-Objekten, wie schon fr&uuml;her erw&auml;hnt, den zusammengesetzten Typ <b>SVGAnimatedLength<\/b> aufweisen:<\/p>\n<pre><span style=\"color:blue;\">With<\/span> oSVGElement\r\n     BaseValue<span style=\"color:blue;\">Len<\/span> .x, xOffset: BaseValue<span style=\"color:blue;\">Len<\/span> .y, 20\r\n     BaseValue<span style=\"color:blue;\">Len<\/span> .Width, m_Width - 20 - xOffset\r\n     BaseValue<span style=\"color:blue;\">Len<\/span> .Height, m_Height - 50\r\n     BaseValue<span style=\"color:blue;\">Len<\/span> .rx, 6: BaseValue<span style=\"color:blue;\">Len<\/span> .ry, 6\r\n    .setAttribute \"style\", \"fill:\" & _\r\n        ColorToStr(m_BackColor) & _\r\n         \";fill-opacity:0.5; stroke:darkblue;\" & _\r\n         \"stroke-width:2;opacity:0.7\"\r\nEnd <span style=\"color:blue;\">With<\/span><\/pre>\n<p>Die Hilfsfunktion belegt lediglich die Eigenschaft <b>baseVal<\/b> des in <b>L<\/b> &uuml;bergebenen Ma&szlig;es mit dem Wert aus <b>val<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>BaseValue<span style=\"color:blue;\">Len<\/span>(L<span style=\"color:blue;\"> As <\/span>SVGAnimatedLength, val<span style=\"color:blue;\"> As Variant<\/span>)\r\n     L.baseVal.Value = val\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das erspart zwar etwas Schreibarbeit, hat jedoch noch einen anderen Grund. Die Werte f&uuml;r die Koordinaten etwa stammen ja aus <b>Integer<\/b>-Variablen, w&auml;hrend die Methode <b>setAttribute<\/b> als Argument einen String erwartet. Folglich m&uuml;ssten alle Integer- oder Flie&szlig;kommawerte &uuml;ber die VBA-Funktionen <b>Str<\/b> oder <b>CStr<\/b> erst in Text umgewandelt werden. Einfacher ist da die Zuweisung &uuml;ber einen <b>Variant<\/b>-Parameter, den <b>baseVal.Value<\/b> ohnehin erwartet.<\/p>\n<p>Der obige Code-Block ist &uuml;brigens ein Beispiel f&uuml;r ein gerundetes <b>SVG<\/b>-Rechteck, denn die Attribute <b>rx<\/b> und <b>ry<\/b> spezifizieren das Ma&szlig; der Rundung mit dem Wert <b>3 Pixel<\/b>. Tats&auml;chlich weicht die Grafik in diesem Punkt von der <b>HTML5<\/b>-Version ab.<\/p>\n<p>Die folgenden Schleifen der Prozedur haben alle den gleichen Aufbau, wie die der <b>HTML5<\/b>-Version. Statt der <b>HTML5<\/b>-Zeichenoperationen mit der &uuml;bergabe von Parametern erfolgt hier die Anlage von <b>SVG<\/b>-Elementen, deren Attribute anschlie&szlig;end gesetzt werden. Das macht den Code etwas l&auml;nger, daf&uuml;r aber &uuml;bersichtlicher. Greifen wir uns einmal den gek&uuml;rzten Teil zum Generieren der Datenbeschriftungen heraus (Listing 4). Die Schleife durchl&auml;uft alle Datens&auml;tze des im <b>Property<\/b> <b>DataRecordset<\/b> der Klasse &uuml;bergebenen Recordsets <b>m_rs<\/b>. F&uuml;r jeden Datensatz wird ein <b>text<\/b>-Element erzeugt und an die <b>SVG<\/b>-Fl&auml;che <b>oSVG<\/b> angeh&auml;ngt. <b>x<\/b> und <b>y<\/b> sind berechnete Werte, die die Positionen der Texte &uuml;ber den Datenbalken bestimmen. Im <b>style<\/b>-Attribut ist der Schriftstil hartkodiert. <b>opacity<\/b> definiert dabei eine leichte Transparenz der Schriftz&uuml;ge, damit die Rasterlinien durchscheinen. In einem erweiterten Klassenmodul w&uuml;rde man hierf&uuml;r eventuell flexible Schrifteigenschaften als <b>Properties<\/b> und <b>Member<\/b>-Variablen vorsehen, damit das Diagramm besser angepasst werden k&ouml;nnte. <\/p>\n<pre>...\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> m_RS.EOF\r\n         <span style=\"color:blue;\">Set<\/span> oSVGElement = CreateSVGElement(\"text\")\r\n         <span style=\"color:blue;\">With<\/span> oSVGElement\r\n             .setAttribute \"x\", x\r\n             .setAttribute \"y\", _\r\n                  m_Height - IIf((i <span style=\"color:blue;\">Mod<\/span> 2) = 0, 16, 2)\r\n             .setAttribute \"style\", _\r\n                 \"font-family:Calibri;font-size:12px;\" & _\r\n                 \"fill:#404040;opacity:0.9\"\r\n             .innerText = CStr(m_RS(0).Value)\r\n         End <span style=\"color:blue;\">With<\/span>\r\n         oSVG.appendChild oSVGElement\r\n         x = x + w1\r\n         i = i + 1\r\n         m_RS.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n...<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: In dieser Schleife werden die SVG-Datentexte angelegt.<\/span><\/b><\/p>\n<p>Die Attribute werden dabei direkt gesetzt, also nicht die Hilfsfunktion <b>BaseValLen<\/b> herangezogen. Das funktioniert deshalb, weil es sich bei den Koordinaten um reine positive Integerwerte handelt, die automatisch korrekt in einen String umgewandelt werden. Anders bei der Beschriftung &uuml;ber <b>innerText<\/b> selbst: Hier muss erst <b>CStr() <\/b>auf den Flie&szlig;kommawert angesetzt werden, damit ein analoger String aus ihm wird. Das Dezimaltrennzeichen ist dann ein Punkt. Mit <b>Str() <\/b>w&uuml;rde es ein Komma.<\/p>\n<p>Nach dem Durchlaufen der Routine PaintData <b>zeigt<\/b> sich nun das fertige Diagramm im Webbrowser-Steuerelement.<\/p>\n<p>Im Gegensatz zur <b>HTML5<\/b>-Version weist es noch den Umstand auf, dass es auf Mausklicks reagiert. Zum einen erscheint bei Rechtsklick das &uuml;bliche Kontextmen&uuml;. Unter produktiven Bedingungen w&uuml;rde man es eher abschalten. Hier wurde es jedoch aktiviert, weil es einige interessante Funktionen bereith&auml;lt. So f&uuml;hrt der Eintrag <b>Bild speichern unter&#8230; <\/b>zu einem Dateiauswahldialog, der die Grafik nicht als Bitmap, sondern als Vektorgrafikdatei <b>blank.svg<\/b> abspeichern m&ouml;chte, was sich auch problemlos machen l&auml;sst.<\/p>\n<p>Die so erstellte <b>SVG<\/b>-Datei kann aber etwa <b>Inkscape<\/b> nicht einlesen. Bei Inspektion unter einem Texteditor zeigt sich, dass der Internet Explorer nicht nur den <b>SVG<\/b>-Teil des Dokuments exportiert hat, sondern auch das <b>DIV-Tag<\/b>. Entfernt man dieses aus der Datei, so, dass sie mit <b><svg..><\/b> beginnt, dann kann das Diagramm auch unter <b>Inkscape<\/b> angezeigt werden. Dort macht sich dann auch schon der Vorteil von <b>SVG<\/b>-Vektorgrafiken bemerkbar: Das Diagramm kann beliebig skaliert werden, ohne dass es zu unscharfen Linien oder Texten kommt.<\/p>\n<p>Ein linker Mausklick auf das Diagramm f&uuml;hrt zu einer <b>Messagebox<\/b>, die einen Zahlenwert ausgibt. F&uuml;r die Datenbeschriftungen ergibt das einen Sinn, f&uuml;r die anderen Elemente weniger. Die zugeh&ouml;rige Ereignisprozedur dient n&auml;mlich nur zur Demonstration einer neuen Technik und sieht so aus:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>oSVG_onmouseup()\r\n     <span style=\"color:blue;\">Dim <\/span>oElement<span style=\"color:blue;\"> As <\/span>SVGElement\r\n     <span style=\"color:blue;\">Set<\/span> oEvent = oDoc.parentWindow.event\r\n     <span style=\"color:blue;\">If <\/span>oEvent.Button = 1<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> oElement = oDoc.elementFromPoint( _\r\n                     oEvent.offsetX, oEvent.OffsetY)\r\n         Select Case oElement.tagName\r\n         <span style=\"color:blue;\">Case <\/span>\"rect\": <span style=\"color:blue;\">MsgBox<\/span> oElement.x.animVal.Value\r\n         <span style=\"color:blue;\">Case <\/span>\"text\": <span style=\"color:blue;\">MsgBox<\/span> oElement.innerText\r\n         <span style=\"color:blue;\">End Select<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Da keiner der <b>SVG<\/b>-Elemente im Dokument mit einer <b>id<\/b> versehen wurde &#8211; das sollten Sie jedoch immer tun! -, l&auml;sst sich ein Element, welches das Ereignis ausl&ouml;ste, auch nicht so einfach identifizieren. Trotzdem kann einiges &uuml;ber es erfahren werden. Das <b>Event<\/b>-Objekt hat etwa die Eigenschaften <b>offsetX<\/b> und <b>offsetY<\/b>, die Auskunft &uuml;ber die Koordinate geben, an die geklickt wurde. Aus dieser Koordinate kann die Funktion <b>elementFromPoint<\/b> des Dokuments das Element-Objekt ermitteln und an die Variable <b>oElement<\/b> zuweisen. Handelt es sich bei ihm um ein Rechteck (<b>tagName<\/b> = <b>rect<\/b>) oder einen Text (<b>tagName<\/b> = <b>text<\/b>), so greifen die entsprechenden Bedingungen des <b>Select-Case<\/b>-Blocks, und als Meldung wird entweder der Text selbst ausgegeben, oder bei Rechtecken der <b>x<\/b>-Wert der Koordinate. Das bringt uns, wie gesagt, wenig, zeigt jedoch, wie Sie auch ohne <b>Ids<\/b> an die ausl&ouml;senden Elemente gelangen.<\/p>\n<h2>Abspeichern als JPG-Bild<\/h2>\n<p>W&auml;hrend das Ausdrucken der Diagramme wenig Probleme bereitet und im Formular &uuml;ber die Methode <b>execCommand<\/b> des Dokuments im Verein mit dem Parameter <b>print<\/b> ausgel&ouml;st werden kann, bereitet der Export in eine Bilddatei mehr Kopfzerbrechen, als in der <b>HTML5<\/b>-Version. Dort n&auml;mlich besteht die Grafik ohnehin aus einem Bitmap, so dass Sie &uuml;ber den <b>data-URI<\/b> des <b>image<\/b>-Objekts an die Pixeldaten gelangen. Die <b>SVG<\/b>-Grafik aber wird ja erst zur Laufzeit gerendert! Der Browser ver&ouml;ffentlicht indessen keinerlei Methoden, um an die gerenderten Daten zu gelangen.<\/p>\n<p>Hier bleibt nur der indirekte Zugriff auf das Browser-Fenster und eine Art Screenshot &uuml;ber API-Funktionen. Das war mein erster Ansatz, der jedoch obsolet wurde, nachdem ich auf die raffinierte API-Funktion <b>OLEDraw<\/b> stie&szlig;. Dieser kann man ein <b>OLE-Objekt<\/b> &uuml;bergeben, dessen visuellen Inhalt sie dann in einen in einen beliebigen <b>Windows Device Context<\/b> (<b>DC<\/b>) rendert. Das funktioniert mit jedem visuellen <b>OLE-Objekt<\/b> und damit auch mit einem <b>HTMLDocument<\/b>. Der Clou aber ist, dass man ihr zus&auml;tzlich mitteilen kann, wie gro&szlig; die gerenderte Grafik werden soll. Das erm&ouml;glicht ein Abspeichern in eine Bilddatei, deren Bildabmessungen viel gr&ouml;&szlig;er sind, als das im Webbrowser pr&auml;sentierte Diagramm. Die API-Funktion interagiert dazu mit der OLE-Anwendung und sagt ihr, welche Gr&ouml;&szlig;e sie haben m&ouml;chte. Der Browser &uuml;bergibt ihr dann das gerenderte Bild.<\/p>\n<p>Das hei&szlig;t im Klartext, dass ein Diagramm, welches im Browser die Ausdehnung <b>800&#215;800<\/b> Pixeln besitzt, auch als Bild in der Gr&ouml;&szlig;e von <b>4000&#215;4000<\/b> Pixeln ausgegeben werden kann, ohne dass Elemente verschwimmen. Aus einer Line der Breite <b>2px<\/b> wird dann einfach eine messerscharfe mit <b>10px<\/b>.<\/p>\n<p>Nat&uuml;rlich kommt man bei dieser API-Funktion auch nicht ohne eine umfangreichere API-Routine herum. Das Modul <b>mdlGDIPSpecial<\/b> der Beispieldatenbank &uuml;bernimmt alles N&ouml;tige. Es basiert auf dem <b>GDIPlus-API<\/b> und l&auml;sst den Export eines OLE-Objekts als Bilddatei im <b>JPG<\/b>-Format zu. Sie brauchen nur die Methode <b>SaveToImageFile<\/b> aufzurufen, die die folgende Syntax aufweist:<\/p>\n<pre><span style=\"color:blue;\">Function <\/span>SaveOLEToImageFile( _\r\n     ByVal OleObj<span style=\"color:blue;\"> As <\/span>stdole.IUnknown, _\r\n     ByVal W<span style=\"color:blue;\"> As Long<\/span>, _\r\n     ByVal H<span style=\"color:blue;\"> As Long<\/span>, _\r\n     ByVal FileName<span style=\"color:blue;\"> As String<\/span>, _\r\n     <span style=\"color:blue;\">Optional<\/span> ByVal Quality<span style=\"color:blue;\"> As Byte<\/span> = 90, _\r\n     <span style=\"color:blue;\">Optional<\/span> ByVal ToClipboard<span style=\"color:blue;\"> As Boolean<\/span>)<span style=\"color:blue;\"> As Boolean<\/span><\/pre>\n<p>Der erste zu &uuml;bergebende Parameter ist das <b>OLE-Objekt<\/b>, in unserem Fall also ein Verweis auf das <b>HTML<\/b>-Dokument-Objekt des Webbrowser-Steuerelements. Mit <b>W<\/b> und <b>H<\/b> geben Sie an, welche Breite und H&ouml;he das erzeugte Bild haben soll. Daran schlie&szlig;t sich der volle Pfad zur zu exportierenden Datei an, gefolgt vom optionalen <b>Quality<\/b>. Ohne Angabe wird der Qualit&auml;tsfaktor <b>90<\/b> verwendet, was f&uuml;r die meisten Zeichnungen ausreichend sein d&uuml;rfte. Geringere Werte lassen meist kleine Artefakte erscheinen, w&auml;hrend Sie mit <b>100<\/b> in jedem Fall auf der sicheren Seite sind. <\/p>\n<p>Tats&auml;chlich kann die Funktion aber nicht nur eine Bilddatei erstellen, sondern das Bild auch in die Zwischenablage legen. Das geschieht dann, wenn Sie den letzten Parameter <b>ToClipboard<\/b> auf <b>True<\/b> setzen. Eine Bilddatei wird in diesem Fall nicht angelegt.<\/p>\n<p>Die Funktion ruft wiederum jeweils die Prozedur <b>SaveAsImage<\/b> der Klassenmodule <b>clsSVGDiagram<\/b> und <b>clsSVGPieChart<\/b> auf (Listing 5).<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>SaveAsImage(ByVal FileName<span style=\"color:blue;\"> As String<\/span>, _\r\n     <span style=\"color:blue;\">Optional<\/span> ByVal dScale<span style=\"color:blue;\"> As Double<\/span> = 1, _\r\n     <span style=\"color:blue;\">Optional<\/span> Preview<span style=\"color:blue;\"> As Boolean<\/span>)\r\n     \r\n     <span style=\"color:blue;\">Dim <\/span>W<span style=\"color:blue;\"> As Long<\/span>, H<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>ret<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>sFile<span style=\"color:blue;\"> As String<\/span>\r\n        \r\n     sFile = FileName\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> oDoc Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(sFile) = 0<span style=\"color:blue;\"> Then<\/span>\r\n           sFile = GetSaveFileDialog(, \"SVGDiagramm.jpg\")\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(sFile) = 0<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit Sub<\/span>\r\n         \r\n         <span style=\"color:blue;\">With<\/span> oDoc.getElementById(\"svgimage\")\r\n             W = dScale * .Width.baseVal.Value\r\n             H = dScale * .Height.baseVal.Value\r\n             .focus\r\n         End <span style=\"color:blue;\">With<\/span>\r\n         ret = SaveOLEToImageFile(oDoc, W, H, sFile, 85)\r\n         <span style=\"color:blue;\">If <\/span>ret<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span>Preview<span style=\"color:blue;\"> Then<\/span>\r\n                 ShellExecute 0&, \"open\", sFile, _\r\n                     vbNullString, vbNullString, 5&\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Abspeichern des Diagramms als Bild im Klassenmodul<\/span><\/b><\/p>\n<p>Der Prozedur &uuml;bergeben Sie den gew&uuml;nschten Dateinamen samt Pfad oder einen Leer-String. In diesem Fall tritt ein <b>Speichern-unter<\/b>-Dialog auf den Plan, &uuml;ber den Sie das Verzeichnis und den Dateinamen bestimmen k&ouml;nnen. Der Parameter <b>dScale<\/b> ist ein Flie&szlig;kommawert, der standardm&auml;&szlig;ig auf <b>1<\/b> steht und damit das Bild in den Abmessungen exportiert, wie es im Browser zu sehen ist. Ein Wert von <b>0.5<\/b> verkleinert das Bild, ein Wert von <b>3<\/b> verdreifacht seine Abmessungen. Setzen Sie schlie&szlig;lich den Parameter <b>Preview<\/b> auf True, so &ouml;ffnet Windows die exportierte Bilddatei &uuml;ber die Shell automatisch, was je nach Dateizuordnung in der Regel das Programm <b>Windows-Bildvorschau<\/b> sein d&uuml;rfte.<\/p>\n<p>Da die API-Funktion <b>OLEDraw<\/b> zwingend die Angabe von Breite und H&ouml;he des zu rendernden Bilds erwartet, muss diese zuvor errechnet worden sein. In der Routine wird dazu das <b>SVG<\/b>-Fl&auml;chenelement <b>svgimage<\/b> im Dokument herausgesucht (<b>getElementById<\/b>) und dessen Breite etwa &uuml;ber seine Eigenschaft <b>Width.basVal.Value<\/b> erhalten. Diese Funktion der Klasse ruft nun das Ereignis <b>Click<\/b> der <b>Als Bild speichern&#8230;<\/b>-Schaltfl&auml;che des Diagrammformulars auf:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdSaveImg_Click()\r\n     <span style=\"color:blue;\">If <\/span>optgrp2.Value = 1<span style=\"color:blue;\"> Then<\/span>\r\n         CDgm.SaveAsImage \"\", 2, <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         CDgmPie.SaveAsImage \"\", 2, <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Je nachdem, ob das Generieren eines Balken- oder Tortendiagramms in der Optionsgruppe <b>optgrp2<\/b> ausgew&auml;hlt ist, kommt entweder die Klassenvariable <b>CDgm<\/b> oder <b>CDgmPie<\/b> zum Zug und ruft die Methode <b>SaveAsImage<\/b> auf. Als Skalierungsfaktor ist fest <b>2<\/b> eingesetzt, so dass die exportierte Bilddatei die doppelte Gr&ouml;&szlig;e aufweisen wird, wie das im Browser angezeigte Diagramm.<\/p>\n<h2>Tortendiagramm<\/h2>\n<p>Das Klassenmodul f&uuml;r Tortendiagramme (<b>clsSVGPieChart<\/b>) ist exakt gleich aufgebaut, wie das f&uuml;r die Balkendiagramme. Nur die Prozedur <b>PaintData<\/b> hat nat&uuml;rlich einen komplett anderen Inhalt. Aus Platzgr&uuml;nden gehen wir auf deren Gestaltung nicht ausf&uuml;hrlich ein, da die wesentlichen Infos bereits ausreichend beim Balkendiagramm dargestellt wurden.<\/p>\n<p>Interessant ist aber vielleicht das Verfahren zum Zeichnen der Tortenst&uuml;cke. Am einfachsten w&auml;re es, einen Kreis und f&uuml;r jedes Tortenst&uuml;ck jeweils eine Line vom Mittelpunkt zum Radius zu zeichnen. Das war auch die Methode, die beim <b>HTML5<\/b>-Diagramm zum Einsatz kam. Die so erzeugte Figur konnte dort problemlos mit einer Zufallsfarbe gef&uuml;llt werden. Anders bei <b>SVG<\/b>. Da hier keine Pixelgrafik vorliegt, kann eine aus mehreren <b>SVG<\/b>-Elementen gezeichnete Figur nicht so einfach gef&uuml;llt werden, schon gar nicht, wenn es sich um Linienelemente handelt. Nur ein einzelnes <b>SVG-<\/b>Element kann im <b>style<\/b>-Attribut &uuml;ber <b>fill<\/b> eine bestimmte F&uuml;llfarbe erhalten. Also ben&ouml;tigen wir hier ein Element, das sich sowohl aus Linien, wie Kurven zusammensetzt. Die Wahl f&auml;llt darum auf ein <b>SVG-path<\/b>-Element.<\/p>\n<p>Ein <b>Path<\/b>-Element kann n&auml;mlich mehrere verschiedenartige <b>Segmente<\/b> beherbergen. Das k&ouml;nnen gerade Linien sein, Kreisteile und Bezier-Kurven. Selbst das nichtvisuelle Verschieben des Stifts zu einer Koordinate, bei der er aufsetzt, ist m&ouml;glich. Wenn Sie sich im Objektkatalog die Methoden der Klasse <b>ISVGPathElement<\/b> anschauen, wird das deutlich. <b>createSVGPathSegMovetoAbs<\/b> setzt den Zeichenstift quasi an eine bestimmte Koordinate. <b>createSVGPathSegLinetoAbs<\/b> zeichnet von dort aus eine Linie zur &uuml;bergebenen Koordinate, <b>createSVGPathSegArcAbs<\/b> w&uuml;rde von dort aus einen Kreisabschnitt zeichnen. Genau diese drei Segmentarten kommen f&uuml;r die Tortenst&uuml;cke zum Einsatz, w&auml;hrend weitere, wie <b>createSVGPathSegCurvetoCubicAbs<\/b> zum Zeichnen einer Bezier-Kurve, hier nicht ben&ouml;tigt werden.<\/p>\n<p>Diese Segmente werden als Objekte an das <b>Path<\/b>-Element &uuml;ber dessen Elementliste <b>pathSegList<\/b> angef&uuml;gt, wobei wie daf&uuml;r die Methode <b>appendItem<\/b> verwenden. Damit die Figur gef&uuml;llt werden kann, muss sie komplett geschlossen sein, was die Methode <b>createSVGPathSegClosePath<\/b> &uuml;bernimmt. Die Figur muss nun nur noch &uuml;ber das <b>style<\/b>-Attribut mit Werten f&uuml;r die Linienbreite, -farbe, Transparenz und F&uuml;llung versehen werden.<\/p>\n<p>Der <b>Dropshadow<\/b>-Effekt f&uuml;r die Textschatten schlie&szlig;lich erfordert einen etwas komplexeren <b>SVG-Filter<\/b>. Einen einzelnen <b>SVG<\/b>-Effekt gibt es daf&uuml;r nicht, weshalb dieser Filter sich aus mehreren miteinander kombinierten bildet. Im Einzelnen sind dies <b>feGaussianBlur<\/b> zum Weichzeichnen des Texts, <b>feOffset<\/b> zum Verschieben des weichgezeichneten Texts als Hintergrund, <b>feMerge<\/b> und <b>feMergeNode<\/b> zum Kombinieren dieser beiden Effekte, und schlie&szlig;lich <b>feBlend<\/b> zum transparenten Einblenden des Schattens unter den Text. Die Beschreibung der genauen Funktionsweise w&uuml;rde an dieser Stelle den Rahmen sprengen. Im Klassenmodul ist der entsprechende Abschnitt der Routine <b>PaintData<\/b> in den Kommentarblock <b>DropShadow<\/b>-Filter eingebunden. Die Technik ist Ergebnis einer Recherche nach den Suchbegriffen <b>SVG Dropshadow<\/b> im Netz, die etliche Beispiele <b>HTML<\/b>-Beispiele und JavaScripte zutage f&ouml;rdert. Diese wurden lediglich nach VBA und <b>MSHTML<\/b> konvertiert.<\/p>\n<h2>SVG-Animationen<\/h2>\n<p>Ein besonderes Feature von <b>SVG<\/b> ist die M&ouml;glichkeit, die <b>SVG<\/b>-Elemente in fast allen Parametern zu animieren. Der Radius eines Kreises etwa kann zur Laufzeit &uuml;ber dessen Attribut <b>r<\/b> ge&auml;ndert werden. Dazu ist es noch gar nicht einmal notwendig, das Attribut etwa in einer Schleife fortw&auml;hrend neu zu setzen. Vielmehr gibt es ein spezielles <b>SVG<\/b>-Element <b>animate<\/b>, das Sie als Kindelement einem <b>SVG<\/b>-Grundelement hinzuf&uuml;gen. Dem <b>animate<\/b>-Element sagen Sie dann &uuml;ber Attribute, welche Parameter des Elternobjekts zu animieren sind. Sie k&ouml;nnen etwa den Radius bestimmen, sagen, innerhalb welcher Grenzen sich dieser ver&auml;ndern soll, und festlegen, in welcher Zeit das erfolgen soll. Der Browser nimmt diese Parameter&auml;nderung dann selbst&auml;ndig vor, ohne dass Sie auch nur eine zus&auml;tzliche VBA-Code-Zeile daf&uuml;r ben&ouml;tigen.<\/p>\n<p>Allerdings hat Microsoft die <b>SVG-animate<\/b>-Elemente und -Methoden (noch) nicht alle direkt in das Objektmodell &uuml;bersetzt. Um den Rahmen dieses Beitrags nicht zu sprengen, enth&auml;lt die Demo-Datenbank auch keine Beispiele f&uuml;r diese Techniken.<\/p>\n<p>Mehr erfahren Sie etwa im Netz unter <b>SELFHTML<\/b> unter der Rubrik <b>SVG\/animate<\/b>. Zu den <b>SVG<\/b>-Diagrammen ist nun alles Wesentliche gesagt. Um mehr Interaktivit&auml;t mit den <b>SVG<\/b>-Elementen geht es dann im gesonderten Beitrag zum <b>Malen und Zeichnen mit SVG<\/b>. Ein letztes Beispiel zum Umgang mit <b>SVG<\/b> integrieren wir hier aber noch.<\/p>\n<h2>Interaktive SVG-Karte<\/h2>\n<p>Sie m&uuml;ssen <b>SVG<\/b>-Zeichnungen nicht von Grund auf per VBA neu erstellen. Sie k&ouml;nnen ebenso eine existierende <b>SVG-Datei <\/b>laden und weiterverarbeiten. Die k&ouml;nnte &uuml;ber den Export aus einem Vektorzeichenprogramm stammen wie <b>Inkscape<\/b>. Im vorliegenden Beispiel des Formulars <b>frmSVGWorld<\/b> l&auml;dt das Webbrowser-Steuerelement eine <b>SVG<\/b>-Europakarte, die auf Klicks reagiert (siehe Bild 5). Die Bet&auml;tigung des Buttons <b>SVG-Grafik laden<\/b> des Formulars weist den Browser <b>oWeb<\/b> lediglich an, direkt zur <b>SVG<\/b>-Datei zu navigieren:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_03\/frmSVG_Europe.png\" alt=\"Das Formular frmSVGWorld l&auml;dt im Webbrowser das Bild einer SVG-Datei und erzeugt bei Mausklick auf einen Bereich eine Meldung\" width=\"700\" height=\"601,4368\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Das Formular frmSVGWorld l&auml;dt im Webbrowser das Bild einer SVG-Datei und erzeugt bei Mausklick auf einen Bereich eine Meldung<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdLoadSVG_Click()\r\n     oWeb.Navigate2 CurrentProject.Path & \"\\europa.svg\"\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Datei <b>europa.svg<\/b> muss sich dazu im Datenbankverzeichnis befinden. Der Vorgang ist abgeschlossen, wenn das Dokument fertig gerendert ist, was das Ereignis <b>NavigateComplete2<\/b> hervorruft. Dort wird die <b>WithEvents<\/b> deklarierte Objektvariable <b>oDoc<\/b> auf das Dokument im Browser gesetzt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>oWeb_NavigateComplete2(ByVal pDisp<span style=\"color:blue;\"> As <\/span> Object, URL<span style=\"color:blue;\"> As Variant<\/span>)\r\n     <span style=\"color:blue;\">Set<\/span> oDoc = oWeb.Document\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Ein Mausklick auf das Dokument l&ouml;st diese Ereignisprozedur aus:<\/p>\n<pre><span style=\"color:blue;\">Private Function <\/span>oDoc_onclick()<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>oEvent<span style=\"color:blue;\"> As Object<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> oEvent = oDoc.parentWindow.event\r\n     <span style=\"color:blue;\">If <\/span>TypeName(oEvent.srcElement) = \"SVGPathElement\"<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> oEvent.srcElement.ID\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Bei allen gef&uuml;llten L&auml;nderfiguren der Karte handelt es sich um <b>SVG-path<\/b>-Elemente. Die filtert die Routine heraus (<b>srcElement<\/b> = <b>SVGPathElement<\/b>) und zeigt in einer Meldung dann deren <b>id<\/b> an. Das <b>gb<\/b> steht f&uuml;r <b>Gro&szlig;britannien<\/b>, und das ist die <b>id,<\/b> die dem <b>Path<\/b>-Element in der Datei spendiert ist. Genauso gut k&ouml;nnte man weitere Eigenschaften und Attribute des Elements ausgeben lassen, oder gar &uuml;ber VBA das <b>style<\/b>-Attribut neu belegen und etwa die Hintergrundfarbe des Lands &auml;ndern.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>europa.svg<\/p>\n<p>SVGImage.accdb<\/p>\n<p>tulpe.jpg<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/5348D743-B253-48E9-816E-8F37459D140C\/aiu_1132.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In zwei Beitr&auml;gen rund um das Thema &#8218;HTML5 als Grafikkomponente&#8216; erfuhren Sie, wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen. &Uuml;ber eine andere Schnittstelle, n&auml;mlich SVG, l&auml;sst sich dasselbe erreichen, wobei hier nicht Pixel-, sondern Vektorgrafiken erzeugt werden, die deutlich mehr Interaktivit&auml;t zulassen und nachtr&auml;glich bearbeitbar sind. <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662018,66032018,44000026],"tags":[],"class_list":["post-55001132","post","type-post","status-publish","format-standard","hentry","category-662018","category-66032018","category-Interaktiv"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>SVG als Grafikkomponente - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SVG als Grafikkomponente\" \/>\n<meta property=\"og:description\" content=\"In zwei Beitr&auml;gen rund um das Thema &#039;HTML5 als Grafikkomponente&#039; erfuhren Sie, wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen. &Uuml;ber eine andere Schnittstelle, n&auml;mlich SVG, l&auml;sst sich dasselbe erreichen, wobei hier nicht Pixel-, sondern Vektorgrafiken erzeugt werden, die deutlich mehr Interaktivit&auml;t zulassen und nachtr&auml;glich bearbeitbar sind.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-13T21:19:44+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg06.met.vgwort.de\/na\/1e321b90619e4317aab6c90914dcb8dc\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"38\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"SVG als Grafikkomponente\",\"datePublished\":\"2020-05-13T21:19:44+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/\"},\"wordCount\":6598,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/1e321b90619e4317aab6c90914dcb8dc\",\"articleSection\":[\"2018\",\"3\\\/2018\",\"Interaktiv\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/\",\"name\":\"SVG als Grafikkomponente - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/1e321b90619e4317aab6c90914dcb8dc\",\"datePublished\":\"2020-05-13T21:19:44+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/1e321b90619e4317aab6c90914dcb8dc\",\"contentUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/1e321b90619e4317aab6c90914dcb8dc\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SVG_als_Grafikkomponente\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SVG als Grafikkomponente\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"SVG als Grafikkomponente - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/","og_locale":"de_DE","og_type":"article","og_title":"SVG als Grafikkomponente","og_description":"In zwei Beitr&auml;gen rund um das Thema 'HTML5 als Grafikkomponente' erfuhren Sie, wie Sie mithilfe des Webbrowser-Steuerelements und HTML5 programmgesteuert Grafiken erzeugen. &Uuml;ber eine andere Schnittstelle, n&auml;mlich SVG, l&auml;sst sich dasselbe erreichen, wobei hier nicht Pixel-, sondern Vektorgrafiken erzeugt werden, die deutlich mehr Interaktivit&auml;t zulassen und nachtr&auml;glich bearbeitbar sind.","og_url":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-13T21:19:44+00:00","og_image":[{"url":"http:\/\/vg06.met.vgwort.de\/na\/1e321b90619e4317aab6c90914dcb8dc","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"38\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"SVG als Grafikkomponente","datePublished":"2020-05-13T21:19:44+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/"},"wordCount":6598,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/1e321b90619e4317aab6c90914dcb8dc","articleSection":["2018","3\/2018","Interaktiv"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/","url":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/","name":"SVG als Grafikkomponente - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/1e321b90619e4317aab6c90914dcb8dc","datePublished":"2020-05-13T21:19:44+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/#primaryimage","url":"http:\/\/vg06.met.vgwort.de\/na\/1e321b90619e4317aab6c90914dcb8dc","contentUrl":"http:\/\/vg06.met.vgwort.de\/na\/1e321b90619e4317aab6c90914dcb8dc"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/SVG_als_Grafikkomponente\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"SVG als Grafikkomponente"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001132","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001132"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001132\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001132"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001132"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001132"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}