waibu-maps 1.0.1

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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/bajo/.alias +1 -0
  4. package/bajo/config.json +10 -0
  5. package/bajoI18N/resource/en-US.json +17 -0
  6. package/bajoI18N/resource/id.json +19 -0
  7. package/package.json +34 -0
  8. package/waibuBootstrap/theme/component/factory/control-attribution.js +29 -0
  9. package/waibuBootstrap/theme/component/factory/control-buttons-item.js +14 -0
  10. package/waibuBootstrap/theme/component/factory/control-buttons.js +67 -0
  11. package/waibuBootstrap/theme/component/factory/control-center-position.js +28 -0
  12. package/waibuBootstrap/theme/component/factory/control-draw.js +43 -0
  13. package/waibuBootstrap/theme/component/factory/control-fullscreen.js +26 -0
  14. package/waibuBootstrap/theme/component/factory/control-geolocate.js +27 -0
  15. package/waibuBootstrap/theme/component/factory/control-group-button.js +15 -0
  16. package/waibuBootstrap/theme/component/factory/control-group-menu.js +45 -0
  17. package/waibuBootstrap/theme/component/factory/control-group.js +94 -0
  18. package/waibuBootstrap/theme/component/factory/control-image.js +43 -0
  19. package/waibuBootstrap/theme/component/factory/control-loader.js +27 -0
  20. package/waibuBootstrap/theme/component/factory/control-logo.js +50 -0
  21. package/waibuBootstrap/theme/component/factory/control-mouse-pos.js +78 -0
  22. package/waibuBootstrap/theme/component/factory/control-navigation.js +29 -0
  23. package/waibuBootstrap/theme/component/factory/control-ruler.js +47 -0
  24. package/waibuBootstrap/theme/component/factory/control-scale.js +27 -0
  25. package/waibuBootstrap/theme/component/factory/control-search.js +159 -0
  26. package/waibuBootstrap/theme/component/factory/control-zbp.js +70 -0
  27. package/waibuBootstrap/theme/component/factory/control.js +42 -0
  28. package/waibuBootstrap/theme/component/factory/layer-geojson.js +103 -0
  29. package/waibuBootstrap/theme/component/factory/layer-html-cluster.js +124 -0
  30. package/waibuBootstrap/theme/component/factory/map/options.js +44 -0
  31. package/waibuBootstrap/theme/component/factory/map.js +139 -0
  32. package/waibuBootstrap/theme/component/factory/script.js +20 -0
  33. package/waibuBootstrap/theme/component/factory/template.js +10 -0
  34. package/waibuBootstrap/theme/component/wmaps-base.js +40 -0
  35. package/waibuMpa/partial/menu.html +10 -0
  36. package/waibuMpa/route/default-style.js +13 -0
  37. package/waibuMpa/route/wmaps.js +13 -0
  38. package/waibuMpa/template/default-style.json +20 -0
  39. package/waibuMpa/template/wmaps.js +320 -0
  40. package/waibuStatic/asset/css/control-buttons.css +3 -0
  41. package/waibuStatic/asset/css/control-center-position.css +17 -0
  42. package/waibuStatic/asset/css/control-loader.css +7 -0
  43. package/waibuStatic/asset/css/control-mouse-position.css +21 -0
  44. package/waibuStatic/asset/css/control-ruler.css +12 -0
  45. package/waibuStatic/asset/css/control-search.css +25 -0
  46. package/waibuStatic/asset/css/wmaps.css +150 -0
  47. package/waibuStatic/asset/font/noto_sans_regular.pbf +0 -0
  48. package/waibuStatic/asset/image/center.svg +25 -0
  49. package/waibuStatic/asset/image/ruler.svg +4 -0
  50. package/waibuStatic/asset/js/control-buttons.js +98 -0
  51. package/waibuStatic/asset/js/control-center-position.js +19 -0
  52. package/waibuStatic/asset/js/control-mouse-position.js +47 -0
  53. package/waibuStatic/asset/js/control-ruler.js +204 -0
  54. package/waibuStatic/asset/js/donut-chart.js +58 -0
  55. package/waibuStatic/asset/js/lib/worker-timers.js +243 -0
  56. package/waibuStatic/virtual.json +7 -0
