leaflet-html 0.1.6 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head lang="en">
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>GeoJSON</title>
7
+ <link
8
+ rel="stylesheet"
9
+ href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
10
+ integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
11
+ crossorigin=""
12
+ />
13
+ <script
14
+ src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
15
+ integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
16
+ crossorigin=""
17
+ ></script>
18
+ <script type="module" src="/src/index.js"></script>
19
+ <style>
20
+ * {
21
+ margin: 0;
22
+ }
23
+ l-map {
24
+ display: block;
25
+ height: 100vh;
26
+ }
27
+ </style>
28
+ </head>
29
+ <body>
30
+ <l-map center="[55,0]" zoom="5">
31
+ <l-tile-layer
32
+ url-template="https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png"
33
+ ></l-tile-layer>
34
+ <l-geojson id="feature" geojson='{"type":"Feature","properties":{"name":"Coors Field","amenity":"Baseball Stadium","popupContent":"This is where the Rockies play!"},"geometry":{"type":"Point","coordinates":[-104.99404,39.75621]}}'></l-geojson>
35
+ </l-map>
36
+ <script>
37
+ document.getElementById("feature").addEventListener("map:addTo", (ev) => {
38
+ console.log({ message: "Hello, World!", ev })
39
+ })
40
+ </script>
41
+ </body>
42
+ </html>
@@ -15,7 +15,8 @@
15
15
  crossorigin=""
16
16
  ></script>
17
17
  <script
18
- src="/dist/leaflet-html.umd.js"
18
+ src="/src/index.js"
19
+ type="module"
19
20
  defer
20
21
  ></script>
21
22
  <style>
@@ -23,18 +24,21 @@
23
24
  margin: 0;
24
25
  }
25
26
 
