Alexander Knapp: Frage zum Wiki-Artikel „SVG_und_JavaScript“

problematische Seite

Ich habe mit einem Tool eine interaktive SVG-Karte erzeugt, die soweit auch funktioniert. Inhalt sind sämtliche PLZ-Bereiche in D, diesen sind in Vertriebsbereiche zusammengefasst.

Ziel ist es jetzt, da eine Suchfunktion draufzusetzen, die es dem User erlaubt, seine Postleitzahl anzugeben und damit herauszufinden, welches Vertriebsgebiet für ihn zuständig ist.

Heisst, bei einem Treffer soll der Hoover-Effekt, der bei einem Mouseover über der Karte ohnehin entsteht, über den PLZ-Parameter ausgelöst werden. innerhalb der Polygone sind die Infos z. B.: id="01067 Dresden" data-info="01067 Dresden" enthalten (für alle PLZ in D).

Ich vermute stark, dass sich das per JS lösen lässt, habe aber auch nach umfangreicher Suche noch nicht mal ein Beispiel finden können, welches mir auf die Sprünge hilft.

Vielleicht kann hier jemand zum Thema einen Anschub geben?

Danke!

  1. problematische Seite

    Hallo Alexander,

    bei einem Treffer soll der Hoover-Effekt

    HILFE! Meine Maus ist weg!!!! Sie wurde in den Bildschirm gesaugt!

    Hoover ist eine amerikanische Staubsaugermarke und wurde zum Allgemeinbegriff für Staubsauger in den USA. So wie Tempo bei uns für Papiertaschentücher. Du meinst Hover - schweben. 😂

    Suchfunktion, die es dem User erlaubt, seine Postleitzahl anzugeben

    Ein Eingabefeld, dessen Wert ein PLZ Gebiet hervorheben soll? Für diejenigen, die nicht wissen, wo die PLZ 12345 zu finden ist?

    Da Du die PLZ in den IDs als Namensanteil drin hast, kannst Du die querySelector-Methode mit einem Attribut-Prefixselektor arbeiten.

    Das stößt Du entweder aus einem input- oder change-Event des Eingabefeldes heraus an, oder über das click-Event eines "Suchen" Buttons. Im Eventhandler prüfst Du, ob im Eingabefeld eine valide PLZ steht (sprich: 5 Stellen nur Ziffern - schwieriger wird es, wenn Du auch Vertriebsgebiete im Ausland dazu bekommst) und kannst das Polygon dann so finden - unter der Annahme, dass das path-Elemente sind.

    const plzPolygon = svgElement.querySelector("path[id^=" + plz + "]")
    

    Damit findest Du das path-Element, das das Polygon für eine bestimmte PLZ enthält, und kannst ihm eine Klasse geben, die dann per CSS für eine Hervorhebung sorgt. Mit animierter Randfarbe, Zoom-Effekt und sonstigem Bling Bling, ganz wie Du willst.

    Wenn Du den Ortsnamen aus der ID herauslässt, kannst Du auch einfach getElementById verwenden. Warum ist der überhaupt in der ID drin? In data-info ist er auch drin, das ist redundant.

    Die weitere Frage wäre dann, ob Du auch das ganze Vertriebsgebiet zu dieser PLZ hervorheben willst. Dafür könntest Du die Vertriebsgebiets-ID als weiteres data-Attribut an die Polygone hängen, und dann, wenn Du das Polygon für die eingegebene PLZ hast, suchst Du alle Polygone mit der gleichen Vertriebs-ID und markierst die auch.

    Wenn Du noch weitere Daten zum Vertriebsgebiet anzeigen willst, brauchst Du ein Array mit den Daten dazu (oder einen Webservice, von dem Du sie fetchen kannst), und kannst damit ein informatives <aside> befüllen.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. problematische Seite

      @@Rolf B

      Hoover ist eine amerikanische Staubsaugermarke und wurde zum Allgemeinbegriff für Staubsauger in den USA. So wie Tempo bei uns für Papiertaschentücher. Du meinst Hover - schweben. 😂

      Da sage nochmal einer, es gäbe gar keine Hooverboards.

      😷 LLAP

      --
      „Dann ist ja auch schrecklich, dass wir in einem Land leben, in dem nicht nur Bildungswillige leben, sondern auch hinreichende Zahlen von Bekloppten. Das darf ich so locker formulieren, ich bin ja jetzt Rentner und muss nicht mehr auf jedes Wort achten.“
      — Joachim Gauck über Impfgegner
      1. problematische Seite

        Hallo,

        Hoover ist eine amerikanische Staubsaugermarke und wurde zum Allgemeinbegriff für Staubsauger in den USA. So wie Tempo bei uns für Papiertaschentücher. Du meinst Hover - schweben. 😂

        Da sage nochmal einer, es gäbe gar keine Hooverboards.

        und, gibt's die denn?

        Aber ganz ehrlich: Mir wäre als erstes nicht die Staubsaugermarke eingefallen, sondern der FBI-Pionier J. Edgar Hoover.

        May the Schwartz be with you
         Martin

        --
        Wenn ich den See seh, brauch ich kein Meer mehr.
    2. problematische Seite

      WOW!

      Mal an der Stelle vielen Dank für die ganzen Antworten, hab ich ein wenig durchzuarbeiten!

      Um ein paar Punkte, die auch weiter unten angesprochen zu klären:

      Das SVG und die ganze Polygon und Polyline-Beschreibung befindet sich innerhalb der HTML-Dateim da wird nichts von extern eingebunden. Polyline für die einzelnen PLZ-Gebiete Polygon umfasst die PLZ zu einem Vertriebsgebiet.

      Wer sich das genauer anschauen möchte: IMapU

      Die Karte an sich IST bereits "interaktiv", d.h. unter anderem: Die jeweiligen Postleitzahlen sind bereits dem Vertriebsgebiet zugeordnet und es wird das komplette Vertriebsgebiet "gehoovert" :)

      Bisher habe ich schon hinbekommen, dass eine Suche nur innerhalb der umschließenden svg id sucht, somit ist der Bereich definiert und es wird nicht das komplette Dokument durchsucht.

      Das Suchfeld hat auch schon die erlaubten Parameter erhalten, es müssen fünf Ziffern sein, optional füge ich da noch ggf. zwei Buchstaben und Bindestrich hinzu, aber da das Tool ohnehin nur D-Karten erzeugt, ist das vernachlässigbar.

      Der Parameter aus dem Suchfeld wird an das "getElemementbyID" übergeben.

      Es findet noch keine Feldüberprüfung statt (es müssen 5 Ziffern eingegeben werden etc.) - ein passendes Snippet zum anpassen hab ich schon gefunden und soweit auch nachvollzogen.

      Ich kann die Karte natürlich auch gerne auf meinen Webspace hochladen und hier verlinken.

      Wesentlich hilfreicher scheint mir aber noch was anderes zu sein: Im Dokument werden JS-Bibliotheken eingebunden, vielleicht ist hier der Ansatz "einfacher", wobei ich aber aktuell JS besser nachvollziehen kann. jquery svg-pan-zoom hammer.js

      Das Ziel ist "schlicht", bei einem Treffer der PLZ, die ja vom Kunden selbst stammt, soll das Verkaufsgebiet, zu dem die PLZ gehört, "gehoovert" werden. In der Hoffnung, dass es dann nicht weg ist, falls der Staubsauger zuschlägt :)

      1. problematische Seite

        Hallo Alexander,

        für die Gültigkeitsprüfung KÖNNTEST Du das Pattern-Attribut des input-Elements nehmen:

        <input id="plzInput" type="text" pattern="\d{5}">
        

        Das Pattern ist eine Regex (regular expression), \d bedeutet "Ziffer" und {5} bedeutet "5 Stück davon". Das Pattern gibt Dir 2 Dinge:

        • eine Pseudoklasse :valid im CSS, die Du zum Darstellen von "gut" und "schlecht" verwenden kannst. Das folgende Beispiel zeigt 4 Möglichkeiten, davon sollte man aber je Zustand nur eine verwenden 😉
        #plzInput:valid {
           background-color: green;
           outline: 3px solid green;
        }
        
        #plzInput:not(:valid) {
           background-color: red;
           outline: 3px solid red;
        }
        
        • eine Methode checkValidity() auf dem HTMLInputElement Objekt in JavaScript, die true oder false liefert, je nachdem, ob das Pattern zutrifft. Du kannst also, statt "Eingabe enthält 5 Ziffern" zu programmieren, einfach das input Element fragen, ob sein Pattern korrekt eingehalten wurde.

        Wenn du das mit jQuery tun willst, musst Du das input-Element aus dem Matched Set herausholen, d.h. so geht's nicht:

        if ($("#plzInput").checkValidity()) ...
        

        Hier gibt jemand einen Tipp für eine einfache selbstgemachte Erweiterung von jQuery zur Anbindung von checkValidity.

        Oder Du tust es direkt:

        if ($("#plzInput")[0].checkValidity()) ...
        

        Oder noch direkter, ohne den ollen jQuery-Saurus:

        if (document.getElementById("plzInput").checkValidity()) ...
        

        Wenn Du das in einem Eventhandler für input oder change tust, kannst Du ohnehin event.target verwenden:

        function HandleInputEvent(event) {
           if (event.target.checkValidity()) ...
        }
        

        Um den visuellen Hover-Effekt hinzubekommen, brauchst Du aber noch eigenes CSS. Denn Du kannst die :hover-Zustand nicht programmatisch herbeiführen. Alles, was Du kannst, ist eine Klasse wie bspw. highlight zu setzen und dann im CSS für polygon.highlight das gleiche zu tun wie für polygon:hover.

        Mit dem Effekt, dass ggf. zwei Gebiete hervorgehoben werden. Es könnte nützlich sein, den :hover- und .hightlight-Effekt unterschiedlich darzustellen.

        Rolf

        --
        sumpsi - posui - obstruxi
      2. problematische Seite

        Servus!

        Das Ziel ist "schlicht", bei einem Treffer der PLZ, die ja vom Kunden selbst stammt, soll das Verkaufsgebiet, zu dem die PLZ gehört, "gehoovert" werden. In der Hoffnung, dass es dann nicht weg ist, falls der Staubsauger zuschlägt :)

        Eben nicht!

        Hier ist das aktualisierte Tutorial: SVG/Tutorials/Datenvisualisierung/interaktive_Landkarten

        Im 3. Beispiel kannst du sehen, wie man mit datalist Suchvorschläge anbietet, die dann in einem einfachen Script verarbeitet werden.

        Ich verändere dann den focus, nicht :hover und CSS markiert den Kartenausschnitt: Beispiel:SVG-Landkarten-3.html

        BTW: In SVG kann man wohl nicht von a-Element zu a-Element durchtabben. Das funktioniert erst, wenn ein tabindex hinzugefügt wird.

        Herzliche Grüße

        Matthias Scharwies

        --
        Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
        1. problematische Seite

          Hallo Matthias,

          Das funktioniert erst, wenn ein tabindex hinzugefügt wird.

          a Elemente sind nur mit href interaktiv.

          Rolf

          --
          sumpsi - posui - obstruxi
          1. problematische Seite

            Servus!

            Hallo Matthias,

            Das funktioniert erst, wenn ein tabindex hinzugefügt wird.

            a Elemente sind nur mit href interaktiv.

            Hatte ich im Hinterkopf auch schon überlegt; war aber zu faul, um Bsp. 3 mit href zu realisieren.

            imho sollten im Tutorial eh nur Konzepte vorgestellt werden, die dann anderswo realisiert werden.

            Herzliche Grüße

            Matthias Scharwies

            --
            Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
        2. problematische Seite

          Deswegen das "schlicht" ;)

          Es handelt sich ja um immerhin alle PLZ-Gebiete in Deutschland, die innerhalb des SVG als Polyline definiert sind, wiederum alle zusammengehörigen Gebiete für einen Händler mit einem Polygon umschlossen.

          Aber der genannte Ansatz dürfte mich schon weiterbringen, denn "mehr" brauche ich eigentlich im Endeffekt ja nicht.

          In der Karte ist ja der nötige Effekt schon drin, daher müsste focus tatsächlich schon genügen, um das auszulösen.

          Ich hab mal das, was -das Tool- liefert hier verlinkt: Karte aus Tool damit man ggf. mal reinschauen kann, was an Info zur Verfügung steht.

          Da sind nur wenige Korrekturen drin, hauptsächlich Formatierung wegen Übersichtlichkeit. Jepp, ich weiß, die HTML-Deklaration fehlt etc. aber dass ist das was aus dem Tool direkt kommt.

          Und wieder an der Stelle und an alle: vielen Dank für die Hinweise!

          Bald ist Urlaub, da kann ich mich damit gründlicher befassen ;)

  2. problematische Seite

    Servus!

    Ich habe mit einem Tool eine interaktive SVG-Karte erzeugt, die soweit auch funktioniert. Inhalt sind sämtliche PLZ-Bereiche in D, diesen sind in Vertriebsbereiche zusammengefasst.

    Ziel ist es jetzt, da eine Suchfunktion draufzusetzen, die es dem User erlaubt, seine Postleitzahl anzugeben und damit herauszufinden, welches Vertriebsgebiet für ihn zuständig ist.

    Heisst, bei einem Treffer soll der Hoover-Effekt, der bei einem Mouseover über der Karte ohnehin entsteht, über den PLZ-Parameter ausgelöst werden. innerhalb der Polygone sind die Infos z. B.: id="01067 Dresden" data-info="01067 Dresden" enthalten (für alle PLZ in D).

    Ich vermute stark, dass sich das per JS lösen lässt, habe aber auch nach umfangreicher Suche noch nicht mal ein Beispiel finden können, welches mir auf die Sprünge hilft.

    Sind deine Polygone innerhalb eines a-Element gekapselt? Dann kannst du den :hover-Effekt auch mit der Tabtaste erzielen:

    a:hover polygon,
    a:focus polygon {
      fill: irgendwas;
    }
    

    Dann musst Du beim Suchergebnis ermitteln, welcher Zahlenbereich / Name gewählt ist.

    Dann suchst du das betreffende Polygone, das hoffentlich eine eindeutige id hat, und weist diesem den Focus zu:

    JavaScript/DOM/HTMLOrSVGElement/focus

    Et voilá : farbig markiert.

    Herzliche Grüße

    Matthias Scharwies

    --
    Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
    1. problematische Seite

      Hallo Matthias,

      ist <a> in SVG zulässig? ()

      Edit: Dummer Rolf, natürlich ist es, es gibt ja ein <a> Element in SVG.

      Was ich Alexander gar nicht gefragt habe: Ist das SVG inline im HTML oder ist es eine separate SVG Datei? Letzeres könnte die Aufgabe nämlich gravierend erschweren bis unmöglich machen. Oder kann ich per JS/CSS in ein img-Element mit SVG-Grafik drin hineingreifen?!

      Rolf

      --
      sumpsi - posui - obstruxi
      1. problematische Seite

        Moin Rolf,

        ist dies hier zulässig?

        <svg viewBox="...">
           ...
           <a href="..."><path d="..."></path></a>
           ...
        </svg>
        

        Ja.

        <a> ist doch ein foreign element für SVG …

        Das war es noch nie.

        Viele Grüße
        Robert

      2. problematische Seite

        Hallo Rolf,

        Oder kann ich per JS/CSS in ein img-Element mit SVG-Grafik drin hineingreifen?!

        Über img nicht, da die Grafik hier keinen DOM-Zugriff liefert, also im Grunde statisch gerendert wird. Möglich ist es mittels object-Element und dessen DOM-Kontext via contentDocument.documentElement.

        Grüße,
        Thomas

        1. problematische Seite

          Hallo,

          … Möglich ist es mittels object-Element und dessen DOM-Kontext via contentDocument.documentElement.

          siehe z.B. hier im Wiki.

          Gruß
          Jürgen

          1. problematische Seite

            Hallo JürgenB,

            welch ein gewaltiges Beispiel 😲 - der normalsterbliche Wikileser dürfte daran ordentlich zu nagen haben!

            Über den Codestyle sollten wir aber mal reden - ich glaube, da muss was überarbeitet werden. Ich guck mir das aber erstmal genauer an.

            Rolf

            --
            sumpsi - posui - obstruxi
      3. problematische Seite

        Servus!

        Hallo Matthias,

        ist <a> in SVG zulässig? ()

        Edit: Dummer Rolf, natürlich ist es, es gibt ja ein <a> Element in SVG.

        Was ich Alexander gar nicht gefragt habe: Ist das SVG inline im HTML oder ist es eine separate SVG Datei? Letzeres könnte die Aufgabe nämlich gravierend erschweren bis unmöglich machen. Oder kann ich per JS/CSS in ein img-Element mit SVG-Grafik drin hineingreifen?!

        Es steht eigentlich schon alles im von @Alexander Knapp velrinkten Wiki-Artikel:

        Ich habe die Übersicht etwas übersichtlicher gemacht und das Ansprechen externer SVG-Dokumente extra aufgeführt.

        Den Einsatz des a-Elements kann man hier anschauen: interaktive Landkarte (Leider funktioniert der Focus nicht wie gewünscht. Sollte man dieses Beispiel mit einem Suchfeld und datalist nach den Vorstellungen des TE umbauen?)

        Übrigens: SVG kennt auch video und audio in SVG Tiny 1.2 und bald wieder in SVG2. Immerhin war SMIL mal für Video-Animationen und Untertiel konzipiert worden.

        Herzliche Grüße

        Matthias Scharwies

        --
        Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
        1. problematische Seite

          Hallo Matthias,

          Ich habe die Übersicht etwas übersichtlicher gemacht und das Ansprechen externer SVG-Dokumente extra aufgeführt.

          Kleiner Hinweis zum Beispiel: Wenn beim initialen document.addEventListener('DOMContentLoaded', function () { … } 'load' verwendet wird, sollte auch das SVG-DOM der eingebundenen Grafik bereits etabliert sein.

          Grüße,
          Thomas

          1. problematische Seite

            Servus!

            Hallo Matthias,

            Ich habe die Übersicht etwas übersichtlicher gemacht und das Ansprechen externer SVG-Dokumente extra aufgeführt.

            Kleiner Hinweis zum Beispiel: Wenn beim initialen document.addEventListener('DOMContentLoaded', function () { … } 'load' verwendet wird, sollte auch das SVG-DOM der eingebundenen Grafik bereits etabliert sein.

            Ah, danke!

            Hier noch etwas zu focus:

            https://allyjs.io/tutorials/focusing-in-svg.html Managing focus in SVG

            Herzliche Grüße

            Matthias Scharwies

            --
            Einfach mal was von der ToDo-Liste auf die Was-Solls-Liste setzen.“
            1. problematische Seite

              Hallo Matthias,

              Kleiner Hinweis zum Beispiel: Wenn beim initialen document.addEventListener('DOMContentLoaded', function () { … } 'load' verwendet wird, sollte auch das SVG-DOM der eingebundenen Grafik bereits etabliert sein.

              Ah, danke!

              Wobei das Laden der externen Ressourcen window.addEventListener('load', function () { … } bewerkstelligt.

              Grüße,
              Thomas

          2. problematische Seite

            Hallo ThomasM,

            ja, da stolperte ich in Jürgens Mouse&More Artikel auch gerade drüber. Ich finde das nicht unbedingt gut.

            Das load-Event als Trigger für Scripte, die erst nach Fertigstellung des DOM laufen dürfen, ist anachronistisch. Statt dessen sollte man

            • das Script als "defer" einbinden (oder als type="module", das impliziert defer)
            • das Script am Ende des Body laden
            • den Code in einen DOMContentLoaded Handler packen

            In dieser Priorität.

            Frickl generiert das script-Element hard-coded im <head> (wobei man heutzutage VERMUTLICH schadlos ein defer einbauen könnte), deswegen ist für Wiki-Beispiel die Variante 3 üblich.

            Der andere Aspekt ist die Abhängigkeit bestimmter Codeteile davon, ob eine bestimmte Ressource geladen ist. Nur deswegen das komplette Script im load-Handler laufen zu lassen, finde ich falsch. Statt dessen gehört der Code dann in einen load-Handler zur Ressource. Und bevor man den registriert, würde ich prüfen, ob die Ressource vielleicht doch schon da ist. Bei einem object-Element dürfte das am contentDocument erkennbar sein, etwas anderes finde ich gerade nicht. Oder kann ich mich darauf verlassen, dass zum Zeitpunkt einer DOMContentLoaded- oder defer-Ausführung noch keine externe Ressource komplett geladen ist?

            Rolf

            --
            sumpsi - posui - obstruxi
            1. problematische Seite

              Hallo Rolf,

              ja, da stolperte ich in Jürgens Mouse&More Artikel auch gerade drüber. Ich finde das nicht unbedingt gut.

              load stammt aus einer Zeit, als es mit DOMContendLoaded im Frickl Probleme gab.

              Gruß
              Jürgen

              1. problematische Seite

                Hallo JürgenB,

                dann ist es gut, dass wir drüber reden, denn ich habe das Beispiel runtergeladen, auf DOMContentLoaded geändert und mich erstmal gewundert, warum es Fehlermeldungen hagelte.

                Rolf

                --
                sumpsi - posui - obstruxi
                1. problematische Seite

                  Hallo Rolf,

                  ich habe damals nur mit dem load-Event getestet, daher kann es sein, das es mit dem SVG Probleme gibt. Evtl. muss man sich an das load-Event vom SVG oder vom object hängen.

                  Gruß
                  Jürgen

                  1. problematische Seite

                    Hallo,

                    ich habe den SVG-Zoom mal auf meinem Rechner mit DOMContentLoaded getestet. Wenn ich die Einbindung des auf meinem Rechner nicht vorhandenem wiki-css entferne, läuft es, sonst wird das object mit dem svg nicht gefunden.

                    Wenn ich das Script über das load-Event vom object starte, geht es auch mit der Einbindung:

                    window.addEventListener("DOMContentLoaded",function() {
                    
                      document.querySelector("#selflogo").addEventListener("load",function() {

                    Gruß
                    Jürgen

      4. problematische Seite

        Die Karte ist Inline im Dokument, deswegen ist das Dokument auch nicht gerade klein ;)

        Aber mit all den Puzzlestückchen komme ich denke ich schon mal weiter.

        Jetzt bau ich mir erst Mal das Suchfeld so wie ich es haben will, danach gehts dann um die eigentliche Suche.

        Wichtig ist mir, dass ich hinterher -verstehe- was passiert, sonst lern ich ja nix ;)