Linuchs: Leaflet: „Sprechende“ Marker aus mehreren Bildern zusammensetzen?

problematische Seite

Moin,

habe bei meiner Recherche keine Lösung gefunden, vermutlich gibt's auch keine. Sehr speziell.

Auf der Europakarte der Vereine unterscheide ich Mitglieder von Interessenten .

Wenn eine Hörprobe vorliegt, nehme ich stattdessen die Marker und

Bei Videos auf der Webseite zwei weitere Marker, macht sechs.

Nun können die Vereine ein kurzes Statement abgeben, wie sie mit Corona klarkommen. Dazu möchte ich den Markern einen Stern hinzufügen, was die Markerzahl nochmal verdoppelt.

Wäre fein, wenn ich einen Marker zusammensetzen könnte dort wo er definiert wird:

// Marker (Bild) definieren
var marker_blau_audio = L.icon({
  iconUrl:      'img/marker_blau_audio_25_41.png',
  shadowUrl:    '',
  iconSize:     [25, 41],     // size of the icon
  shadowSize:   [ 0,  0],     // size of the shadow
  iconAnchor:   [12, 41],     // point of the icon which will correspond to marker's location - rechts, oben
  shadowAnchor: [ 0,  0],     // the same for the shadow
  popupAnchor:  [ 0,-41]      // point from which the popup should open relative to the iconAnchor
});