26
- [data-leaflet-html] {
27
+ l-map {
27
28
  block-size: 100vh;
28
29
  isolation: isolate;
29
30
  z-index: 1;
30
31
  }
31
32
 
32
- #btn {
33
+ .btn-group {
33
34
  z-index: 2;
34
35
  position: absolute;
35
36
  bottom: 0;
36
37
  left: 0;
37
38
  margin: 1rem;
39
+ }
40
+
41
+ button {
38
42
  padding: 1rem;
39
43
  background-color: #337;
40
44
  color: white;
@@ -42,62 +46,66 @@
42
46
  cursor: pointer;
43
47
  font-size: 1.2rem;
44
48
  }
49
+
50
+ body {
51
+ display: grid;
52
+ grid-template-columns: 1fr 1fr;
53
+ }
45
54
  </style>
46
55
  </head>
47
56
  <body>
48
- <div data-leaflet-html data-center="[39.61, -105.02]" data-zoom="10">
49
- <div data-control-layers>
50
- <div data-base-maps>
51
- <div
52
- data-tile-layer
53
- data-name="OpenStreetMap"
54
- data-url-template="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
55
- data-attribution='&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
56
- data-max-zoom="12"
57
- ></div>
58
- <div
59
- data-tile-layer
60
- data-name="CartoDB_Voyager"
61
- data-url-template="https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png"
62
- data-attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
63
- data-max-zoom="20"
64
- data-subdomains="abcd"
65
- data-show
66
- ></div>
67
- </div>
68
- <div data-overlay-maps>
69
- <div data-layer-group data-name="Cities">
70
- <div data-marker data-lat-lng="[39.61, -105.02]">
71
- <div data-popup data-content="This is Littleton, CO."></div>
72
- </div>
73
- <div data-marker data-lat-lng="[39.74, -104.99]">
74
- <div data-popup data-content="This is Denver, CO."></div>
75
- </div>
76
- <div data-marker data-lat-lng="[39.73, -104.8]" data-opacity="0.7">
77
- <div data-popup data-content="This is Aurora, CO."></div>
78
- </div>
79
- <div data-marker data-lat-lng="[39.77, -105.23]">
80
- <div data-popup data-content="This is Golden, CO."></div>
81
- </div>
82
- </div>
83
- </div>
84
- </div>
57
+ <l-map center="[39.61, -105.02]" zoom="10">
58
+ <l-control-layers>
59
+ <l-base-layers>
60
+ <l-tile-layer
61
+ name="OpenStreetMap"
62
+ url-template="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
63
+ attribution='&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
64
+ max-zoom="12"
65
+ ></l-tile-layer>
66
+ <l-tile-layer
67
+ name="CartoDB_Voyager"
68
+ url-template="https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png"
69
+ attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>'
70
+ max-zoom="20"
71
+ subdomains="abcd"
72
+ ></l-tile-layer>
73
+ </l-base-layers>
74
+ <l-overlay-layers>
75
+ <l-layer-group name="Cities">
76
+ <l-marker lat-lng="[39.61, -105.02]">
77
+ <l-popup content="This is Littleton, CO."></l-popup>
78
+ </l-marker>
79
+ <l-marker lat-lng="[39.74, -104.99]">
80
+ <l-popup content="This is Denver, CO."></l-popup>
81
+ </l-marker>
82
+ <l-marker lat-lng="[39.73, -104.8]" opacity="0.7">
83
+ <l-popup content="This is Aurora, CO."></l-popup>
84
+ </l-marker>
85
+ <l-marker lat-lng="[39.77, -105.23]">
86
+ <l-popup content="This is Golden, CO."></l-popup>
87
+ </l-marker>
88
+ </l-layer-group>
89
+ </l-overlay-layers>
90
+ </l-control-layers>
91
+ </l-map>
92
+ <div class="btn-group">
93
+ <button id="btn-move">Move Denver</button>
94
+ <button id="btn-remove">Remove Denver</button>
85
95
  </div>
86
- <button id="btn">Add a city</button>
87
96
  <script type="module">
88
97
  // Manual tests
89
- document.getElementById("btn").addEventListener("click", () => {
90
- // New city
91
- let el = document.querySelector('[data-name="Cities"]');
92
- const city = document.createElement("div");
93
- city.dataset.marker = "";
94
- city.dataset.latLng = "[39.60, -105.02]";
95
- el.appendChild(city);
96
-
98
+ document.getElementById("btn-remove").addEventListener("click", () => {
97
99
  // Remove Denver
98
- el = document.querySelector('[data-lat-lng="[39.74, -104.99]"]');
100
+ let el = document.querySelector('[lat-lng="[39.74, -104.99]"]');
99
101
  el.remove();
100
102
  });
103
+ document.getElementById("btn-move").addEventListener("click", () => {
104
+ // Move Denver
105
+ let el = document.querySelector('[lat-lng="[39.74, -104.99]"]');
106
+ el.setAttribute("lat-lng", "[39.74, -104.89]");
107
+ el.setAttribute("opacity", "0.5");
108
+ });
101
109
  </script>
102
110
  </body>
103
111
  </html>
@@ -15,60 +15,59 @@
15
15
  integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
16
16
  crossorigin=""
17
17
  ></script>
18
- <script src="/dist/leaflet-html.umd.js"></script>
18
+ <script type="module" src="/src/index.js"></script>
19
19
  <style>
20
20
  * {
21
21
  margin: 0;
22
22
  }
23
23
 
24
- [data-leaflet-html] {
24
+ l-map {
25
+ display: block;
25
26
  block-size: 100vh;
27
+ outline: 1px solid hotpink;
26
28
  isolation: isolate;
27
29
  z-index: 1;
28
30
  }
29
31
  </style>
30
32
  </head>
31
33
  <body>
32
- <div data-leaflet-html data-center="[37.8, -96]" data-zoom="4">
33
- <div
34
- data-lat-lng-bounds
35
- data-bounds="[[40.799311, -74.118464], [40.68202047785919, -74.33]]"
36
- ></div>
37
- <div
38
- data-tile-layer
39
- data-name="OpenStreetMap"
40
- data-url-template="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
41
- data-attribution=""
42
- ></div>
34
+ <l-map center="[37.8, -96]" zoom="4">
35
+ <l-lat-lng-bounds
36
+ bounds="[[40.799311, -74.118464], [40.68202047785919, -74.33]]"
37
+ ></l-lat-lng-bounds>
38
+ <l-tile-layer
39
+ name="OpenStreetMap"
40
+ url-template="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
41
+ attribution=""
42
+ ></l-tile-layer>
43
43
  <!-- Newark -->
44
- <div
45
- data-image-overlay
46
- data-url="https://maps.lib.utexas.edu/maps/historical/newark_nj_1922.jpg"
47
- data-bounds="[[40.799311, -74.118464], [40.68202047785919, -74.33]]"
48
- data-opacity="0.8"
49
- data-interactive="true"
50
- data-error-overlay-url="https://cdn-icons-png.flaticon.com/512/110/110686.png"
51
- data-alt="Image of Newark, N.J. in 1922. Source: The University of Texas at Austin, UT Libraries Map Collection."
52
- ></div>
44
+ <l-image-overlay
45
+ url="https://maps.lib.utexas.edu/maps/historical/newark_nj_1922.jpg"
46
+ bounds="[[40.799311, -74.118464], [40.68202047785919, -74.33]]"
47
+ opacity="0.8"
48
+ interactive="true"
49
+ error-overlay-url="https://cdn-icons-png.flaticon.com/512/110/110686.png"
50
+ alt="Image of Newark, N.J. in 1922. Source: The University of Texas at Austin, UT Libraries Map Collection."
51
+ ></l-image-overlay>
53
52
  <!-- Hurricane Patricia -->
54
- <div
55
- data-video-overlay
56
- data-url='["https://www.mapbox.com/bites/00188/patricia_nasa.webm", "https://www.mapbox.com/bites/00188/patricia_nasa.mp4"]'
57
- data-error-overlay-url="https://cdn-icons-png.flaticon.com/512/110/110686.png"
58
- data-bounds="[[32, -130], [13, -100]]"
59
- ></div>
60
- </div>
53
+ <l-video-overlay
54
+ url='["https://www.mapbox.com/bites/00188/patricia_nasa.webm", "https://www.mapbox.com/bites/00188/patricia_nasa.mp4"]'
55
+ error-overlay-url="https://cdn-icons-png.flaticon.com/512/110/110686.png"
56
+ bounds="[[32, -130], [13, -100]]"
57
+ ></l-video-overlay>
58
+ </l-map>
59
+
61
60
  <script>
62
- el = document.querySelector("[data-lat-lng-bounds]")
61
+ el = document.querySelector("l-lat-lng-bounds")
63
62
  let counter = 0
64
63
  document.body.addEventListener("click", () => {
65
- console.log("click")
64
+ el.setAttribute("method", "flyToBounds")
66
65
  if (counter === 0) {
67
- const { bounds } = document.querySelector("[data-video-overlay]").dataset
68
- el.dataset.bounds = bounds
66
+ const bounds = document.querySelector("l-video-overlay").getAttribute("bounds")
67
+ el.setAttribute("bounds", bounds)
69
68
  } else {
70
- const { bounds } = document.querySelector("[data-image-overlay]").dataset
71
- el.dataset.bounds = bounds
69
+ const bounds = document.querySelector("l-image-overlay").getAttribute("bounds")
70
+ el.setAttribute("bounds", bounds)
72
71
  }
73
72
  counter += 1
74
73
  })
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "leaflet-html",
3
3
  "type": "module",
4
- "version": "0.1.6",
4
+ "version": "0.2.0",
5
5
  "description": "Leaflet expressed in HTML",
6
6
  "source": "src/index.js",
7
7
  "main": "./dist/leaflet-html.js",
8
8
  "umd:main": "./dist/leaflet-html.umd.js",
9
9
  "exports": {
10
- "default": "./dist/leaflet-html.js"
10
+ "module": "./dist/leaflet-html.js"
11
11
  },
12
12
  "module": "./dist/leaflet-html.esm.js",
13
13
  "author": "andrewgryan",
package/src/events.js ADDED
@@ -0,0 +1,3 @@
1
+ export const mapAddTo = "map:addTo"
2
+ export const popupAdd = "popup:add"
3
+ export const layerRemove = "layer:remove"
package/src/index.js CHANGED
@@ -1,191 +1,32 @@
1
1
  // @ts-check
2
+ import LBaseLayers from "./l-base-layers.js";
3
+ import LControlLayers from "./l-control-layers.js";
4
+ import LLayerGroup from "./l-layer-group.js";
5
+ import LMap from "./l-map.js";
6
+ import LMarker from "./l-marker.js";
7
+ import LOverlayLayers from "./l-overlay-layers.js";
8
+ import LPopup from "./l-popup.js";
9
+ import LTileLayer from "./l-tile-layer.js";
10
+ import LLatLngBounds from "./l-lat-lng-bounds.js";
11
+ import LImageOverlay from "./l-image-overlay.js";
12
+ import LVideoOverlay from "./l-video-overlay.js";
13
+ import LGeoJSON from "./l-geojson.js";
2
14
 
3
- // Helpers
4
- const selector = (noun) => `[data-${noun}]`;
5
-
6
- /**
7
- * Parse L.tileLayer args from element attributes
8
- */
9
- const parseTileLayer = (el) => {
10
- const { urlTemplate } = el.dataset;
11
- const {
12
- attribution = null,
13
- maxZoom = "18",
14
- minZoom = "0",
15
- subdomains = "abc",
16
- } = el.dataset;
17
- const options = { attribution, maxZoom, minZoom, subdomains };
18
- return [urlTemplate, options];
19
- };
20
-
21
- /**
22
- * Parse L.imageOverlay args from element attributes
23
- */
24
- const parseImageOverlay = (el) => {
25
- let { url, bounds } = el.dataset;
26
- bounds = JSON.parse(bounds);
27
- const { opacity } = el.dataset;
28
- const options = { opacity: parseFloat(opacity) };
29
- return [url, bounds, options];
30
- };
31
-
32
- /**
33
- * Parse L.imageOverlay args from element attributes
34
- */
35
- const parseVideoOverlay = (el) => {
36
- let { url, bounds } = el.dataset;
37
- url = JSON.parse(url);
38
- bounds = JSON.parse(bounds);
39
- const {
40
- opacity,
41
- errorOverlayUrl,
42
- autoplay = true,
43
- muted = true,
44
- playsInline = true,
45
- } = el.dataset;
46
- const options = {
47
- opacity: parseFloat(opacity),
48
- errorOverlayUrl,
49
- autoplay,
50
- muted,
51
- playsInline,
52
- };
53
- return [url, bounds, options];
54
- };
55
-
56
- /**
57
- * @param {HTMLElement} el
58
- */
59
- const parseLatLngBounds = (el) => {
60
- let { bounds } = el.dataset;
61
- if (typeof bounds === "undefined") {
62
- throw Error("data-bounds not specified")
63
- }
64
- return [JSON.parse(bounds)];
65
- }
66
-
67
- const render = () => {
68
- // Render Leaflet API calls
69
- document.querySelectorAll(selector("leaflet-html")).forEach((el) => {
70
- const { center, zoom } = el.dataset;
71
- const map = L.map(el).setView(JSON.parse(center), parseInt(zoom));
72
-
73
- // L.latLngBounds
74
- el.querySelectorAll(selector("lat-lng-bounds")).forEach((el) => {
75
- const bounds = L.latLngBounds(...parseLatLngBounds(el))
76
- // TODO: encapsulate this design pattern
77
- const observer = new MutationObserver(function (mutations) {
78
- mutations.forEach((mutation) => {
79
- let [bounds] = parseLatLngBounds(mutation.target)
80
- map.flyToBounds(bounds); // TODO: Use HTML attrs for fly/fit bounds
81
- });
82
- });
83
- observer.observe(el, {
84
- attributes: true,
85
- attributeFilter: ["data-bounds"],
86
- });
87
- map.fitBounds(bounds)
88
- })
89
-
90
- // L.tileLayers
91
- el.querySelectorAll(selector("tile-layer")).forEach((el) => {
92
- L.tileLayer(...parseTileLayer(el)).addTo(map);
93
- });
94
-
95
- el.querySelectorAll(selector("image-overlay")).forEach((el) => {
96
- L.imageOverlay(...parseImageOverlay(el)).addTo(map);
97
- });
98
-
99
- el.querySelectorAll(selector("video-overlay")).forEach((el) => {
100
- L.videoOverlay(...parseVideoOverlay(el)).addTo(map);
101
- });
102
-
103
- // L.control.layers
104
- el.querySelectorAll(selector("control-layers")).forEach((el) => {
105
- const baseMaps = {};
106
-
107
- // L.tileLayers
108
- el.querySelectorAll(selector("tile-layer")).forEach((el) => {
109
- const { name, show } = el.dataset;
110
- baseMaps[name] = L.tileLayer(...parseTileLayer(el));
111
- if (show != null) {
112
- baseMaps[name].addTo(map);
113
- }
114
- });
115
-
116
- const overlayMaps = {};
117
- // L.layerGroup
118
- el.querySelectorAll(selector("layer-group")).forEach((el) => {
119
- const { name } = el.dataset;
120
- const layers = [];
121
-
122
- const observer = new MutationObserver(function (mutations) {
123
- const group = overlayMaps[name];
124
-
125
- mutations.forEach((mutation) => {
126
- mutation.addedNodes.forEach((node) => {
127
- const { latLng } = node.dataset; // MutationObserver needed
128
- const layer = L.marker(JSON.parse(latLng));
129
- group.addLayer(layer);
130
- map.addLayer(layer);
131
- });
132
-
133
- mutation.removedNodes.forEach((node) => {
134
- const { _leafletId } = node.dataset;
135
- const layer = group.getLayer(_leafletId);
136
- group.removeLayer(layer);
137
-
138
- map.removeLayer(layer);
139
- });
140
- });
141
- });
142
- observer.observe(el, { childList: true });
143
-
144
- // L.marker
145
- el.querySelectorAll(selector("marker")).forEach((el) => {
146
- const { latLng } = el.dataset;
147
- const { opacity = "1.0" } = el.dataset;
148
- const options = { opacity: parseFloat(opacity) };
149
- const marker = L.marker(JSON.parse(latLng), options).addTo(map);
150
- el.dataset._leafletId = L.stamp(marker); // Save ID for later
151
-
152
- const observer = new MutationObserver(function (mutations) {
153
- mutations.forEach((mutation) => {
154
- const { latLng } = mutation.target.dataset;
155
- marker.setLatLng(JSON.parse(latLng));
156
- });
157
- });
158
- observer.observe(el, {
159
- attributes: true,
160
- attributeFilter: ["data-lat-lng"],
161
- });
162
-
163
- // marker.bindPopup
164
- el.querySelectorAll(selector("popup")).forEach((el) => {
165
- const { content } = el.dataset;
166
- marker.bindPopup(content);
167
- const observer = new MutationObserver(function () {
168
- marker.getPopup().setContent(el.dataset.content);
169
- });
170
- observer.observe(el, {
171
- attributes: true,
172
- attributeFilter: ["data-content"],
173
- });
174
- });
175
-
176
- layers.push(marker);
177
- });
178
-
179
- overlayMaps[name] = L.layerGroup(layers);
180
- });
181
-
182
- L.control.layers(baseMaps, overlayMaps).addTo(map);
183
- });
184
- });
185
- };
186
15
 
187
16
  const init = (() => {
188
- document.addEventListener("DOMContentLoaded", render);
17
+ // Custom elements (order of definition is important)
18
+ customElements.define("l-map", LMap)
19
+ customElements.define("l-control-layers", LControlLayers)
20
+ customElements.define("l-base-layers", LBaseLayers)
21
+ customElements.define("l-overlay-layers", LOverlayLayers)
22
+ customElements.define("l-layer-group", LLayerGroup)
23
+ customElements.define("l-tile-layer", LTileLayer)
24
+ customElements.define("l-marker", LMarker)
25
+ customElements.define("l-popup", LPopup)
26
+ customElements.define("l-lat-lng-bounds", LLatLngBounds)
27
+ customElements.define("l-image-overlay", LImageOverlay)
28
+ customElements.define("l-video-overlay", LVideoOverlay)
29
+ customElements.define("l-geojson", LGeoJSON)
189
30
  })();
190
31
 
191
32
  export default init;
@@ -0,0 +1,16 @@
1
+ import { mapAddTo } from "./events.js"
2
+
3
+ class LBaseLayers extends HTMLElement {
4
+ constructor() {
5
+ super()
6
+ }
7
+
8
+ connectedCallback() {
9
+ this.addEventListener(mapAddTo, (ev) => {
10
+ ev.detail["type"] = "base"
11
+ })
12
+ }
13
+ }
14
+
15
+ export default LBaseLayers
16
+
@@ -0,0 +1,34 @@
1
+ import { mapAddTo } from "./events.js"
2
+
3
+ class LControlLayers extends HTMLElement {
4
+ constructor() {
5
+ super()
6
+ }
7
+
8
+ connectedCallback() {
9
+ const base = {}
10
+ const overlay = {}
11
+ const control = L.control.layers(base, overlay)
12
+
13
+ this.addEventListener(mapAddTo, (ev) => {
14
+ const { type, name, layer } = ev.detail
15
+ if (type === "overlay") {
16
+ control.addOverlay(layer, name)
17
+ } else if (type === "base") {
18
+ control.addBaseLayer(layer, name)
19
+ }
20
+ ev.preventDefault()
21
+ })
22
+
23
+ const event = new CustomEvent(mapAddTo, {
24
+ cancelable: true,
25
+ bubbles: true,
26
+ detail: {
27
+ layer: control
28
+ }
29
+ })
30
+ this.dispatchEvent(event)
31
+ }
32
+ }
33
+
34
+ export default LControlLayers
@@ -0,0 +1,20 @@
1
+ import { mapAddTo } from "./events.js"
2
+
3
+ class LGeoJSON extends HTMLElement {
4
+ constructor() {
5
+ super()
6
+ }
7
+
8
+ connectedCallback() {
9
+ const layer = L.geoJSON(JSON.parse(this.getAttribute("geojson")))
10
+ this.dispatchEvent(new CustomEvent(mapAddTo, {
11
+ bubbles: true,
12
+ cancelable: true,
13
+ detail: {
14
+ layer
15
+ }
16
+ }))
17
+ }
18
+ }
19
+
20
+ export default LGeoJSON
@@ -0,0 +1,41 @@
1
+ import { mapAddTo } from "./events.js"
2
+
3
+ class LImageOverlay extends HTMLElement {
4
+ static observedAttributes = ["url", "bounds", "opacity"]
5
+
6
+ constructor() {
7
+ super()
8
+ this.layer = null
9
+ }
10
+
11
+ connectedCallback() {
12
+ const url = this.getAttribute("url")
13
+ const bounds = JSON.parse(this.getAttribute("bounds"))
14
+ const options = {
15
+ opacity: parseFloat(this.getAttribute("opacity") || "1.0"),
16
+ alt: this.getAttribute("alt") || ""
17
+ }
18
+ this.layer = L.imageOverlay(url, bounds, options)
19
+ this.dispatchEvent(new CustomEvent(mapAddTo, {
20
+ cancelable: true,
21
+ bubbles: true,
22
+ detail: {
23
+ layer: this.layer
24
+ }
25
+ }))
26
+ }
27
+
28
+ attributeChangedCallback(name, _oldValue, newValue) {
29
+ if (this.layer !== null) {
30
+ if (name === "url") {
31
+ this.layer.setUrl(newValue)
32
+ } else if (name === "bounds") {
33
+ this.layer.setBounds(JSON.parse(newValue))
34
+ } else if (name === "opacity") {
35
+ this.layer.setOpacity(parseFloat(newValue))
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ export default LImageOverlay
@@ -0,0 +1,20 @@
1
+ class LLatLngBounds extends HTMLElement {
2
+ static observedAttributes = ["bounds"]
3
+
4
+ constructor() {
5
+ super()
6
+ }
7
+
8
+ attributeChangedCallback(_name, _oldValue, newValue) {
9
+ const event = new CustomEvent("map:bounds", {
10
+ bubbles: true,
11
+ detail: {
12
+ bounds: JSON.parse(newValue),
13
+ method: this.getAttribute("method") || "fitBounds"
14
+ }
15
+ })
16
+ this.dispatchEvent(event)
17
+ }
18
+ }
19
+
20
+ export default LLatLngBounds