@@ -0,0 +1,21 @@
1
+ .maplibregl-ctrl-mouse-position {
2
+ background-color: #fff;
3
+ border-radius: 12px;
4
+ box-sizing: content-box;
5
+ color: #000;
6
+ margin: 10px;
7
+ min-height: 20px;
8
+ padding: 2px 8px 2px 8px;
9
+ position: relative;
10
+ }
11
+
12
+ .maplibregl-ctrl-mouse-position-lat-lng {
13
+ display: inline-block;
14
+ width: 80px;
15
+ white-space: nowrap;
16
+ }
17
+
18
+ .maplibregl-ctrl-mouse-position-lat-lng.dms {
19
+ width: 120px;
20
+ }
21
+
@@ -0,0 +1,12 @@
1
+ .maplibregl-ctrl-ruler button.active img {
2
+ background-color: orange;
3
+ }
4
+
5
+ .maplibregl-ctrl-ruler button.disabled img {
6
+ background-color: silver;
7
+ }
8
+
9
+ [data-bs-theme=dark] .maplibregl-ctrl-ruler img {
10
+ filter: invert(1);
11
+ }
12
+
@@ -0,0 +1,25 @@
1
+ .maplibregl-ctrl-search {
2
+ z-index: 1000;
3
+ position: absolute;
4
+ width: 100%;
5
+ top: 10px;
6
+ pointer-events: none;
7
+ }
8
+
9
+ .maplibregl-ctrl-search input {
10
+ pointer-events: all;
11
+ border: none;
12
+ }
13
+
14
+ .maplibregl-ctrl-search input:focus {
15
+ outline: none;
16
+ }
17
+
18
+ .maplibregl-ctrl-search .maplibregl-ctrl {
19
+ padding: .375rem .75rem;
20
+ font-size: 1rem;
21
+ font-weight: 400;
22
+ line-height: 1.5;
23
+ color: var(--bs-body-color);
24
+ background-color: var(--bs-body-bg);
25
+ }
@@ -0,0 +1,150 @@
1
+ [data-bs-theme=dark] .maplibregl-ctrl-group,
2
+ [data-bs-theme=dark] .maplibregl-ctrl-attrib,
3
+ [data-bs-theme=dark] .maplibregl-ctrl-scale,
4
+ [data-bs-theme=dark] .maplibregl-popup-content,
5
+ [data-bs-theme=dark] .maplibregl-ctrl-widget,
6
+ [data-bs-theme=dark] .maplibregl-ctrl-mouse-position {
7
+ background-color: var(--bs-body-bg);
8
+ color: var(--bs-body-color);
9
+ }
10
+
11
+ [data-bs-theme=dark] .maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
12
+ [data-bs-theme=dark] .maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
13
+ [data-bs-theme=dark] .maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip {
14
+ border-top-color: var(--bs-body-bg);
15
+ }
16
+ [data-bs-theme=dark] .maplibregl-popup-anchor-left .maplibregl-popup-tip {
17
+ border-right-color: var(--bs-body-bg);
18
+ }
19
+ [data-bs-theme=dark] .maplibregl-popup-anchor-right .maplibregl-popup-tip {
20
+ border-left-color: var(--bs-body-bg);
21
+ }
22
+ [data-bs-theme=dark] .maplibregl-popup-anchor-top .maplibregl-popup-tip,
23
+ [data-bs-theme=dark] .maplibregl-popup-anchor-top-right .maplibregl-popup-tip,
24
+ [data-bs-theme=dark] .maplibregl-popup-anchor-top-left .maplibregl-popup-tip {
25
+ border-bottom-color: var(--bs-body-bg);
26
+ }
27
+
28
+ [data-bs-theme=dark] .maplibregl-ctrl-attrib a {
29
+ color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1))
30
+ }
31
+
32
+ [data-bs-theme=dark] .maplibregl-ctrl button .maplibregl-ctrl-icon,
33
+ [data-bs-theme=dark] .maplibregl-ctrl-attrib-button {
34
+ filter: invert(100%);
35
+ }
36
+
37
+ [data-bs-theme=dark] .maplibregl-ctrl-group button+button {
38
+ border-top: 1px solid #5c5c5c;
39
+ }
40
+
41
+ [data-bs-theme=dark] .maplibregl-ctrl-wmaps.widget {
42
+ background-color: rgba(33, 37, 41, 0.85) !important;
43
+ }
44
+
45
+ .maplibregl-ctrl-wmaps.widget {
46
+ background-color: rgba(255, 255, 255, 0.85) !important;
47
+ }
48
+
49
+ .maplibregl-ctrl-wmaps.widget .smaller {
50
+ font-size: smaller;
51
+ }
52
+
53
+ .maplibregl-ctrl-loader {
54
+ z-index: 1000;
55
+ position: absolute;
56
+ width: 100%;
57
+ top: 0px;
58
+ pointer-events: none;
59
+ }
60
+
61
+ .maplibregl-ctrl-group button.btn {
62
+ background-color: var(--bs-btn-bg);
63
+ width: auto;
64
+ height: auto;
65
+ padding: var(--bs-btn-padding-y) var(--bs-btn-padding-x);
66
+ }
67
+
68
+ .maplibregl-ctrl-group button.btn:hover {
69
+ background-color: var(--bs-btn-hover-bg);
70
+ }
71
+
72
+ .maplibregl-popup {
73
+ max-width: 300px !important;
74
+ }
75
+
76
+ .maplibregl-ctrl-attrib {
77
+ margin: 0px 10px 10px !important;
78
+ }
79
+
80
+ .maplibregl-ctrl-group > button {
81
+ width: 35px !important;
82
+ height: 35px !important;
83
+ }
84
+
85
+ .maplibregl-ctrl-group > button i {
86
+ font-size: 16pt;
87
+ }
88
+
89
+ .maplibregl-ctrl-group button.accordion-button {
90
+ height: auto !important;
91
+ }
92
+
93
+ .maplibregl-ctrl-group .accordion-header button {
94
+ width: 100%;
95
+ display: flex;
96
+ }
97
+
98
+ .maplibregl-ctrl-group .accordion-body .form-check-label {
99
+ white-space: nowrap;;
100
+ }
101
+
102
+ .maplibregl-ctrl-group .dropdown-menu > div {
103
+ font-size: smaller;
104
+ }
105
+
106
+ .maplibregl-popup-content div span {
107
+ display: inline-block;
108
+ }
109
+
110
+ .maplibregl-popup-content div span.label {
111
+ min-width: 80px;
112
+ }
113
+
114
+ .maplibregl-popup-content .btn-sm {
115
+ padding: 0.1rem 0.3rem;
116
+ font-size: small;
117
+ }
118
+
119
+ .maplibregl-popup-content .nav-link {
120
+ outline: none !important;
121
+ padding: 0.3rem 0.5rem;
122
+ }
123
+
124
+ .maplibregl-popup-content .nav {
125
+ padding: 0 0.5rem;
126
+ }
127
+
128
+ .maplibregl-ctrl-group.cmp {
129
+ width:240px;
130
+ }
131
+
132
+ .maplibregl-ctrl-group.cgr button img {
133
+ width: 35px;
134
+ height: 35px;
135
+ opacity: 0.75;
136
+ }
137
+
138
+ .maplibregl-ctrl-group.cgr button img:hover {
139
+ opacity: 1;
140
+ }
141
+
142
+ .maplibregl-ctrl-group.cgr button:first-child img {
143
+ border-top-left-radius: 4px;
144
+ border-top-right-radius: 4px;
145
+ }
146
+
147
+ .maplibregl-ctrl-group.cgr button:last-child img {
148
+ border-bottom-left-radius: 4px;
149
+ border-bottom-right-radius: 4px;
150
+ }
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg
3
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
4
+ xmlns:cc="http://creativecommons.org/ns#"
5
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
6
+ xmlns:svg="http://www.w3.org/2000/svg"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ version="1.1"
9
+ x="0px"
10
+ y="0px"
11
+ viewBox="0 0 99.999998 99.999998"
12
+ xml:space="preserve">
13
+ <g><circle
14
+ r="3.9234731"
15
+ cy="50.21946"
16
+ cx="50.027821"
17
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /><path
18
+ d="m 4.9734042,54.423642 31.7671398,0 c 2.322349,0 4.204185,-1.881836 4.204185,-4.204185 0,-2.322349 -1.881836,-4.204184 -4.204185,-4.204184 l -31.7671398,0 c -2.3223489,-2.82e-4 -4.20418433,1.881554 -4.20418433,4.204184 0,2.322631 1.88183543,4.204185 4.20418433,4.204185 z"
19
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /><path
20
+ d="m 54.232003,5.1650429 c 0,-2.3223489 -1.881836,-4.20418433 -4.204184,-4.20418433 -2.322349,0 -4.204185,1.88183543 -4.204185,4.20418433 l 0,31.7671401 c 0,2.322349 1.881836,4.204184 4.204185,4.204184 2.322348,0 4.204184,-1.881835 4.204184,-4.204184 l 0,-31.7671401 z"
21
+ style="fill:#000000;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1" /><path
22
+ d="m 99.287826,50.219457 c 0,-2.322349 -1.881835,-4.204184 -4.204184,-4.204184 l -31.76714,0 c -2.322349,0 -4.204184,1.881835 -4.204184,4.204184 0,2.322349 1.881835,4.204185 4.204184,4.204185 l 31.76714,0 c 2.320658,0 4.204184,-1.881836 4.204184,-4.204185 z"
23
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /><path
24
+ d="m 45.823352,95.27359 c 0,2.322349 1.881836,4.204184 4.204185,4.204184 2.322349,0 4.204184,-1.881835 4.204184,-4.204184 l 0,-31.76714 c 0,-2.322349 -1.881835,-4.204185 -4.204184,-4.204185 -2.322349,0 -4.204185,1.881836 -4.204185,4.204185 l 0,31.76714 z"
25
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /></g></svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="22" height="12" viewBox="0 0 22 12" fill="#505050">
2
+ <path fill-rule="evenodd" fill="none" d="M-1-6h24v24H-1z"/>
3
+ <path d="M20 0H2C.9 0 0 .9 0 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V2c0-1.1-.9-2-2-2zm0 10H2V2h2v4h2V2h2v4h2V2h2v4h2V2h2v4h2V2h2v8z"/>
4
+ </svg>
@@ -0,0 +1,98 @@
1
+ /* global _, wmpa */
2
+
3
+ class ControlButtons { // eslint-disable-line no-unused-vars
4
+ constructor (options = {}) {
5
+ this.position = options.position ?? 'top-left'
6
+ this.items = options.items ?? []
7
+ this.scopeId = options.scopeId
8
+ }
9
+
10
+ createButtons () {
11
+ for (const b of this.items) {
12
+ const btn = document.createElement('button')
13
+ btn.setAttribute('type', 'button')
14
+ if (b.class) btn.classList.add(...b.class.split(' '))
15
+ for (const attr in b.attrib ?? {}) {
16
+ btn.setAttribute(_.kebabCase(attr), b.attrib[attr])
17
+ }
18
+ if (b.imageUrl) {
19
+ const img = document.createElement('img')
20
+ img.src = b.imageUrl
21
+ btn.appendChild(img)
22
+ } else if (b.icon) {
23
+ const icon = document.createElement('i')
24
+ icon.classList.add('d-flex', 'justify-content-center', 'align-items-center', ...b.icon.split(' '))
25
+ btn.appendChild(icon)
26
+ }
27
+ if (b.dropdown) {
28
+ const wrapper = this.createDropdown(btn, b)
29
+ this.container.appendChild(wrapper)
30
+ } else if (!_.get(b, 'attrib.dataBsTarget')) {
31
+ if (b.fn) this.buildOnClick(btn, b)
32
+ else if (b.url && b.newTab) btn.setAttribute('onclick', 'window.open(\'' + b.url + '\', \'_blank\')')
33
+ else if (b.url) btn.setAttribute('onclick', 'location.href=\'' + b.url + '\'')
34
+ this.container.appendChild(btn)
35
+ } else {
36
+ this.container.appendChild(btn)
37
+ }
38
+ if (b.minZoom) {
39
+ if (this.map.getZoom() < b.minZoom) btn.setAttribute('disabled', '')
40
+ this.map.on('zoomend', () => {
41
+ if (this.map.getZoom() < b.minZoom) btn.setAttribute('disabled', '')
42
+ else btn.removeAttribute('disabled')
43
+ })
44
+ }
45
+ }
46
+ }
47
+
48
+ createDropdown (btn, b) {
49
+ const wrapper = document.createElement('button')
50
+ wrapper.setAttribute('id', b.id)
51
+ this.buildOnClick(wrapper, b)
52
+ wrapper.classList.add('dropdown')
53
+ const pos = this.position.split('-')[1] === 'right' ? 'start' : 'end'
54
+ wrapper.classList.add('drop' + pos)
55
+ btn.setAttribute('data-bs-toggle', 'dropdown')
56
+ btn.setAttribute('data-bs-auto-close', 'outside')
57
+ const menu = document.createElement('div')
58
+ menu.classList.add('dropdown-menu')
59
+ wrapper.appendChild(btn)
60
+ wrapper.appendChild(menu)
61
+ return wrapper
62
+ }
63
+
64
+ createControl () {
65
+ this.container = document.createElement('div')
66
+ this.container.classList.add('maplibregl-ctrl', 'maplibregl-ctrl-group', 'maplibregl-ctrl-buttons')
67
+ this.createButtons()
68
+ }
69
+
70
+ buildOnClick (btn, opts) {
71
+ let [ns, method, subMethod] = opts.fn.split('.')
72
+ if (!method) {
73
+ method = ns
74
+ ns = 'window'
75
+ }
76
+ if (ns === 'scope') {
77
+ btn.addEventListener('click', evt => {
78
+ if (!(this.scopeId && wmpa)) return
79
+ const fn = wmpa.alpineScopeMethod('#' + this.scopeId, method)
80
+ if (fn) fn(opts.fnParams)
81
+ })
82
+ } else {
83
+ const params = opts.fnParams ? `'${opts.fnParams}'` : ''
84
+ btn.setAttribute('onclick', `${ns}['${method}']${subMethod ? `['${subMethod}'` : ''}(${params})`)
85
+ }
86
+ }
87
+
88
+ onAdd (map) {
89
+ this.map = map
90
+ this.createControl()
91
+ return this.container
92
+ }
93
+
94
+ onRemove () {
95
+ this.container.parentNode.removeChild(this.container)
96
+ this.map = undefined
97
+ }
98
+ }
@@ -0,0 +1,19 @@
1
+ class ControlCenterPosition { // eslint-disable-line no-unused-vars
2
+ createControl () {
3
+ this.container = document.createElement('div')
4
+ this.container.classList.add('maplibregl-ctrl')
5
+ this.container.classList.add('maplibregl-ctrl-center')
6
+ this.icon = document.createElement('div')
7
+ }
8
+
9
+ onAdd (map) {
10
+ this.map = map
11
+ this.createControl()
12
+ return this.container
13
+ }
14
+
15
+ onRemove () {
16
+ this.container.parentNode.removeChild(this.container)
17
+ this.map = undefined
18
+ }
19
+ }
@@ -0,0 +1,47 @@
1
+ /* global maplibregl */
2
+
3
+ function defaultLabelFormat ({ lng, lat }) {
4
+ return `Lng: ${lng}, Lat: ${lat}`
5
+ }
6
+
7
+ class ControlMousePosition { // eslint-disable-line no-unused-vars
8
+ constructor (options) {
9
+ this.digits = options.digits || 5
10
+ this.trackCenter = options.trackCenter || false
11
+ this.labelFormat = options.labelFormat || defaultLabelFormat
12
+ this.coord = new maplibregl.LngLat(0, 0)
13
+ }
14
+
15
+ createControl () {
16
+ this.container = document.createElement('div')
17
+ this.container.classList.add('maplibregl-ctrl', 'maplibregl-ctrl-mouse-position')
18
+ this.panel = document.createElement('div')
19
+ this.panel.classList.add('maplibregl-ctrl-attrib-inner')
20
+ if (this.trackCenter) this.onMouseMove()
21
+ else this.panel.innerHTML = this.labelFormat({ lng: '', lat: '', lngLat: null, map: this.map })
22
+ this.container.appendChild(this.panel)
23
+ }
24
+
25
+ onMouseMove (evt) {
26
+ if (this.trackCenter) this.coord = this.map.getCenter().wrap()
27
+ else this.coord = evt.lngLat.wrap()
28
+ const lng = (this.coord.lng < 0 ? '-' : '') + Math.abs(this.coord.lng).toFixed(this.digits)
29
+ const lat = (this.coord.lat < 0 ? '-' : '') + Math.abs(this.coord.lat).toFixed(this.digits)
30
+ this.panel.innerHTML = this.labelFormat({ lng, lat, lngLat: this.coord, map: this.map })
31
+ }
32
+
33
+ onAdd (map) {
34
+ this.map = map
35
+ this.createControl()
36
+ if (this.trackCenter) this.map.on('move', this.onMouseMove.bind(this))
37
+ else this.map.on('mousemove', this.onMouseMove.bind(this))
38
+ return this.container
39
+ }
40
+
41
+ onRemove () {
42
+ if (this.trackCenter) this.map.off('move', this.onMouseMove.bind(this))
43
+ else this.map.off('mousemove', this.onMouseMove.bind(this))
44
+ this.container.parentNode.removeChild(this.container)
45
+ this.map = undefined
46
+ }
47
+ }
@@ -0,0 +1,204 @@
1
+ // Based on: https://raw.githubusercontent.com/bravecow/maplibre-gl-controls/master/src/ruler/ruler.js
2
+ /* global maplibregl, geolib */
3
+
4
+ const LAYER_LINE = 'controls-layer-line'
5
+ const SOURCE_LINE = 'controls-source-line'
6
+ const MAIN_COLOR = '#263238'
7
+ const HALO_COLOR = '#fff'
8
+ const HALO1_COLOR = '#0f0'
9
+
10
+ function geoLineString (coordinates = []) {
11
+ return {
12
+ type: 'Feature',
13
+ properties: {},
14
+ geometry: {
15
+ type: 'LineString',
16
+ coordinates
17
+ }
18
+ }
19
+ }
20
+
21
+ function defaultLabelFormat (delta, sum, units) {
22
+ return `+ ${delta.toFixed(2)} ${units}<br/>= ${sum.toFixed(2)} ${units}`
23
+ }
24
+
25
+ class ControlRuler { // eslint-disable-line no-unused-vars
26
+ constructor (options = {}) {
27
+ this.isMeasuring = false
28
+ this.enabled = true
29
+ this.markers = []
30
+ this.coordinates = []
31
+ this.labels = []
32
+ this.imageUrl = options.imageUrl
33
+ this.units = options.units || 'km'
34
+ // this.font = options.font || ['Noto Sans Regular']
35
+ this.fontSize = options.fontSize || 12
36
+ this.fontHalo = options.fontHalo || 1
37
+ this.labelFormat = options.labelFormat || defaultLabelFormat
38
+ this.mainColor = options.mainColor || MAIN_COLOR
39
+ this.secondaryColor = options.secondaryColor || HALO_COLOR
40
+ this.altColor = options.altColor || HALO1_COLOR
41
+ this.mapClickListener = this.mapClickListener.bind(this)
42
+ this.styleLoadListener = this.styleLoadListener.bind(this)
43
+ }
44
+
45
+ insertControls () {
46
+ this.container = document.createElement('div')
47
+ this.container.classList.add('maplibregl-ctrl')
48
+ this.container.classList.add('maplibregl-ctrl-group')
49
+ this.container.classList.add('maplibregl-ctrl-ruler')
50
+ this.button = document.createElement('button')
51
+ this.button.setAttribute('type', 'button')
52
+ const img = document.createElement('img')
53
+ img.src = this.imageUrl
54
+ this.button.appendChild(img)
55
+ this.container.appendChild(this.button)
56
+ }
57
+
58
+ setUnits (units) {
59
+ this.units = units
60
+ }
61
+
62
+ draw () {
63
+ this.map.addSource(SOURCE_LINE, {
64
+ type: 'geojson',
65
+ data: geoLineString(this.coordinates)
66
+ })
67
+
68
+ this.map.addLayer({
69
+ id: LAYER_LINE,
70
+ type: 'line',
71
+ source: SOURCE_LINE,
72
+ paint: {
73
+ 'line-color': this.mainColor,
74
+ 'line-width': 2
75
+ }
76
+ })
77
+ }
78
+
79
+ measuringOn () {
80
+ this.isMeasuring = true
81
+ this.markers = []
82
+ this.coordinates = []
83
+ this.labels = []
84
+ this.map.getCanvas().style.cursor = 'crosshair'
85
+ this.button.classList.add('active')
86
+ this.draw()
87
+ this.map.on('click', this.mapClickListener)
88
+ this.map.on('style.load', this.styleLoadListener)
89
+ this.map.fire('ruler.on')
90
+ }
91
+
92
+ measuringOff () {
93
+ this.isMeasuring = false
94
+ this.map.getCanvas().style.cursor = ''
95
+ this.button.classList.remove('active')
96
+ if (this.map.getLayer(LAYER_LINE)) this.map.removeLayer(LAYER_LINE)
97
+ if (this.map.getSource(SOURCE_LINE)) this.map.removeSource(SOURCE_LINE)
98
+ this.markers.forEach((m) => m.remove())
99
+ this.map.off('click', this.mapClickListener)
100
+ this.map.off('style.load', this.styleLoadListener)
101
+ this.map.fire('ruler.off')
102
+ }
103
+
104
+ enable () {
105
+ this.enabled = true
106
+ this.button.classList.remove('disabled')
107
+ }
108
+
109
+ disable () {
110
+ this.enabled = false
111
+ this.measuringOff()
112
+ this.button.classList.add('disabled')
113
+ }
114
+
115
+ mapClickListener (event) {
116
+ const markerNode = document.createElement('div')
117
+ markerNode.style.width = '12px'
118
+ markerNode.style.height = '12px'
119
+ markerNode.style.borderRadius = '50%'
120
+ markerNode.style.background = this.markers.length === 0 ? this.altColor : this.secondaryColor
121
+ markerNode.style.boxSizing = 'border-box'
122
+ markerNode.style.border = `2px solid ${this.mainColor}`
123
+ const marker = new maplibregl.Marker({
124
+ element: markerNode,
125
+ draggable: true
126
+ })
127
+ .setLngLat(event.lngLat)
128
+ .addTo(this.map)
129
+ this.coordinates.push([event.lngLat.lng, event.lngLat.lat])
130
+ this.map.getSource(SOURCE_LINE).setData(geoLineString(this.coordinates))
131
+ this.markers.push(marker)
132
+ if (this.markers.length > 1) {
133
+ this.labels = this.coordinatesToLabels()
134
+ marker.setPopup(new maplibregl.Popup({ closeButton: false, closeOnClick: false }))
135
+ marker.togglePopup()
136
+ marker.getPopup().setHTML(this.labels[this.markers.length - 1])
137
+ }
138
+ marker.on('drag', () => {
139
+ const index = this.markers.indexOf(marker)
140
+ const lngLat = marker.getLngLat()
141
+ this.coordinates[index] = [lngLat.lng, lngLat.lat]
142
+ this.recalcPopup()
143
+ this.map.getSource(SOURCE_LINE).setData(geoLineString(this.coordinates))
144
+ })
145
+ }
146
+
147
+ recalcPopup () {
148
+ this.labels = this.coordinatesToLabels()
149
+ this.labels.forEach((l, i) => {
150
+ const popup = this.markers[i].getPopup()
151
+ if (popup) popup.setHTML(l)
152
+ })
153
+ }
154
+
155
+ coordinatesToLabels () {
156
+ const { coordinates, units, labelFormat } = this
157
+ let sum = 0
158
+ return coordinates.map((coordinate, index) => {
159
+ if (index === 0) return labelFormat(0, 0, units)
160
+ let delta = geolib.getDistance({
161
+ latitude: coordinates[index - 1][1],
162
+ longitude: coordinates[index - 1][0]
163
+ }, {
164
+ latitude: coordinates[index][1],
165
+ longitude: coordinates[index][0]
166
+ }) / 1000
167
+ if (units === 'mi') {
168
+ delta = delta * 0.621371
169
+ } else if (units === 'nm') {
170
+ delta = delta * 0.539957
171
+ }
172
+ sum += delta
173
+ return labelFormat(delta, sum, units)
174
+ })
175
+ }
176
+
177
+ styleLoadListener () {
178
+ this.draw()
179
+ }
180
+
181
+ onButtonClick () {
182
+ if (!this.enabled) return
183
+ if (this.isMeasuring) this.measuringOff()
184
+ else this.measuringOn()
185
+ this.map.fire('ruler.buttonclick', { measuring: this.isMeasuring })
186
+ }
187
+
188
+ onAdd (map) {
189
+ this.map = map
190
+ this.insertControls()
191
+ this.button.addEventListener('click', this.onButtonClick.bind(this))
192
+ return this.container
193
+ }
194
+
195
+ onRemove () {
196
+ if (this.isMeasuring) {
197
+ this.measuringOff()
198
+ }
199
+ this.button.removeEventListener('click', this.onButtonClick.bind(this))
200
+ this.map.off('click', this.mapClickListener)
201
+ this.container.parentNode.removeChild(this.container)
202
+ this.map = undefined
203
+ }
204
+ }
@@ -0,0 +1,58 @@
1
+ // based on: https://docs.mapbox.com/mapbox-gl-js/example/cluster-html/
2
+
3
+ class DonutCharts {
4
+ create (props, itemCounts, colors) {
5
+ const offsets = []
6
+ const counts = []
7
+ for (const ic of itemCounts) {
8
+ counts.push(props[ic])
9
+ }
10
+ let total = 0
11
+ for (const count of counts) {
12
+ offsets.push(total)
13
+ total += count
14
+ }
15
+ const fontSize = total >= 1000 ? 22 : total >= 100 ? 20 : total >= 10 ? 18 : 16
16
+ const r = total >= 1000 ? 50 : total >= 100 ? 32 : total >= 10 ? 24 : 18
17
+ const r0 = Math.round(r * 0.6)
18
+ const w = r * 2
19
+
20
+ let html = `<div><svg width="${w}" height="${w}" viewbox="0 0 ${w} ${w}"
21
+ text-anchor="middle" style="font: ${fontSize}px sans-serif; display: block">`
22
+ for (let i = 0; i < counts.length; i++) {
23
+ html += this.donutSegment(
24
+ offsets[i] / total,
25
+ (offsets[i] + counts[i]) / total,
26
+ r,
27
+ r0,
28
+ colors[i]
29
+ )
30
+ }
31
+ html += `<circle cx="${r}" cy="${r}" r="${r0}" fill="white" />
32
+ <text dominant-baseline="central" transform="translate(${r}, ${r})">
33
+ ${total.toLocaleString()}
34
+ </text></svg></div>`
35
+
36
+ const el = document.createElement('div')
37
+ el.innerHTML = html
38
+ return el.firstChild
39
+ }
40
+
41
+ donutSegment (start, end, r, r0, color) {
42
+ if (end - start === 1) end -= 0.00001
43
+ const a0 = 2 * Math.PI * (start - 0.25)
44
+ const a1 = 2 * Math.PI * (end - 0.25)
45
+ const x0 = Math.cos(a0)
46
+ const y0 = Math.sin(a0)
47
+ const x1 = Math.cos(a1)
48
+ const y1 = Math.sin(a1)
49
+ const largeArc = end - start > 0.5 ? 1 : 0
50
+
51
+ // draw an SVG path
52
+ return `<path d="M ${r + r0 * x0} ${r + r0 * y0} L ${r + r * x0} ${r + r * y0} A
53
+ ${r} ${r} 0 ${largeArc} 1 ${r + r * x1} ${r + r * y1} L ${r + r0 * x1} ${r + r0 * y1} A
54
+ ${r0} ${r0} 0 ${largeArc} 0 ${r + r0 * x0} ${r + r0 * y0}" fill="${color}" />`
55
+ }
56
+ }
57
+
58
+ const donutChart = new DonutCharts() // eslint-disable-line no-unused-vars