Gruß, Linuchs

  1. problematische Seite

    Hallo Linuchs,

    das einzige, was mir einfiele, wäre eine Overlaytechnik. Dafür hast Du einen roten oder blauen Basismarker, und legst nach Bedarf Symbole für Audio, Video oder Sternchen mit transparentem Hintergrund darüber. Das können GIF oder PNG mit transparentem Hintergrund sein, oder SVGs (für IE11 Unterstützung müssen die SVGs passend gebaut sein).

    D.h. entweder hast Du bei 500 Vereinen 500 Marker, aber 12 verschiedene Icons für die Marker und weitere Verdopplungen, wenn noch was dazu kommt. Oder Du hast nur 5 Icons (rot, blau, audio-Overlay, video-Overlay, corona-Overlay), von denen Du pro Verein 1-3 Stück zeigst. Das kann man so lösen, dass Du an dem HTML Element mit dem Marker darin Klassen setzt, und im CSS je nach gesetzten Klassen das background-image zurechtstapelst. Oder mit ::after und ::before Zusatzebenen hinzufügst. Wenn es nur audio/video und corona ist, kommt man mit ::before und ::after gerade so hin 😀:

    Allerdings: die Zugänglichkeit dieser Konstruktion - oder generell der Marker-Konstruktion - müsste man noch genauer betrachten. Entweder durch visuell versteckten Text im div oder durch geeignete aria-Attribute.

    <div class="marker red audio corona" style="top:...; left: ..."></div>
    
    .marker {
       position: absolute;
       width: ..., height: ...;
    }
    .marker.red {
       background-image: red-icon.png;
    }
    .marker.blue {
       background-image: red-icon.png;
    }
    .marker.audio::before {
       position:absolute; 
       background-image: audio-icon.png;
       z-index: 1;
    }
    .marker.video::before {
       position:absolute; 
       background-image: audio-icon.png;
       z-index: 1;
    }
    .marker.infos::after {
       position:absolute; 
       background-image: infos-icon.png;
       z-index: 2;
    }
    

    Also - viele Icons oder Stapeltechnik, für eins von beiden musst Du Dich wohl entscheiden. Wie setzt Du die Marker? Per JS am Client? Oder erzeugst Du das HTML dafür am Server mit PHP? Wenn es PHP ist, würde ich bei vielen unterschiedlichen Icons bleiben, auf diese Weise transferierst Du deutlich weniger HTML. Wenn es JS ist, dann würde ich sagen: es ist netzwerktechnisch egal, du sparst Dir nur die Arbeit, viele Iconvarianten zu pflegen.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. problematische Seite

      Hallo Rolf,

      einen roten oder blauen Basismarker, und legst nach Bedarf Symbole für Audio, Video oder Sternchen mit transparentem Hintergrund darüber.

      Ging mir auch durch den Kopf. Dann wäre aber der Basismarker nicht mehr anklickbar, weil er abgedeckt ist. Man könnte ihn vielleicht transparent oben drauflegen ...

      Wie setzt Du die Marker? Per JS am Client?

      Genau. Die (hunderte) Marker werden per CSV-String an den Client übergeben. Kannst du im HTML-Code sehen. Wird erstaunlich flott vom Client platziert.

      Mit deinem ::before und ::after experimentiere ich, wenn die Idee von Jürgen nicht funktioniert, etwas an den Basismarker „anzukleben“.

      Gruß Linuchs

    2. problematische Seite

      Hallo Rolf B,

      das einzige, was mir einfiele, wäre eine Overlaytechnik.

      Ein Sprite oder gestapelte Hintergrundgrafiken wären auch denkbar.

      Bis demnächst
      Matthias

      --
      Du kannst das Projekt SELFHTML unterstützen,
      indem du bei Amazon-Einkäufen Amazon smile (Was ist das?) nutzt.
      1. problematische Seite

        Hallo ihr beiden,

        das einzige, was mir einfiele, wäre eine Overlaytechnik.

        Ein Sprite oder gestapelte Hintergrundgrafiken wären auch denkbar.

        es ist hier vieles denkbar, aber das Mittel der Wahl ist das, was Leaflet dafür vorgesehen hat: divIcon

        Gruß
        Jürgen

        1. problematische Seite

          Hallo JürgenB,

          ok, Leaflet kenne ich nicht und wusste auch nicht (mehr), dass Linuchs das einsetzt. Daher kam ich mit "Bordmitteln" an.

          Rolf

          --
          sumpsi - posui - obstruxi
  2. problematische Seite

    Hallo Linuchs,

    kennst du L.divIcon? Mit folgendem Code ertstelle ich ein Icon mit Text (label) darüber, nur mal so als Anregung:

    	Cluster_Icon = { icon:   { anchor: {x:16,y:16}, url: baseurl+"Icons/cluster.svg", 
    											scaledSize: { width: 31, height: 31, widthUnit: "px", heightUnit: "px" },
    											size: { width: 31, height: 31, widthUnit: "px", heightUnit: "px" } } };
    
    icon = Cluster_Icon;
    
    JB.Map.prototype.setClusterMarker = function(coord,icon,title,label) { 
    	var url = icon.icon.url;
    	var w = icon.icon.size.width + icon.icon.size.widthUnit;
    	var h = icon.icon.size.height + icon.icon.size.heightUnit;
    	var marker = [];
    	var html = "<div style='background-image:url("+url+");background-repeat: no-repeat;width:"+w+";height:"+h+"'><div>"+label+"</div></div>";
    	var thisicon = L.divIcon({className:"JBcluster-icon", html: html, iconAnchor: [icon.icon.anchor.x, icon.icon.anchor.y] });
    	marker[0] = L.marker(coord, {icon: thisicon, title: title, zIndexOffset: 500 } ); 
    	marker[0].addTo(this.map);
    	return marker;
    } // setClusterMarker
    
    div.JBcluster-icon > div { display: flex; align-items: center; justify-content: center; font-weight: bold }
    

    Gruß
    Jürgen

    1. problematische Seite

      Hallo Jürgen,

      sieht sehr kryptisch aus.

      Kannst du bitte mal einen Link nennen oder hier ein Bild der Marker posten?

      Gruß, Linuchs

      1. problematische Seite

        Habe hier mal etwas rumgespielt mit diesem Ergebnis:

        Doch der Stern ist ein vollkommen eigenständiger HTML-Marker, der mit eigenem lat/lon platziert werden muss. Je nach Zoom-Faktor dürfte er näher oder weiter vom Haupt-Marker entfernt sein, das konnte ich bei jsfiddle nicht testen.

        Geht das auch als Anhängsel zum vorhandenen Marker?

        Linuchs

        1. problematische Seite

          Hallo Linuchs,

          Habe hier mal etwas rumgespielt mit diesem Ergebnis:

          Doch der Stern ist ein vollkommen eigenständiger HTML-Marker, der mit eigenem lat/lon platziert werden muss. Je nach Zoom-Faktor dürfte er näher oder weiter vom Haupt-Marker entfernt sein, das konnte ich bei jsfiddle nicht testen.

          Geht das auch als Anhängsel zum vorhandenen Marker?

          ja, siehe meine andere Antwort.

          Ansonsten kannt du den Ursprung des Icons ja auch in Pixeln angeben und so Marker und Stern an die gleichen Koordinaten setzen, den Stern dann aber etwas weniger als die halbe Größe des Markers verschieben.

          Gruß
          Jürgen

      2. problematische Seite

        Hallo Linuchs,

        https://www.j-berkemeier.de/GPXViewer/Beispiel9.html

        Die roten Icons mit der Zahl in der Mitte sind mit dem gezeigten Code erstellt.

        Ich verwende die Methode L.divIcon, um die Icons zu erstellen. Dabei wird eigentlich nur ein HTML-Element frei auf der Karte positioniert.

        	var html = "<div style='background-image:url("+url+");background-repeat: no-repeat;width:"+w+";height:"+h+"'><div>"+label+"</div></div>";
        	var thisicon = L.divIcon({className:"JBcluster-icon", html: html, iconAnchor: [icon.icon.anchor.x, icon.icon.anchor.y] });
        

        erstellt das Icon. Die URL und weitere Parameter wie Offset und Größe hole ich aus einer Datenstruktur.

        Ich nehme als Grundelement ein div mit Hintergrundbild, und als Inhalt den Text.

        	marker[0] = L.marker(coord, {icon: thisicon, title: title, zIndexOffset: 500 } ); 
        

        erzeugt dann das Icon, das sich wie ein "normales" Icon verhält.

        Gruß
        Jürgen

        1. problematische Seite

          Hallo JürgenB,

          nun gut, aber das ist die Leaflet-spezifische Hülle um das Ganze.

          Im Inneren besteht wieder das ursprüngliche Problem. Viele verschiedene Icons, oder die Montage mehrerer Layer zu einem Bild. So wie von mir oben schon angesprochen.

          Und viel inline style, der vermutlich gerne im Stylesheet landen möchte.

          Rolf

          --
          sumpsi - posui - obstruxi