leaflet-html 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/example/index.html +96 -0
- package/package.json +22 -0
- package/src/index.js +86 -0
package/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Leaflet HTML
|
2
|
+
|
3
|
+
Leaflet expressed in HTML to add maps to Hypermedia Driven Applications (HDA).
|
4
|
+
|
5
|
+
## Example
|
6
|
+
|
7
|
+
The HTML in `example/index.html` is a simple demonstration of the API.
|
8
|
+
|
9
|
+

|
10
|
+
|
11
|
+
```html
|
12
|
+
<!-- Note: Leaflet JS/CSS must be included in <head> and [data-leaflet-html] styled to an appropriate size. -->
|
13
|
+
<div data-leaflet-html data-center="[39.61, -105.02]" data-zoom="10">
|
14
|
+
<div data-control-layers>
|
15
|
+
<div data-base-maps>
|
16
|
+
<div data-tile-layer
|
17
|
+
data-name="OpenStreetMap"
|
18
|
+
data-url-template="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
|
19
|
+
data-attribution='© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
20
|
+
data-max-zoom="12"
|
21
|
+
></div>
|
22
|
+
<div data-tile-layer
|
23
|
+
data-name="Toner"
|
24
|
+
data-url-template="https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.png"
|
25
|
+
data-attribution=''
|
26
|
+
data-max-zoom="12"
|
27
|
+
data-show
|
28
|
+
></div>
|
29
|
+
</div>
|
30
|
+
<div data-overlay-maps>
|
31
|
+
<div data-layer-group data-name="Cities">
|
32
|
+
<div data-marker data-lat-lng="[39.61, -105.02]">
|
33
|
+
<div data-popup data-content="This is Littleton, CO."></div>
|
34
|
+
</div>
|
35
|
+
<div data-marker data-lat-lng="[39.74, -104.99]">
|
36
|
+
<div data-popup data-content="This is Denver, CO."></div>
|
37
|
+
</div>
|
38
|
+
<div data-marker data-lat-lng="[39.73, -104.8]">
|
39
|
+
<div data-popup data-content="This is Aurora, CO."></div>
|
40
|
+
</div>
|
41
|
+
<div data-marker data-lat-lng="[39.77, -105.23]">
|
42
|
+
<div data-popup data-content="This is Golden, CO."></div>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
```
|
49
|
+
|
50
|
+
## Build
|
51
|
+
|
52
|
+
To build the source code run.
|
53
|
+
|
54
|
+
```sh
|
55
|
+
yarn build
|
56
|
+
```
|
@@ -0,0 +1,96 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<title>Leaflet HTML</title>
|
5
|
+
<meta charset="utf-8" />
|
6
|
+
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
7
|
+
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
8
|
+
crossorigin=""/>
|
9
|
+
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
10
|
+
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
11
|
+
crossorigin=""></script>
|
12
|
+
<style>
|
13
|
+
* {
|
14
|
+
margin: 0;
|
15
|
+
}
|
16
|
+
|
17
|
+
[data-leaflet-html] {
|
18
|
+
block-size: 100vh;
|
19
|
+
isolation: isolate;
|
20
|
+
z-index: 1;
|
21
|
+
}
|
22
|
+
|
23
|
+
#btn {
|
24
|
+
z-index: 2;
|
25
|
+
position: absolute;
|
26
|
+
bottom: 0;
|
27
|
+
left: 0;
|
28
|
+
margin: 1rem;
|
29
|
+
padding: 1rem;
|
30
|
+
background-color: #337;
|
31
|
+
color: white;
|
32
|
+
border-radius: 0.25rem;
|
33
|
+
cursor: pointer;
|
34
|
+
font-size: 1.2rem;
|
35
|
+
}
|
36
|
+
</style>
|
37
|
+
</head>
|
38
|
+
<body>
|
39
|
+
<div data-leaflet-html data-center="[39.61, -105.02]" data-zoom="10">
|
40
|
+
<div data-control-layers>
|
41
|
+
<div data-base-maps>
|
42
|
+
<div data-tile-layer
|
43
|
+
data-name="OpenStreetMap"
|
44
|
+
data-url-template="https://tile.openstreetmap.org/{z}/{x}/{y}.png"
|
45
|
+
data-attribution='© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
46
|
+
data-max-zoom="12"
|
47
|
+
></div>
|
48
|
+
<div data-tile-layer
|
49
|
+
data-name="Toner"
|
50
|
+
data-url-template="https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.png"
|
51
|
+
data-attribution=''
|
52
|
+
data-max-zoom="12"
|
53
|
+
data-show
|
54
|
+
></div>
|
55
|
+
</div>
|
56
|
+
<div data-overlay-maps>
|
57
|
+
<div data-layer-group data-name="Cities">
|
58
|
+
<div data-marker data-lat-lng="[39.61, -105.02]">
|
59
|
+
<div data-popup data-content="This is Littleton, CO."></div>
|
60
|
+
</div>
|
61
|
+
<div data-marker data-lat-lng="[39.74, -104.99]">
|
62
|
+
<div data-popup data-content="This is Denver, CO."></div>
|
63
|
+
</div>
|
64
|
+
<div data-marker data-lat-lng="[39.73, -104.8]" data-opacity="0.7">
|
65
|
+
<div data-popup data-content="This is Aurora, CO."></div>
|
66
|
+
</div>
|
67
|
+
<div data-marker data-lat-lng="[39.77, -105.23]">
|
68
|
+
<div data-popup data-content="This is Golden, CO."></div>
|
69
|
+
</div>
|
70
|
+
</div>
|
71
|
+
</div>
|
72
|
+
</div>
|
73
|
+
|
74
|
+
</div>
|
75
|
+
<button id="btn">Add a city</button>
|
76
|
+
<script type="module">
|
77
|
+
import leafletHTML from "/dist/leaflet-html.esm.js"
|
78
|
+
|
79
|
+
leafletHTML()
|
80
|
+
|
81
|
+
// Manual tests
|
82
|
+
document.getElementById("btn").addEventListener("click", () => {
|
83
|
+
// New city
|
84
|
+
let el = document.querySelector('[data-name="Cities"]')
|
85
|
+
const city = document.createElement("div")
|
86
|
+
city.dataset.marker = ''
|
87
|
+
city.dataset.latLng = "[39.60, -105.02]"
|
88
|
+
el.appendChild(city)
|
89
|
+
|
90
|
+
// Remove Denver
|
91
|
+
el = document.querySelector('[data-lat-lng="[39.74, -104.99]"]')
|
92
|
+
el.remove()
|
93
|
+
})
|
94
|
+
</script>
|
95
|
+
</body>
|
96
|
+
</html>
|
package/package.json
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"name": "leaflet-html",
|
3
|
+
"type": "module",
|
4
|
+
"version": "0.1.0",
|
5
|
+
"description": "Leaflet expressed in HTML",
|
6
|
+
"source": "src/index.js",
|
7
|
+
"main": "./dist/leaflet-html.js",
|
8
|
+
"module": "./dist/leaflet-html.esm.js",
|
9
|
+
"author": "andrewgryan",
|
10
|
+
"repository": {
|
11
|
+
"type": "git",
|
12
|
+
"url": "git+https://github.com/andrewgryan/leaflet-html.git"
|
13
|
+
},
|
14
|
+
"license": "MIT",
|
15
|
+
"scripts": {
|
16
|
+
"build": "microbundle",
|
17
|
+
"watch": "microbundle watch"
|
18
|
+
},
|
19
|
+
"devDependencies": {
|
20
|
+
"microbundle": "^0.15.1"
|
21
|
+
}
|
22
|
+
}
|
package/src/index.js
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
const init = () => {
|
2
|
+
// Render Leaflet API calls
|
3
|
+
document.querySelectorAll("[data-leaflet-html]").forEach((el) => {
|
4
|
+
const { center, zoom } = el.dataset
|
5
|
+
const map = L.map(el).setView(JSON.parse(center), parseInt(zoom))
|
6
|
+
|
7
|
+
// L.control.layers
|
8
|
+
el.querySelectorAll("[data-control-layers]").forEach((el) => {
|
9
|
+
const baseMaps = {}
|
10
|
+
|
11
|
+
// L.tileLayers
|
12
|
+
el.querySelectorAll("[data-tile-layer]").forEach((tileEl) => {
|
13
|
+
const { show, urlTemplate, attribution, maxZoom, name } = tileEl.dataset
|
14
|
+
baseMaps[name] = L.tileLayer(urlTemplate, { maxZoom, attribution });
|
15
|
+
if (show != null) {
|
16
|
+
baseMaps[name].addTo(map)
|
17
|
+
}
|
18
|
+
})
|
19
|
+
|
20
|
+
const overlayMaps = {}
|
21
|
+
// L.layerGroup
|
22
|
+
el.querySelectorAll("[data-layer-group]").forEach((el) => {
|
23
|
+
const { name } = el.dataset
|
24
|
+
const layers = []
|
25
|
+
|
26
|
+
const observer = new MutationObserver(function(mutations) {
|
27
|
+
const group = overlayMaps[name]
|
28
|
+
|
29
|
+
mutations.forEach(mutation => {
|
30
|
+
mutation.addedNodes.forEach(node => {
|
31
|
+
const { latLng } = node.dataset // MutationObserver needed
|
32
|
+
const layer = L.marker(JSON.parse(latLng))
|
33
|
+
group.addLayer(layer)
|
34
|
+
map.addLayer(layer)
|
35
|
+
})
|
36
|
+
|
37
|
+
mutation.removedNodes.forEach(node => {
|
38
|
+
const { _leafletId } = node.dataset
|
39
|
+
const layer = group.getLayer(_leafletId)
|
40
|
+
group.removeLayer(layer)
|
41
|
+
|
42
|
+
map.removeLayer(layer)
|
43
|
+
})
|
44
|
+
})
|
45
|
+
})
|
46
|
+
observer.observe(el, { childList: true })
|
47
|
+
|
48
|
+
// L.marker
|
49
|
+
el.querySelectorAll("[data-marker]").forEach((el) => {
|
50
|
+
const { latLng } = el.dataset
|
51
|
+
const { opacity = "1.0" } = el.dataset
|
52
|
+
const options = { opacity: parseFloat(opacity) }
|
53
|
+
console.log(options)
|
54
|
+
const marker = L.marker(JSON.parse(latLng), options).addTo(map)
|
55
|
+
el.dataset._leafletId = L.stamp(marker) // Save ID for later
|
56
|
+
|
57
|
+
const observer = new MutationObserver(function(mutations) {
|
58
|
+
mutations.forEach((mutation) => {
|
59
|
+
const { latLng } = mutation.target.dataset
|
60
|
+
marker.setLatLng(JSON.parse(latLng))
|
61
|
+
})
|
62
|
+
})
|
63
|
+
observer.observe(el, { attributes: true, attributeFilter: ["data-lat-lng"] })
|
64
|
+
|
65
|
+
// marker.bindPopup
|
66
|
+
el.querySelectorAll("[data-popup]").forEach((el) => {
|
67
|
+
const { content } = el.dataset
|
68
|
+
marker.bindPopup(content)
|
69
|
+
const observer = new MutationObserver(function() {
|
70
|
+
marker.getPopup().setContent(el.dataset.content)
|
71
|
+
})
|
72
|
+
observer.observe(el, { attributes: true, attributeFilter: ["data-content"] })
|
73
|
+
})
|
74
|
+
|
75
|
+
layers.push(marker)
|
76
|
+
})
|
77
|
+
|
78
|
+
overlayMaps[name] = L.layerGroup(layers)
|
79
|
+
})
|
80
|
+
|
81
|
+
L.control.layers(baseMaps, overlayMaps).addTo(map)
|
82
|
+
})
|
83
|
+
})
|
84
|
+
}
|
85
|
+
|
86
|
+
export default init
|