Einbinden einer OSM-Karte als Beispiel für Custom Elements – SELFHTML-Blog Das Weblog als Ergänzung zu SELFHTML https://forum.selfhtml.org/weblog?srt=yes Einbinden einer OSM-Karte als Beispiel für Custom Elements Thu, 03 Dec 20 08:52:55 Z https://forum.selfhtml.org/weblog/2020/dec/03/einbinden-einer-osm-karte-als-beispiel-fuer-custom-elements/1782943?srt=yes#m1782943 https://forum.selfhtml.org/weblog/2020/dec/03/einbinden-einer-osm-karte-als-beispiel-fuer-custom-elements/1782943?srt=yes#m1782943 <p>Im Blog-Artikel <a href="https://blog.selfhtml.org/2019/01/13/einstieg-in-leaflet/">Einstieg in Leaflet</a> wurde beschrieben, wie man mit dem Leaflet-API eine Landkarte in seine Seite einbinden kann. Darauf basierend wird in diesem Artikel gezeigt, wie man Custom Elements für eine Landkarte mit Markern erstellen kann.</p> <p>Im <a href="https://wiki.selfhtml.org/wiki/HTML/Web_Components/custom_elements#neue_Elemente">Selfwiki</a> wird das Grundgerüst für die Definition von Custom Elements vorgestellt. Da beim Entfernen des Elements nichts Weiteres passieren soll, und der Fall „Bewegen in ein anderes Dokument“ nicht vorgesehen ist, werden die Methoden disconnectedCallback und adoptedCallback weggelassen.</p> <p>Das Custom Element für die Karte soll <osm-map> sein und die Eckkoordinaten der Karte sollen als Attribute übergeben werden. Die Definition sieht daher so aus:</p> <pre><code class="block language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>osm-map</span> <span class="token attr-name">topleft</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>52.65, 13.2<span class="token punctuation">"</span></span> <span class="token attr-name">bottomright</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>52.35, 13.6<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>osm-map</span><span class="token punctuation">></span></span> </code></pre> <pre><code class="block language-js"><span class="token comment">// Custom-Element osm-map anlegen</span> <span class="token keyword">class</span> <span class="token class-name">osmMap</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLElement</span> <span class="token punctuation">{</span> … <span class="token punctuation">}</span> customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">'osm-map'</span><span class="token punctuation">,</span> osmMap<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>Im Getter observedAttributes wird festgelegt, dass auf die Änderung der Attribute topleft und bottomright reagiert werden soll:</p> <pre><code class="block language-js"> <span class="token keyword">static</span> <span class="token keyword">get</span> <span class="token function">observedAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string">'topleft'</span><span class="token punctuation">,</span> <span class="token string">'bottomright'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>Im Konstruktor muss als erstes die Methode „super“ aufgerufen werden, die den Konstruktor der Elternklasse aufruft:</p> <pre><code class="block language-js"> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>Als nächstes wird dann das Shadow Dom angelegt:</p> <pre><code class="block language-js"> <span class="token keyword">const</span> shadow <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">attachShadow</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">mode</span><span class="token operator">:</span> closed<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>Mode wurde auf „closed“ gesetzt, da von außen nicht per Javascript auf das Shadow Dom zugegriffen werden muss. Für die Landkarte benötigt das Leaflet-API ein DIV, das ins Shadow Dom eingehängt wird:</p> <pre><code class="block language-js"> <span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"mapcanvas"</span><span class="token punctuation">;</span> shadow<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>Dann wird noch ein Stylesheet erstellt, in dem das Leaflet-CSS importiert wird. So ist dieses CSS Teil des Shadow Doms.</p> <pre><code class="block language-js"> <span class="token keyword">const</span> style1 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'style'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Leaflet-CSS laden</span> style1<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">@import url('</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>LeafletBasePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">leaflet.css')</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> shadow<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>style1<span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p>Custom-Elemente sind Inline-Elemente. Um der Karte per css eine Größe geben zu können, erhält das osm-map-Element die Displayeigenschaft block, und das div für die Karte die Größe 100%.</p> <pre><code class="block language-js"> <span class="token keyword">const</span> style2 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'style'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> style2<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> :host { display: block; } .mapcanvas { width: 100%; height: 100%; } </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> shadow<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>style2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>Die Methode connectedCallback wird aufgerufen, wenn das Element ins DOM eingehängt wird. Leaflet orientiert sich beim Erstellen der Karte an den Maßen des Karten-Divs. Da Safari (Stand Dez. 2020) die Style-Regeln verzögert umsetzt, werden hier die kritischen Regeln noch einmal per Javascript gesetzt und dann die Methode makeMap aufgerufen, die die Karte erstellt:</p> <pre><code class="block language-js"> <span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">"block"</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">.</span>style<span class="token punctuation">.</span>height <span class="token operator">=</span> <span class="token string">"100%"</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">.</span>style<span class="token punctuation">.</span>width <span class="token operator">=</span> <span class="token string">"100%"</span><span class="token punctuation">;</span> <span class="token comment">// Karte anlegen</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">makeMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>Die Methode attributeChangedCallback wird bei Attributänderung aufgerufen. Da diese Methode vor der Methode connectedCallback aufgerufen werden kann, muss geprüft werden, ob die Methode makeMap schon gelaufen ist und das Kartenobjekt angelegt hat:</p> <pre><code class="block language-js"> <span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Element-Attribute auslesen</span> <span class="token keyword">let</span> topleft<span class="token punctuation">,</span> bottomright<span class="token punctuation">;</span> topleft <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"topleft"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> bottomright <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"bottomright"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bounds <span class="token operator">=</span> <span class="token punctuation">[</span> topleft<span class="token punctuation">,</span> bottomright <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">.</span><span class="token function">fitBounds</span><span class="token punctuation">(</span> bounds <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </code></pre> <p>Die Methode makeMap liest die Attribute topleft und bottomright erstellt die Karte.</p> <pre><code class="block language-js"> <span class="token function">makeMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Element-Attribute auslesen</span> <span class="token keyword">let</span> topleft<span class="token punctuation">,</span> bottomright<span class="token punctuation">;</span> topleft <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"topleft"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> bottomright <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"bottomright"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bounds <span class="token operator">=</span> <span class="token punctuation">[</span> topleft<span class="token punctuation">,</span> bottomright <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Karte anlegen</span> <span class="token keyword">const</span> osm <span class="token operator">=</span> <span class="token constant">L</span><span class="token punctuation">.</span><span class="token function">tileLayer</span><span class="token punctuation">(</span><span class="token string">'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">maxZoom</span><span class="token operator">:</span> <span class="token number">19</span><span class="token punctuation">,</span> <span class="token literal-property property">attribution</span><span class="token operator">:</span> <span class="token string">'Map data © <a href="https://www.openstreetmap.org/" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> and contributors <a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank" rel="noopener noreferrer">CC-BY-SA</a>'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>map <span class="token operator">=</span> <span class="token constant">L</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">layers</span><span class="token operator">:</span> osm<span class="token punctuation">,</span> <span class="token literal-property property">tap</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token constant">L</span><span class="token punctuation">.</span>control<span class="token punctuation">.</span><span class="token function">scale</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">imperial</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addTo</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">.</span><span class="token function">fitBounds</span><span class="token punctuation">(</span> bounds <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"resize"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">.</span><span class="token function">fitBounds</span><span class="token punctuation">(</span> bounds <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> </code></pre> <p>Auf der Karte sollen auch noch Orte mit einem Marker gekennzeichnet werden können. Das Custom Element sieht so aus:</p> <pre><code class="block language-html"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>osm-marker</span> <span class="token attr-name">latlon</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>52.363860434566206,13.489083283593702<span class="token punctuation">"</span></span> <span class="token attr-name">title</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Flughafen BER<span class="token punctuation">"</span></span> <span class="token attr-name">popup</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Endlich fertig.<span class="token entity named-entity" title="<">&lt;</span>br<span class="token entity named-entity" title=">">&gt;</span>Hat ja kaum noch einer dran geglaubt.<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>osm-marker</span><span class="token punctuation">></span></span> </code></pre> <p>Der Marker hat die Attribute latlon für die Koordinaten, title wird bei hover angezeigt und popup als Inhalt für ein Popup-Fenster, das sich bei Klick auf den Marker öffnet. Die letzten beiden sind optional.</p> <p>Die Definition von osm-marker ist analog zu osm-map aufgebaut. Im Konstruktor wird nur der Basispfad für die Markergrafik angegeben. In connectedCallback wird geprüft, ob das Elternelement des Markers ein osm-map-Element ist und ob die Karte schon angelegt wurde. Wenn beides gegeben ist, wird der Marker erstellt. In attributeChangedCallback wird, wenn der Marker schon angelegt ist, auf das Setzen oder Ändern der jeweiligen Attribute reagiert.</p> <p>Für die Erklärung zu den Methoden makeMap und makeMarker verweise ich auf <a href="https://blog.selfhtml.org/2019/01/13/einstieg-in-leaflet/">Einstieg in Leaflet</a>.</p> <p>Da CSS, Script und Karten-Bilder von Fremdanbietern geladen werden, wird aus Datenschutzgründen gefragt, ob das OK ist. Daher wird das Leaflet-Script erts nach der Zustimmung mit einer Hilfsfunktion geladen, und die Definition der Elemente erfolgt im Callback der Hilfsfunktion. Das Leaflet-CSS wird dann erst in der Element-Definition importiert.</p> <p>Das komplette Script sieht jetzt so aus (<a href="http://test.berkemeier.eu/selfwiki/leaflet/CustomElements/Beispiel_JS-Leaflet_CustomElements.html ">Live Beispiel</a>):</p> <pre><code class="block language-js"><span class="token comment">// Leafletscript laden</span> <span class="token keyword">const</span> LeafletBasePath <span class="token operator">=</span> <span class="token string">"https://unpkg.com/leaflet@1.7.1/dist/"</span><span class="token punctuation">;</span> <span class="token function">loadScript</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>LeafletBasePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">leaflet.js</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Custom-Element osm-map anlegen</span> <span class="token keyword">class</span> <span class="token class-name">osmMap</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLElement</span> <span class="token punctuation">{</span> <span class="token comment">// Festlegen, welche Attribute überwacht werden sollen</span> <span class="token keyword">static</span> <span class="token keyword">get</span> <span class="token function">observedAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string">'topleft'</span><span class="token punctuation">,</span> <span class="token string">'bottomright'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// super muss als erstes in constructor aufgerufen werden, super ruft construcor der Elternklasse auf</span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Shadow Dom anlegen</span> <span class="token keyword">const</span> shadow <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">attachShadow</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'closed'</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Canvas für die Karten anlegen und ins Shadow Dom einhängen</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'div'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">.</span>className <span class="token operator">=</span> <span class="token string">"mapcanvas"</span><span class="token punctuation">;</span> shadow<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// CSS für die Karten anlegen und ins Shadow Dom einhängen</span> <span class="token keyword">const</span> style1 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'style'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Leaflet-CSS laden</span> style1<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">@import url('</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>LeafletBasePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">leaflet.css')</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> shadow<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>style1<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> style2 <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span><span class="token string">'style'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> style2<span class="token punctuation">.</span>textContent <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string"> :host { display: block; } .mapcanvas { width: 100%; height: 100%; } </span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> shadow<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>style2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Safari setzt die folgenden Angaben verspätet bzw. erst bei Reload um ??? Daher direktes Setzen im connectedCallback</span> <span class="token keyword">this</span><span class="token punctuation">.</span>style<span class="token punctuation">.</span>display <span class="token operator">=</span> <span class="token string">"block"</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">.</span>style<span class="token punctuation">.</span>height <span class="token operator">=</span> <span class="token string">"100%"</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">.</span>style<span class="token punctuation">.</span>width <span class="token operator">=</span> <span class="token string">"100%"</span><span class="token punctuation">;</span> <span class="token comment">// Karte anlegen</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">makeMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// attributeChangedCallback kommt vor connectedCallback, daher prüfen, ob makeMap schon gelaufen ist.</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Element-Attribute auslesen</span> <span class="token keyword">let</span> topleft<span class="token punctuation">,</span> bottomright<span class="token punctuation">;</span> topleft <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"topleft"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> bottomright <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"bottomright"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bounds <span class="token operator">=</span> <span class="token punctuation">[</span> topleft<span class="token punctuation">,</span> bottomright <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">.</span><span class="token function">fitBounds</span><span class="token punctuation">(</span> bounds <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">makeMap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Element-Attribute auslesen</span> <span class="token keyword">let</span> topleft<span class="token punctuation">,</span> bottomright<span class="token punctuation">;</span> topleft <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"topleft"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> bottomright <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"bottomright"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> bounds <span class="token operator">=</span> <span class="token punctuation">[</span> topleft<span class="token punctuation">,</span> bottomright <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Karte anlegen</span> <span class="token keyword">const</span> osm <span class="token operator">=</span> <span class="token constant">L</span><span class="token punctuation">.</span><span class="token function">tileLayer</span><span class="token punctuation">(</span><span class="token string">'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">maxZoom</span><span class="token operator">:</span> <span class="token number">19</span><span class="token punctuation">,</span> <span class="token literal-property property">attribution</span><span class="token operator">:</span> <span class="token string">'Map data © &lt;a href="https://www.openstreetmap.org/" target="_blank"&gt;OpenStreetMap&lt;/a&gt; and contributors &lt;a href="https://creativecommons.org/licenses/by-sa/2.0/" target="_blank"&gt;CC-BY-SA&lt;/a&gt;'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> map <span class="token operator">=</span> <span class="token constant">L</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>mapcanvas<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">layers</span><span class="token operator">:</span> osm<span class="token punctuation">,</span> <span class="token literal-property property">tap</span><span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>map <span class="token operator">=</span> map<span class="token punctuation">;</span> <span class="token constant">L</span><span class="token punctuation">.</span>control<span class="token punctuation">.</span><span class="token function">scale</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">imperial</span><span class="token operator">:</span><span class="token boolean">false</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addTo</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span> map<span class="token punctuation">.</span><span class="token function">fitBounds</span><span class="token punctuation">(</span> bounds <span class="token punctuation">)</span><span class="token punctuation">;</span> map<span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">"resize"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token punctuation">{</span> map<span class="token punctuation">.</span><span class="token function">fitBounds</span><span class="token punctuation">(</span> bounds <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">'osm-map'</span><span class="token punctuation">,</span> osmMap<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Custom-Element osm-marker anlegen</span> <span class="token keyword">class</span> <span class="token class-name">osmMarker</span> <span class="token keyword">extends</span> <span class="token class-name">HTMLElement</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token keyword">get</span> <span class="token function">observedAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token string">'latlon'</span><span class="token punctuation">,</span> <span class="token string">'title'</span><span class="token punctuation">,</span> <span class="token string">'popup'</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token constant">L</span><span class="token punctuation">.</span>Icon<span class="token punctuation">.</span><span class="token class-name">Default</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span>options<span class="token punctuation">.</span>imagePath <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>LeafletBasePath<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">images/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">connectedCallback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>parentNode <span class="token operator">||</span> <span class="token keyword">this</span><span class="token punctuation">.</span>parentNode<span class="token punctuation">.</span>nodeName<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token string">"osm-map"</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"CB: Kein osm-map-Element als Elternelement gefunden."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">this</span><span class="token punctuation">.</span>map <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>parentNode<span class="token punctuation">.</span>map<span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"CB: Kein Elternelement mit Karte gefunden."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">makeMarker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">attributeChangedCallback</span><span class="token punctuation">(</span><span class="token parameter">name<span class="token punctuation">,</span> oldValue<span class="token punctuation">,</span> newValue</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Geändertes Element-Attribut auslesen</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>marker<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">switch</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">case</span> <span class="token string">"latlon"</span><span class="token operator">:</span> <span class="token keyword">const</span> latlon <span class="token operator">=</span> newValue<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>marker<span class="token punctuation">.</span><span class="token function">setLatLng</span><span class="token punctuation">(</span>latlon<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token string">"title"</span><span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>marker<span class="token punctuation">.</span>options<span class="token punctuation">.</span>title <span class="token operator">=</span> newValue<span class="token punctuation">;</span> <span class="token comment">// Zeigt beim Marker keine Wirkung</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token keyword">case</span> <span class="token string">"popup"</span><span class="token operator">:</span> <span class="token keyword">const</span> title <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span><span class="token string">"title"</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"title"</span><span class="token punctuation">)</span><span class="token operator">:</span><span class="token string">""</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>newValue<span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>marker<span class="token punctuation">.</span><span class="token function">bindPopup</span><span class="token punctuation">(</span><span class="token string">"&lt;h3&gt;"</span><span class="token operator">+</span>title<span class="token operator">+</span><span class="token string">"&lt;/h3&gt;"</span><span class="token operator">+</span>newValue<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">break</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">makeMarker</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Alle Element-Attribute auslesen</span> <span class="token keyword">let</span> latlon<span class="token punctuation">,</span> title<span class="token operator">=</span><span class="token string">""</span><span class="token punctuation">,</span> popup<span class="token operator">=</span><span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span><span class="token string">"latlon"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> latlon <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"latlon"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>Number<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span><span class="token string">"title"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> title <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"title"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">hasAttribute</span><span class="token punctuation">(</span><span class="token string">"popup"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> popup <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">"popup"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Marker anzeigen</span> <span class="token keyword">this</span><span class="token punctuation">.</span>marker <span class="token operator">=</span> <span class="token constant">L</span><span class="token punctuation">.</span><span class="token function">marker</span><span class="token punctuation">(</span>latlon<span class="token punctuation">,</span><span class="token punctuation">{</span><span class="token literal-property property">title</span><span class="token operator">:</span>title<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">addTo</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span>popup<span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>marker<span class="token punctuation">.</span><span class="token function">bindPopup</span><span class="token punctuation">(</span><span class="token string">"&lt;h3&gt;"</span><span class="token operator">+</span>title<span class="token operator">+</span><span class="token string">"&lt;/h3&gt;"</span><span class="token operator">+</span>popup<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> customElements<span class="token punctuation">.</span><span class="token function">define</span><span class="token punctuation">(</span><span class="token string">'osm-marker'</span><span class="token punctuation">,</span> osmMarker<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> </code></pre> <p><a href="http://test.berkemeier.eu/selfwiki/leaflet/CustomElements/Beispiel_JS-Leaflet_CustomElements.html">Live Beispiel</a></p> <p>Um zu testen, ob die Custom-Elemente auch dynamisch geladen und modifiziert werden können, gibt es in der Testseite noch einen Eventhandler für das load-Event, der diese Tests durchführt.</p>