abn-osmvue 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 abaniconetworks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,426 @@
1
+ # abn-osmvue
2
+
3
+ Librería de componentes Vue 2/Vue 3 para integrar mapas de OpenStreetMap. Basada en [Leaflet.js](https://leafletjs.com/) y compatible con ambas versiones de Vue gracias a [vue-demi](https://github.com/vueuse/vue-demi).
4
+
5
+ ---
6
+
7
+ ## Instalación
8
+
9
+ ```bash
10
+ npm install abn-osmvue leaflet
11
+ ```
12
+
13
+ > Leaflet debe instalarse como dependencia directa de tu proyecto.
14
+
15
+ ---
16
+
17
+ ## Registro
18
+
19
+ ### Vue 3
20
+
21
+ ```js
22
+ // main.js
23
+ import { createApp } from 'vue'
24
+ import AbnOsmVue from 'abn-osmvue'
25
+ import 'abn-osmvue/dist/style.css'
26
+ import 'leaflet/dist/leaflet.css'
27
+
28
+ const app = createApp(App)
29
+ app.use(AbnOsmVue)
30
+ app.mount('#app')
31
+ ```
32
+
33
+ ### Vue 2
34
+
35
+ ```js
36
+ // main.js
37
+ import Vue from 'vue'
38
+ import AbnOsmVue from 'abn-osmvue'
39
+ import 'abn-osmvue/dist/style.css'
40
+ import 'leaflet/dist/leaflet.css'
41
+
42
+ Vue.use(AbnOsmVue)
43
+ ```
44
+
45
+ ### Registro local (ambas versiones)
46
+
47
+ ```js
48
+ import { OsmMap, OsmMapEmbed } from 'abn-osmvue'
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Componentes
54
+
55
+ ### `<OsmMap>`
56
+
57
+ Renderiza un mapa interactivo usando Leaflet. Es el componente principal de la librería.
58
+
59
+ #### Props
60
+
61
+ | Prop | Tipo | Default | Requerido | Descripción |
62
+ |---|---|---|---|---|
63
+ | `lat` | `Number` | — | ✅ | Latitud del centro / pin |
64
+ | `lng` | `Number` | — | ✅ | Longitud del centro / pin |
65
+ | `zoom` | `Number` | `13` | — | Nivel de zoom inicial (1–19) |
66
+ | `minZoom` | `Number` | `1` | — | Zoom mínimo permitido |
67
+ | `maxZoom` | `Number` | `19` | — | Zoom máximo permitido |
68
+ | `height` | `String` | `'400px'` | — | Alto del contenedor (cualquier unidad CSS) |
69
+ | `width` | `String` | `'100%'` | — | Ancho del contenedor |
70
+ | `tileLayer` | `String` | `'osm'` | — | Proveedor de capa base (ver tabla de capas) |
71
+ | `tileUrl` | `String` | `null` | — | URL de teselas personalizada (sobreescribe `tileLayer`) |
72
+ | `tileOptions` | `Object` | `{}` | — | Opciones adicionales para el tile layer de Leaflet |
73
+ | `tileFilter` | `String` | `null` | — | Filtro CSS aplicado a las teselas (`'grayscale'`, `'invert'`, `'sepia'`, o valor CSS arbitrario) |
74
+ | `showMarker` | `Boolean` | `true` | — | Mostrar u ocultar el marcador en lat/lng |
75
+ | `markerIcon` | `String` | `null` | — | URL de imagen personalizada para el pin |
76
+ | `markerIconSize` | `Array` | `[32, 32]` | — | Tamaño del icono en píxeles `[width, height]` |
77
+ | `markerAnchor` | `Array` | `null` | — | Punto de anclaje del icono. Default: centro-base |
78
+ | `markerPopup` | `String` | `null` | — | HTML que aparece en popup al hacer clic en el pin |
79
+ | `controls` | `String\|Array` | `'all'` | — | Controles visibles (ver tabla de controles) |
80
+ | `draggable` | `Boolean` | `true` | — | Permitir arrastrar el mapa |
81
+ | `scrollWheelZoom` | `Boolean` | `true` | — | Zoom con scroll del ratón |
82
+ | `doubleClickZoom` | `Boolean` | `true` | — | Zoom con doble clic |
83
+ | `attributionControl` | `Boolean` | `true` | — | Mostrar atribución de OSM (requerida por licencia) |
84
+
85
+ #### Eventos
86
+
87
+ | Evento | Payload | Descripción |
88
+ |---|---|---|
89
+ | `map-ready` | `{ map: L.Map }` | El mapa ha sido inicializado |
90
+ | `click` | `{ latlng, originalEvent }` | Clic en el mapa |
91
+ | `zoom-change` | `{ zoom: Number }` | El nivel de zoom cambió |
92
+ | `move-end` | `{ center: L.LatLng }` | El mapa dejó de moverse |
93
+ | `marker-click` | `{ latlng }` | Clic en el marcador |
94
+
95
+ #### Métodos (vía `ref`)
96
+
97
+ ```js
98
+ const mapRef = ref(null)
99
+
100
+ mapRef.value.flyTo(lat, lng, zoom) // Animar desplazamiento al punto
101
+ mapRef.value.setView(lat, lng, zoom) // Centrar sin animación
102
+ mapRef.value.getLeafletMap() // Instancia L.Map raw para uso avanzado
103
+ mapRef.value.addMarker({ lat, lng, icon, iconSize, iconAnchor, popup })
104
+ mapRef.value.clearMarkers() // Eliminar todos los marcadores extra
105
+ ```
106
+
107
+ #### Slot `overlay`
108
+
109
+ Permite superponer contenido personalizado sobre el mapa:
110
+
111
+ ```html
112
+ <OsmMap :lat="40.41" :lng="-3.70">
113
+ <template #overlay>
114
+ <div class="mi-panel">Contenido encima del mapa</div>
115
+ </template>
116
+ </OsmMap>
117
+ ```
118
+
119
+ ---
120
+
121
+ ### `<OsmMapEmbed>`
122
+
123
+ Genera un `<iframe>` apuntando a un mapa de OpenStreetMap embebido. Útil cuando no se quiere cargar Leaflet en el bundle del cliente.
124
+
125
+ #### Props
126
+
127
+ | Prop | Tipo | Default | Requerido | Descripción |
128
+ |---|---|---|---|---|
129
+ | `lat` | `Number` | — | ✅ | Latitud |
130
+ | `lng` | `Number` | — | ✅ | Longitud |
131
+ | `zoom` | `Number` | `13` | — | Nivel de zoom |
132
+ | `height` | `String` | `'400px'` | — | Alto del iframe |
133
+ | `width` | `String` | `'100%'` | — | Ancho del iframe |
134
+ | `markerLat` | `Number` | igual que `lat` | — | Latitud del marcador (si difiere del centro) |
135
+ | `markerLng` | `Number` | igual que `lng` | — | Longitud del marcador |
136
+ | `embedSrc` | `String` | auto-generado | — | URL iframe completa personalizada |
137
+ | `title` | `String` | `'Mapa'` | — | Atributo `title` del iframe (accesibilidad) |
138
+ | `sandbox` | `String` | `null` | — | Valor del atributo `sandbox` del iframe |
139
+
140
+ ---
141
+
142
+ ## Capas de mapa (`tileLayer`)
143
+
144
+ | Valor | Proveedor | API key | Descripción |
145
+ |---|---|---|---|
146
+ | `'osm'` | OpenStreetMap Mapnik | No | Capa estándar OSM (default) |
147
+ | `'osm-hot'` | OSM Humanitarian | No | Estilo humanitario, alto contraste |
148
+ | `'carto-light'` | CartoDB Positron | No | Blanco y gris, minimalista |
149
+ | `'carto-dark'` | CartoDB Dark Matter | No | Fondo oscuro |
150
+ | `'carto-voyager'` | CartoDB Voyager | No | Colorida y moderna, buena alternativa gratuita |
151
+ | `'opentopomap'` | OpenTopoMap | No | Topográfica (máx. zoom 17) |
152
+ | `'esri-satellite'` | Esri World Imagery | Sí ⚠️ | Satélite |
153
+ | `'stadia-alidade'` | Stadia Maps | Sí ⚠️ | Estilo limpio moderno |
154
+
155
+ ### ⚠️ Capas que requieren API key
156
+
157
+ **Stadia Maps** (`'stadia-alidade'`)
158
+ Requiere una API key para uso en producción. El plan gratuito cubre proyectos no comerciales con tráfico moderado.
159
+ → Obtén tu clave en [stadiamaps.com/auth/signup](https://stadiamaps.com/auth/signup)
160
+
161
+ ```html
162
+ <OsmMap
163
+ tile-url="https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png?api_key=TU_API_KEY"
164
+ :tile-options="{ maxZoom: 20, attribution: '© Stadia Maps © OpenStreetMap contributors' }"
165
+ />
166
+ ```
167
+
168
+ **Esri World Imagery** (`'esri-satellite'`)
169
+ Requiere una cuenta de ArcGIS. El uso sin cuenta puede infringir sus términos de servicio en producción.
170
+ → Información en [developers.arcgis.com](https://developers.arcgis.com)
171
+
172
+ ```html
173
+ <OsmMap
174
+ tile-url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}?token=TU_TOKEN"
175
+ :tile-options="{ maxZoom: 18, attribution: 'Tiles © Esri' }"
176
+ />
177
+ ```
178
+
179
+ Para URL propia, usar `tile-url`:
180
+
181
+ ```html
182
+ <OsmMap
183
+ :lat="40.41" :lng="-3.70"
184
+ tile-url="https://mi-servidor/{z}/{x}/{y}.png"
185
+ :tile-options="{ maxZoom: 18, attribution: '© Mi empresa' }"
186
+ />
187
+ ```
188
+
189
+ ### Filtros de color (`tileFilter`)
190
+
191
+ | Valor | Efecto |
192
+ |---|---|
193
+ | `null` | Sin filtro (default) |
194
+ | `'grayscale'` | Escala de grises |
195
+ | `'invert'` | Colores invertidos (útil para dark mode) |
196
+ | `'sepia'` | Tono sepia |
197
+ | `String` | Valor CSS `filter` arbitrario, ej: `'hue-rotate(180deg) saturate(0.5)'` |
198
+
199
+ ---
200
+
201
+ ## Sistema de controles (`controls`)
202
+
203
+ | Valor | Resultado |
204
+ |---|---|
205
+ | `'all'` | Zoom + escala + atribución |
206
+ | `'zoom'` | Solo botones de zoom (+/−) |
207
+ | `'none'` | Sin controles |
208
+ | `Array` | Lista explícita: `['zoom', 'scale']` |
209
+
210
+ Valores válidos en array: `'zoom'`, `'scale'`, `'attribution'`.
211
+
212
+ ---
213
+
214
+ ## Ejemplos
215
+
216
+ ### Vue 3 — Mapa básico
217
+
218
+ ```vue
219
+ <template>
220
+ <OsmMap :lat="40.4168" :lng="-3.7038" />
221
+ </template>
222
+ ```
223
+
224
+ ### Vue 3 — Mapa personalizado con eventos
225
+
226
+ ```vue
227
+ <template>
228
+ <OsmMap
229
+ :lat="40.4168"
230
+ :lng="-3.7038"
231
+ :zoom="15"
232
+ height="500px"
233
+ tile-layer="carto-light"
234
+ tile-filter="grayscale"
235
+ marker-popup="<b>Madrid</b><br>Centro"
236
+ controls="zoom"
237
+ :scroll-wheel-zoom="false"
238
+ @map-ready="onReady"
239
+ @click="onClick"
240
+ @marker-click="onMarkerClick"
241
+ />
242
+ </template>
243
+
244
+ <script setup>
245
+ const onReady = ({ map }) => console.log('Mapa listo', map)
246
+ const onClick = ({ latlng }) => console.log('Clic en', latlng)
247
+ const onMarkerClick = ({ latlng }) => console.log('Marcador clicado', latlng)
248
+ </script>
249
+ ```
250
+
251
+ ### Vue 3 — Control programático vía ref
252
+
253
+ ```vue
254
+ <template>
255
+ <OsmMap ref="mapRef" :lat="40.4168" :lng="-3.7038" />
256
+ <button @click="volarABarcelona">Ir a Barcelona</button>
257
+ <button @click="añadirPin">Añadir pin</button>
258
+ </template>
259
+
260
+ <script setup>
261
+ import { ref } from 'vue'
262
+
263
+ const mapRef = ref(null)
264
+
265
+ function volarABarcelona() {
266
+ mapRef.value.flyTo(41.3874, 2.1686, 14)
267
+ }
268
+
269
+ function añadirPin() {
270
+ mapRef.value.addMarker({
271
+ lat: 41.3874,
272
+ lng: 2.1686,
273
+ popup: '<b>Barcelona</b>',
274
+ })
275
+ }
276
+ </script>
277
+ ```
278
+
279
+ ### Vue 3 — Slot overlay
280
+
281
+ ```vue
282
+ <template>
283
+ <OsmMap :lat="40.4168" :lng="-3.7038" height="500px">
284
+ <template #overlay>
285
+ <div style="position: absolute; top: 10px; right: 10px; background: white; padding: 8px; border-radius: 4px;">
286
+ Panel personalizado
287
+ </div>
288
+ </template>
289
+ </OsmMap>
290
+ </template>
291
+ ```
292
+
293
+ ### Vue 3 — Mapa estático sin controles
294
+
295
+ ```vue
296
+ <template>
297
+ <OsmMap
298
+ :lat="40.4168"
299
+ :lng="-3.7038"
300
+ controls="none"
301
+ :draggable="false"
302
+ :scroll-wheel-zoom="false"
303
+ :double-click-zoom="false"
304
+ />
305
+ </template>
306
+ ```
307
+
308
+ ### Vue 3 — Iframe embebido
309
+
310
+ ```vue
311
+ <template>
312
+ <OsmMapEmbed
313
+ :lat="40.4168"
314
+ :lng="-3.7038"
315
+ :zoom="14"
316
+ height="400px"
317
+ title="Ubicación de nuestra oficina"
318
+ />
319
+ </template>
320
+ ```
321
+
322
+ ### Vue 2 — Mapa básico
323
+
324
+ ```vue
325
+ <template>
326
+ <osm-map :lat="40.4168" :lng="-3.7038" />
327
+ </template>
328
+
329
+ <script>
330
+ export default {
331
+ name: 'MiComponente',
332
+ }
333
+ </script>
334
+ ```
335
+
336
+ ### Vue 2 — Mapa personalizado con eventos
337
+
338
+ ```vue
339
+ <template>
340
+ <osm-map
341
+ :lat="40.4168"
342
+ :lng="-3.7038"
343
+ :zoom="15"
344
+ height="500px"
345
+ tile-layer="carto-light"
346
+ tile-filter="grayscale"
347
+ marker-popup="<b>Madrid</b><br>Centro"
348
+ controls="zoom"
349
+ :scroll-wheel-zoom="false"
350
+ @map-ready="onReady"
351
+ @click="onClick"
352
+ />
353
+ </template>
354
+
355
+ <script>
356
+ export default {
357
+ methods: {
358
+ onReady({ map }) {
359
+ console.log('Mapa listo', map)
360
+ },
361
+ onClick({ latlng }) {
362
+ console.log('Clic en', latlng)
363
+ },
364
+ },
365
+ }
366
+ </script>
367
+ ```
368
+
369
+ ### Vue 2 — Control programático vía ref
370
+
371
+ ```vue
372
+ <template>
373
+ <div>
374
+ <osm-map ref="mapRef" :lat="40.4168" :lng="-3.7038" />
375
+ <button @click="volarABarcelona">Ir a Barcelona</button>
376
+ </div>
377
+ </template>
378
+
379
+ <script>
380
+ export default {
381
+ methods: {
382
+ volarABarcelona() {
383
+ this.$refs.mapRef.flyTo(41.3874, 2.1686, 14)
384
+ },
385
+ },
386
+ }
387
+ </script>
388
+ ```
389
+
390
+ ### Vue 2 — Iframe embebido
391
+
392
+ ```vue
393
+ <template>
394
+ <osm-map-embed
395
+ :lat="40.4168"
396
+ :lng="-3.7038"
397
+ :zoom="14"
398
+ height="400px"
399
+ title="Nuestra ubicación"
400
+ />
401
+ </template>
402
+
403
+ <script>
404
+ export default {
405
+ name: 'MiMapa',
406
+ }
407
+ </script>
408
+ ```
409
+
410
+ ---
411
+
412
+ ## Consideraciones de licencia
413
+
414
+ - **OpenStreetMap** requiere atribución visible. No desactivar `attribution-control` en producción salvo que uses un tile server propio con su propia atribución.
415
+ - Las capas de terceros (CartoDB, Stadia, Esri) tienen sus propios términos de servicio. Revisa su documentación antes de usarlas en producción.
416
+
417
+ ---
418
+
419
+ ## Hoja de ruta
420
+
421
+ - [ ] Soporte para múltiples marcadores (`markers: Array<{lat, lng, icon?, popup?}>`)
422
+ - [ ] Dibujar polilíneas y polígonos
423
+ - [ ] Clustering de marcadores (via Leaflet.markercluster)
424
+ - [ ] Plugin de geolocalización
425
+ - [ ] Modo offline con teselas locales
426
+ - [ ] Storybook con ejemplos interactivos
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const b=require("vue-demi"),k=require("leaflet"),m=require("vue"),T={osm:{url:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',maxZoom:19}},"osm-hot":{url:"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Tiles style by <a href="https://www.hotosm.org/" target="_blank">Humanitarian OpenStreetMap Team</a>',maxZoom:19}},"carto-light":{url:"https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',subdomains:"abcd",maxZoom:20}},"carto-dark":{url:"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',subdomains:"abcd",maxZoom:20}},"esri-satellite":{url:"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",options:{attribution:"Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community",maxZoom:18}},"stadia-alidade":{url:"https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png",options:{attribution:'&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',maxZoom:20}},"carto-voyager":{url:"https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',subdomains:"abcd",maxZoom:20}},opentopomap:{url:"https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",options:{attribution:'Map data: &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="https://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',maxZoom:17}}},F={grayscale:"grayscale(100%)",invert:"invert(100%)",sepia:"sepia(100%)"};function Y(){function e(t,r,o,n){let a,l={};if(r)a=r,l={...o};else{const i=T[t]||T.osm;a=i.url,l={...i.options,...o}}const s=k.tileLayer(a,l);if(n){const i=F[n]||n;s.on("tileload",u=>{u.tile.style.filter=i})}return s}return{createTileLayer:e}}function H(){const e=[];function t(a,l,s){if(!a)return null;const i=l||[32,32],u=s||[i[0]/2,i[1]];return k.icon({iconUrl:a,iconSize:i,iconAnchor:u,popupAnchor:[0,-u[1]]})}function r(a,l,s,i,u,M,p,y){const d=t(i,u,M),f=d?{icon:d}:{},w=k.marker([l,s],f).addTo(a);return p&&w.bindPopup(p),w.on("click",S=>{y({latlng:S.latlng})}),w}function o(a,{lat:l,lng:s,icon:i,iconSize:u,iconAnchor:M,popup:p}={}){const y=t(i,u,M),d=y?{icon:y}:{},f=k.marker([l,s],d).addTo(a);return p&&f.bindPopup(p),e.push(f),f}function n(a){e.forEach(l=>a.removeLayer(l)),e.length=0}return{createMainMarker:r,addMarker:o,clearMarkers:n}}const z={zoom:e=>{e.zoomControl||k.control.zoom().addTo(e)},scale:e=>{k.control.scale().addTo(e)},attribution:e=>{e.attributionControl||k.control.attribution().addTo(e)}};function X(){function e(t,r){if(t.zoomControl.remove(),r!=="none"){if(r==="all"){Object.values(z).forEach(o=>o(t));return}if(r==="zoom"){z.zoom(t);return}Array.isArray(r)&&r.forEach(o=>{z[o]&&z[o](t)})}}return{applyControls:e}}function J(e){let t=null,r=null;const{createTileLayer:o}=Y(),{createMainMarker:n,addMarker:a,clearMarkers:l}=H(),{applyControls:s}=X();function i(c,h){const{lat:g,lng:O,zoom:C,minZoom:_,maxZoom:A,tileLayer:$,tileUrl:Z,tileOptions:B,tileFilter:N,showMarker:I,markerIcon:P,markerIconSize:R,markerAnchor:V,markerPopup:G,controls:q,draggable:U,scrollWheelZoom:j,doubleClickZoom:W,attributionControl:D}=h;t=k.map(c,{center:[g,O],zoom:C,minZoom:_,maxZoom:A,dragging:U,scrollWheelZoom:j,doubleClickZoom:W,attributionControl:D,zoomControl:!0}),o($,Z,B,N).addTo(t),s(t,q),I&&(r=n(t,g,O,P,R,V,G,v=>e("marker-click",v))),t.on("click",v=>{e("click",{latlng:v.latlng,originalEvent:v.originalEvent})}),t.on("zoomend",()=>{e("zoom-change",{zoom:t.getZoom()})}),t.on("moveend",()=>{e("move-end",{center:t.getCenter()})}),e("map-ready",{map:t})}function u(){t&&(t.remove(),t=null,r=null)}function M(c,h,g){t==null||t.flyTo([c,h],g)}function p(c,h,g){t==null||t.setView([c,h],g)}function y(){return t}function d(c){return t?a(t,c):null}function f(){t&&l(t)}function w(c){t&&(r&&(t.removeLayer(r),r=null),c.showMarker&&(r=n(t,c.lat,c.lng,c.markerIcon,c.markerIconSize,c.markerAnchor,c.markerPopup,h=>e("marker-click",h))))}function S(c,h,g){t==null||t.setView([c,h],g,{animate:!1})}return{initMap:i,destroyMap:u,flyTo:M,setView:p,getLeafletMap:y,addMarker:d,clearMarkers:f,updateMarker:w,updateView:S}}const x=(e,t)=>{const r=e.__vccOpts||e;for(const[o,n]of t)r[o]=n;return r},K=b.defineComponent({name:"OsmMap",props:{lat:{type:Number,required:!0},lng:{type:Number,required:!0},zoom:{type:Number,default:13},minZoom:{type:Number,default:1},maxZoom:{type:Number,default:19},height:{type:String,default:"400px"},width:{type:String,default:"100%"},tileLayer:{type:String,default:"osm"},tileUrl:{type:String,default:null},tileOptions:{type:Object,default:()=>({})},tileFilter:{type:String,default:null},showMarker:{type:Boolean,default:!0},markerIcon:{type:String,default:null},markerIconSize:{type:Array,default:()=>[32,32]},markerAnchor:{type:Array,default:null},markerPopup:{type:String,default:null},controls:{type:[String,Array],default:"all"},draggable:{type:Boolean,default:!0},scrollWheelZoom:{type:Boolean,default:!0},doubleClickZoom:{type:Boolean,default:!0},attributionControl:{type:Boolean,default:!0}},emits:["map-ready","click","zoom-change","move-end","marker-click"],setup(e,{emit:t,expose:r}){const o=b.ref(null),{initMap:n,destroyMap:a,flyTo:l,setView:s,getLeafletMap:i,addMarker:u,clearMarkers:M,updateMarker:p,updateView:y}=J(t);b.onMounted(()=>{n(o.value,e)}),b.onBeforeUnmount(()=>{a()}),b.watch(()=>[e.lat,e.lng,e.zoom],([f,w,S])=>{y(f,w,S)}),b.watch(()=>[e.showMarker,e.markerIcon,e.markerIconSize,e.markerAnchor,e.markerPopup],()=>{p(e)});const d={flyTo:l,setView:s,getLeafletMap:i,addMarker:u,clearMarkers:M};return r&&r(d),{mapEl:o,...d}}}),Q={ref:"mapEl",class:"abn-osmvue-map"},ee={key:0,class:"abn-osmvue-overlay"};function te(e,t,r,o,n,a){return m.openBlock(),m.createElementBlock("div",{class:"abn-osmvue-wrapper",style:m.normalizeStyle({height:e.height,width:e.width})},[m.createElementVNode("div",Q,null,512),e.$slots.overlay?(m.openBlock(),m.createElementBlock("div",ee,[m.renderSlot(e.$slots,"overlay")])):m.createCommentVNode("",!0)],4)}const E=x(K,[["render",te]]),re=b.defineComponent({name:"OsmMapEmbed",props:{lat:{type:Number,required:!0},lng:{type:Number,required:!0},zoom:{type:Number,default:13},height:{type:String,default:"400px"},width:{type:String,default:"100%"},markerLat:{type:Number,default:null},markerLng:{type:Number,default:null},embedSrc:{type:String,default:null},title:{type:String,default:"Mapa"},sandbox:{type:String,default:null}},setup(e){return{iframeSrc:b.computed(()=>{if(e.embedSrc)return e.embedSrc;const r=e.markerLat??e.lat,o=e.markerLng??e.lng,n=.01*Math.pow(2,13-e.zoom),a=e.lng-n,l=e.lat-n*.6,s=e.lng+n,i=e.lat+n*.6;return`https://www.openstreetmap.org/export/embed.html?bbox=${`${a},${l},${s},${i}`}&layer=mapnik&marker=${r},${o}`})}}}),oe=["src","width","height","title","sandbox"];function ae(e,t,r,o,n,a){return m.openBlock(),m.createElementBlock("iframe",{src:e.iframeSrc,width:e.width,height:e.height,title:e.title,sandbox:e.sandbox||void 0,class:"abn-osmvue-embed",frameborder:"0",scrolling:"no",marginheight:"0",marginwidth:"0",allowfullscreen:""},null,8,oe)}const L=x(re,[["render",ae]]),ne={install(e){e.component("OsmMap",E),e.component("OsmMapEmbed",L)}};exports.OsmMap=E;exports.OsmMapEmbed=L;exports.default=ne;
@@ -0,0 +1,367 @@
1
+ import { defineComponent as L, ref as Y, onMounted as D, onBeforeUnmount as H, watch as O, computed as X } from "vue-demi";
2
+ import g from "leaflet";
3
+ import { openBlock as v, createElementBlock as z, normalizeStyle as J, createElementVNode as K, renderSlot as Q, createCommentVNode as ee } from "vue";
4
+ const T = {
5
+ osm: {
6
+ url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
7
+ options: {
8
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
9
+ maxZoom: 19
10
+ }
11
+ },
12
+ "osm-hot": {
13
+ url: "https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
14
+ options: {
15
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Tiles style by <a href="https://www.hotosm.org/" target="_blank">Humanitarian OpenStreetMap Team</a>',
16
+ maxZoom: 19
17
+ }
18
+ },
19
+ "carto-light": {
20
+ url: "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
21
+ options: {
22
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
23
+ subdomains: "abcd",
24
+ maxZoom: 20
25
+ }
26
+ },
27
+ "carto-dark": {
28
+ url: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",
29
+ options: {
30
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
31
+ subdomains: "abcd",
32
+ maxZoom: 20
33
+ }
34
+ },
35
+ "esri-satellite": {
36
+ url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
37
+ options: {
38
+ attribution: "Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community",
39
+ maxZoom: 18
40
+ }
41
+ },
42
+ "stadia-alidade": {
43
+ url: "https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png",
44
+ options: {
45
+ attribution: '&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
46
+ maxZoom: 20
47
+ }
48
+ },
49
+ "carto-voyager": {
50
+ url: "https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",
51
+ options: {
52
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
53
+ subdomains: "abcd",
54
+ maxZoom: 20
55
+ }
56
+ },
57
+ opentopomap: {
58
+ url: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
59
+ options: {
60
+ attribution: 'Map data: &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="https://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',
61
+ maxZoom: 17
62
+ }
63
+ }
64
+ }, te = {
65
+ grayscale: "grayscale(100%)",
66
+ invert: "invert(100%)",
67
+ sepia: "sepia(100%)"
68
+ };
69
+ function re() {
70
+ function e(t, r, o, n) {
71
+ let a, l = {};
72
+ if (r)
73
+ a = r, l = { ...o };
74
+ else {
75
+ const i = T[t] || T.osm;
76
+ a = i.url, l = { ...i.options, ...o };
77
+ }
78
+ const c = g.tileLayer(a, l);
79
+ if (n) {
80
+ const i = te[n] || n;
81
+ c.on("tileload", (u) => {
82
+ u.tile.style.filter = i;
83
+ });
84
+ }
85
+ return c;
86
+ }
87
+ return { createTileLayer: e };
88
+ }
89
+ function oe() {
90
+ const e = [];
91
+ function t(a, l, c) {
92
+ if (!a) return null;
93
+ const i = l || [32, 32], u = c || [i[0] / 2, i[1]];
94
+ return g.icon({
95
+ iconUrl: a,
96
+ iconSize: i,
97
+ iconAnchor: u,
98
+ popupAnchor: [0, -u[1]]
99
+ });
100
+ }
101
+ function r(a, l, c, i, u, b, m, h) {
102
+ const p = t(i, u, b), d = p ? { icon: p } : {}, k = g.marker([l, c], d).addTo(a);
103
+ return m && k.bindPopup(m), k.on("click", (M) => {
104
+ h({ latlng: M.latlng });
105
+ }), k;
106
+ }
107
+ function o(a, { lat: l, lng: c, icon: i, iconSize: u, iconAnchor: b, popup: m } = {}) {
108
+ const h = t(i, u, b), p = h ? { icon: h } : {}, d = g.marker([l, c], p).addTo(a);
109
+ return m && d.bindPopup(m), e.push(d), d;
110
+ }
111
+ function n(a) {
112
+ e.forEach((l) => a.removeLayer(l)), e.length = 0;
113
+ }
114
+ return { createMainMarker: r, addMarker: o, clearMarkers: n };
115
+ }
116
+ const S = {
117
+ zoom: (e) => {
118
+ e.zoomControl || g.control.zoom().addTo(e);
119
+ },
120
+ scale: (e) => {
121
+ g.control.scale().addTo(e);
122
+ },
123
+ attribution: (e) => {
124
+ e.attributionControl || g.control.attribution().addTo(e);
125
+ }
126
+ };
127
+ function ae() {
128
+ function e(t, r) {
129
+ if (t.zoomControl.remove(), r !== "none") {
130
+ if (r === "all") {
131
+ Object.values(S).forEach((o) => o(t));
132
+ return;
133
+ }
134
+ if (r === "zoom") {
135
+ S.zoom(t);
136
+ return;
137
+ }
138
+ Array.isArray(r) && r.forEach((o) => {
139
+ S[o] && S[o](t);
140
+ });
141
+ }
142
+ }
143
+ return { applyControls: e };
144
+ }
145
+ function ne(e) {
146
+ let t = null, r = null;
147
+ const { createTileLayer: o } = re(), { createMainMarker: n, addMarker: a, clearMarkers: l } = oe(), { applyControls: c } = ae();
148
+ function i(s, f) {
149
+ const {
150
+ lat: y,
151
+ lng: x,
152
+ zoom: C,
153
+ minZoom: E,
154
+ maxZoom: _,
155
+ tileLayer: $,
156
+ tileUrl: Z,
157
+ tileOptions: N,
158
+ tileFilter: I,
159
+ showMarker: B,
160
+ markerIcon: P,
161
+ markerIconSize: R,
162
+ markerAnchor: V,
163
+ markerPopup: G,
164
+ controls: U,
165
+ draggable: q,
166
+ scrollWheelZoom: W,
167
+ doubleClickZoom: j,
168
+ attributionControl: F
169
+ } = f;
170
+ t = g.map(s, {
171
+ center: [y, x],
172
+ zoom: C,
173
+ minZoom: E,
174
+ maxZoom: _,
175
+ dragging: q,
176
+ scrollWheelZoom: W,
177
+ doubleClickZoom: j,
178
+ attributionControl: F,
179
+ zoomControl: !0
180
+ }), o($, Z, N, I).addTo(t), c(t, U), B && (r = n(
181
+ t,
182
+ y,
183
+ x,
184
+ P,
185
+ R,
186
+ V,
187
+ G,
188
+ (w) => e("marker-click", w)
189
+ )), t.on("click", (w) => {
190
+ e("click", { latlng: w.latlng, originalEvent: w.originalEvent });
191
+ }), t.on("zoomend", () => {
192
+ e("zoom-change", { zoom: t.getZoom() });
193
+ }), t.on("moveend", () => {
194
+ e("move-end", { center: t.getCenter() });
195
+ }), e("map-ready", { map: t });
196
+ }
197
+ function u() {
198
+ t && (t.remove(), t = null, r = null);
199
+ }
200
+ function b(s, f, y) {
201
+ t == null || t.flyTo([s, f], y);
202
+ }
203
+ function m(s, f, y) {
204
+ t == null || t.setView([s, f], y);
205
+ }
206
+ function h() {
207
+ return t;
208
+ }
209
+ function p(s) {
210
+ return t ? a(t, s) : null;
211
+ }
212
+ function d() {
213
+ t && l(t);
214
+ }
215
+ function k(s) {
216
+ t && (r && (t.removeLayer(r), r = null), s.showMarker && (r = n(
217
+ t,
218
+ s.lat,
219
+ s.lng,
220
+ s.markerIcon,
221
+ s.markerIconSize,
222
+ s.markerAnchor,
223
+ s.markerPopup,
224
+ (f) => e("marker-click", f)
225
+ )));
226
+ }
227
+ function M(s, f, y) {
228
+ t == null || t.setView([s, f], y, { animate: !1 });
229
+ }
230
+ return {
231
+ initMap: i,
232
+ destroyMap: u,
233
+ flyTo: b,
234
+ setView: m,
235
+ getLeafletMap: h,
236
+ addMarker: p,
237
+ clearMarkers: d,
238
+ updateMarker: k,
239
+ updateView: M
240
+ };
241
+ }
242
+ const A = (e, t) => {
243
+ const r = e.__vccOpts || e;
244
+ for (const [o, n] of t)
245
+ r[o] = n;
246
+ return r;
247
+ }, ie = L({
248
+ name: "OsmMap",
249
+ props: {
250
+ lat: { type: Number, required: !0 },
251
+ lng: { type: Number, required: !0 },
252
+ zoom: { type: Number, default: 13 },
253
+ minZoom: { type: Number, default: 1 },
254
+ maxZoom: { type: Number, default: 19 },
255
+ height: { type: String, default: "400px" },
256
+ width: { type: String, default: "100%" },
257
+ tileLayer: { type: String, default: "osm" },
258
+ tileUrl: { type: String, default: null },
259
+ tileOptions: { type: Object, default: () => ({}) },
260
+ tileFilter: { type: String, default: null },
261
+ showMarker: { type: Boolean, default: !0 },
262
+ markerIcon: { type: String, default: null },
263
+ markerIconSize: { type: Array, default: () => [32, 32] },
264
+ markerAnchor: { type: Array, default: null },
265
+ markerPopup: { type: String, default: null },
266
+ controls: { type: [String, Array], default: "all" },
267
+ draggable: { type: Boolean, default: !0 },
268
+ scrollWheelZoom: { type: Boolean, default: !0 },
269
+ doubleClickZoom: { type: Boolean, default: !0 },
270
+ attributionControl: { type: Boolean, default: !0 }
271
+ },
272
+ emits: ["map-ready", "click", "zoom-change", "move-end", "marker-click"],
273
+ setup(e, { emit: t, expose: r }) {
274
+ const o = Y(null), {
275
+ initMap: n,
276
+ destroyMap: a,
277
+ flyTo: l,
278
+ setView: c,
279
+ getLeafletMap: i,
280
+ addMarker: u,
281
+ clearMarkers: b,
282
+ updateMarker: m,
283
+ updateView: h
284
+ } = ne(t);
285
+ D(() => {
286
+ n(o.value, e);
287
+ }), H(() => {
288
+ a();
289
+ }), O(
290
+ () => [e.lat, e.lng, e.zoom],
291
+ ([d, k, M]) => {
292
+ h(d, k, M);
293
+ }
294
+ ), O(
295
+ () => [e.showMarker, e.markerIcon, e.markerIconSize, e.markerAnchor, e.markerPopup],
296
+ () => {
297
+ m(e);
298
+ }
299
+ );
300
+ const p = { flyTo: l, setView: c, getLeafletMap: i, addMarker: u, clearMarkers: b };
301
+ return r && r(p), { mapEl: o, ...p };
302
+ }
303
+ }), le = {
304
+ ref: "mapEl",
305
+ class: "abn-osmvue-map"
306
+ }, se = {
307
+ key: 0,
308
+ class: "abn-osmvue-overlay"
309
+ };
310
+ function ce(e, t, r, o, n, a) {
311
+ return v(), z("div", {
312
+ class: "abn-osmvue-wrapper",
313
+ style: J({ height: e.height, width: e.width })
314
+ }, [
315
+ K("div", le, null, 512),
316
+ e.$slots.overlay ? (v(), z("div", se, [
317
+ Q(e.$slots, "overlay")
318
+ ])) : ee("", !0)
319
+ ], 4);
320
+ }
321
+ const ue = /* @__PURE__ */ A(ie, [["render", ce]]), me = L({
322
+ name: "OsmMapEmbed",
323
+ props: {
324
+ lat: { type: Number, required: !0 },
325
+ lng: { type: Number, required: !0 },
326
+ zoom: { type: Number, default: 13 },
327
+ height: { type: String, default: "400px" },
328
+ width: { type: String, default: "100%" },
329
+ markerLat: { type: Number, default: null },
330
+ markerLng: { type: Number, default: null },
331
+ embedSrc: { type: String, default: null },
332
+ title: { type: String, default: "Mapa" },
333
+ sandbox: { type: String, default: null }
334
+ },
335
+ setup(e) {
336
+ return { iframeSrc: X(() => {
337
+ if (e.embedSrc) return e.embedSrc;
338
+ const r = e.markerLat ?? e.lat, o = e.markerLng ?? e.lng, n = 0.01 * Math.pow(2, 13 - e.zoom), a = e.lng - n, l = e.lat - n * 0.6, c = e.lng + n, i = e.lat + n * 0.6;
339
+ return `https://www.openstreetmap.org/export/embed.html?bbox=${`${a},${l},${c},${i}`}&layer=mapnik&marker=${r},${o}`;
340
+ }) };
341
+ }
342
+ }), pe = ["src", "width", "height", "title", "sandbox"];
343
+ function de(e, t, r, o, n, a) {
344
+ return v(), z("iframe", {
345
+ src: e.iframeSrc,
346
+ width: e.width,
347
+ height: e.height,
348
+ title: e.title,
349
+ sandbox: e.sandbox || void 0,
350
+ class: "abn-osmvue-embed",
351
+ frameborder: "0",
352
+ scrolling: "no",
353
+ marginheight: "0",
354
+ marginwidth: "0",
355
+ allowfullscreen: ""
356
+ }, null, 8, pe);
357
+ }
358
+ const fe = /* @__PURE__ */ A(me, [["render", de]]), be = {
359
+ install(e) {
360
+ e.component("OsmMap", ue), e.component("OsmMapEmbed", fe);
361
+ }
362
+ };
363
+ export {
364
+ ue as OsmMap,
365
+ fe as OsmMapEmbed,
366
+ be as default
367
+ };
@@ -0,0 +1 @@
1
+ (function(p,m){typeof exports=="object"&&typeof module<"u"?m(exports,require("vue-demi"),require("leaflet"),require("vue")):typeof define=="function"&&define.amd?define(["exports","vue-demi","leaflet","vue"],m):(p=typeof globalThis<"u"?globalThis:p||self,m(p.AbnOsmVue={},p.VueDemi,p.L,p.Vue))})(this,function(p,m,b,d){"use strict";const x={osm:{url:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',maxZoom:19}},"osm-hot":{url:"https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Tiles style by <a href="https://www.hotosm.org/" target="_blank">Humanitarian OpenStreetMap Team</a>',maxZoom:19}},"carto-light":{url:"https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',subdomains:"abcd",maxZoom:20}},"carto-dark":{url:"https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',subdomains:"abcd",maxZoom:20}},"esri-satellite":{url:"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",options:{attribution:"Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community",maxZoom:18}},"stadia-alidade":{url:"https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png",options:{attribution:'&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',maxZoom:20}},"carto-voyager":{url:"https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png",options:{attribution:'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',subdomains:"abcd",maxZoom:20}},opentopomap:{url:"https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",options:{attribution:'Map data: &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="https://viewfinderpanoramas.org">SRTM</a> | Map style: &copy; <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)',maxZoom:17}}},v={grayscale:"grayscale(100%)",invert:"invert(100%)",sepia:"sepia(100%)"};function $(){function e(t,r,o,n){let a,l={};if(r)a=r,l={...o};else{const i=x[t]||x.osm;a=i.url,l={...i.options,...o}}const c=b.tileLayer(a,l);if(n){const i=v[n]||n;c.on("tileload",u=>{u.tile.style.filter=i})}return c}return{createTileLayer:e}}function L(){const e=[];function t(a,l,c){if(!a)return null;const i=l||[32,32],u=c||[i[0]/2,i[1]];return b.icon({iconUrl:a,iconSize:i,iconAnchor:u,popupAnchor:[0,-u[1]]})}function r(a,l,c,i,u,w,f,k){const h=t(i,u,w),y=h?{icon:h}:{},S=b.marker([l,c],y).addTo(a);return f&&S.bindPopup(f),S.on("click",O=>{k({latlng:O.latlng})}),S}function o(a,{lat:l,lng:c,icon:i,iconSize:u,iconAnchor:w,popup:f}={}){const k=t(i,u,w),h=k?{icon:k}:{},y=b.marker([l,c],h).addTo(a);return f&&y.bindPopup(f),e.push(y),y}function n(a){e.forEach(l=>a.removeLayer(l)),e.length=0}return{createMainMarker:r,addMarker:o,clearMarkers:n}}const z={zoom:e=>{e.zoomControl||b.control.zoom().addTo(e)},scale:e=>{b.control.scale().addTo(e)},attribution:e=>{e.attributionControl||b.control.attribution().addTo(e)}};function Z(){function e(t,r){if(t.zoomControl.remove(),r!=="none"){if(r==="all"){Object.values(z).forEach(o=>o(t));return}if(r==="zoom"){z.zoom(t);return}Array.isArray(r)&&r.forEach(o=>{z[o]&&z[o](t)})}}return{applyControls:e}}function B(e){let t=null,r=null;const{createTileLayer:o}=$(),{createMainMarker:n,addMarker:a,clearMarkers:l}=L(),{applyControls:c}=Z();function i(s,g){const{lat:M,lng:_,zoom:j,minZoom:W,maxZoom:F,tileLayer:Y,tileUrl:H,tileOptions:X,tileFilter:J,showMarker:K,markerIcon:Q,markerIconSize:D,markerAnchor:ee,markerPopup:te,controls:re,draggable:oe,scrollWheelZoom:ae,doubleClickZoom:ne,attributionControl:ie}=g;t=b.map(s,{center:[M,_],zoom:j,minZoom:W,maxZoom:F,dragging:oe,scrollWheelZoom:ae,doubleClickZoom:ne,attributionControl:ie,zoomControl:!0}),o(Y,H,X,J).addTo(t),c(t,re),K&&(r=n(t,M,_,Q,D,ee,te,T=>e("marker-click",T))),t.on("click",T=>{e("click",{latlng:T.latlng,originalEvent:T.originalEvent})}),t.on("zoomend",()=>{e("zoom-change",{zoom:t.getZoom()})}),t.on("moveend",()=>{e("move-end",{center:t.getCenter()})}),e("map-ready",{map:t})}function u(){t&&(t.remove(),t=null,r=null)}function w(s,g,M){t==null||t.flyTo([s,g],M)}function f(s,g,M){t==null||t.setView([s,g],M)}function k(){return t}function h(s){return t?a(t,s):null}function y(){t&&l(t)}function S(s){t&&(r&&(t.removeLayer(r),r=null),s.showMarker&&(r=n(t,s.lat,s.lng,s.markerIcon,s.markerIconSize,s.markerAnchor,s.markerPopup,g=>e("marker-click",g))))}function O(s,g,M){t==null||t.setView([s,g],M,{animate:!1})}return{initMap:i,destroyMap:u,flyTo:w,setView:f,getLeafletMap:k,addMarker:h,clearMarkers:y,updateMarker:S,updateView:O}}const E=(e,t)=>{const r=e.__vccOpts||e;for(const[o,n]of t)r[o]=n;return r},N=m.defineComponent({name:"OsmMap",props:{lat:{type:Number,required:!0},lng:{type:Number,required:!0},zoom:{type:Number,default:13},minZoom:{type:Number,default:1},maxZoom:{type:Number,default:19},height:{type:String,default:"400px"},width:{type:String,default:"100%"},tileLayer:{type:String,default:"osm"},tileUrl:{type:String,default:null},tileOptions:{type:Object,default:()=>({})},tileFilter:{type:String,default:null},showMarker:{type:Boolean,default:!0},markerIcon:{type:String,default:null},markerIconSize:{type:Array,default:()=>[32,32]},markerAnchor:{type:Array,default:null},markerPopup:{type:String,default:null},controls:{type:[String,Array],default:"all"},draggable:{type:Boolean,default:!0},scrollWheelZoom:{type:Boolean,default:!0},doubleClickZoom:{type:Boolean,default:!0},attributionControl:{type:Boolean,default:!0}},emits:["map-ready","click","zoom-change","move-end","marker-click"],setup(e,{emit:t,expose:r}){const o=m.ref(null),{initMap:n,destroyMap:a,flyTo:l,setView:c,getLeafletMap:i,addMarker:u,clearMarkers:w,updateMarker:f,updateView:k}=B(t);m.onMounted(()=>{n(o.value,e)}),m.onBeforeUnmount(()=>{a()}),m.watch(()=>[e.lat,e.lng,e.zoom],([y,S,O])=>{k(y,S,O)}),m.watch(()=>[e.showMarker,e.markerIcon,e.markerIconSize,e.markerAnchor,e.markerPopup],()=>{f(e)});const h={flyTo:l,setView:c,getLeafletMap:i,addMarker:u,clearMarkers:w};return r&&r(h),{mapEl:o,...h}}}),I={ref:"mapEl",class:"abn-osmvue-map"},V={key:0,class:"abn-osmvue-overlay"};function P(e,t,r,o,n,a){return d.openBlock(),d.createElementBlock("div",{class:"abn-osmvue-wrapper",style:d.normalizeStyle({height:e.height,width:e.width})},[d.createElementVNode("div",I,null,512),e.$slots.overlay?(d.openBlock(),d.createElementBlock("div",V,[d.renderSlot(e.$slots,"overlay")])):d.createCommentVNode("",!0)],4)}const A=E(N,[["render",P]]),R=m.defineComponent({name:"OsmMapEmbed",props:{lat:{type:Number,required:!0},lng:{type:Number,required:!0},zoom:{type:Number,default:13},height:{type:String,default:"400px"},width:{type:String,default:"100%"},markerLat:{type:Number,default:null},markerLng:{type:Number,default:null},embedSrc:{type:String,default:null},title:{type:String,default:"Mapa"},sandbox:{type:String,default:null}},setup(e){return{iframeSrc:m.computed(()=>{if(e.embedSrc)return e.embedSrc;const r=e.markerLat??e.lat,o=e.markerLng??e.lng,n=.01*Math.pow(2,13-e.zoom),a=e.lng-n,l=e.lat-n*.6,c=e.lng+n,i=e.lat+n*.6;return`https://www.openstreetmap.org/export/embed.html?bbox=${`${a},${l},${c},${i}`}&layer=mapnik&marker=${r},${o}`})}}}),G=["src","width","height","title","sandbox"];function q(e,t,r,o,n,a){return d.openBlock(),d.createElementBlock("iframe",{src:e.iframeSrc,width:e.width,height:e.height,title:e.title,sandbox:e.sandbox||void 0,class:"abn-osmvue-embed",frameborder:"0",scrolling:"no",marginheight:"0",marginwidth:"0",allowfullscreen:""},null,8,G)}const C=E(R,[["render",q]]),U={install(e){e.component("OsmMap",A),e.component("OsmMapEmbed",C)}};p.OsmMap=A,p.OsmMapEmbed=C,p.default=U,Object.defineProperties(p,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .abn-osmvue-wrapper{position:relative;display:block}.abn-osmvue-map{width:100%;height:100%}.abn-osmvue-overlay{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:1000}.abn-osmvue-overlay>*{pointer-events:auto}.abn-osmvue-embed{display:block;border:none}
@@ -0,0 +1,71 @@
1
+ import { DefineComponent } from 'vue-demi'
2
+ import * as L from 'leaflet'
3
+
4
+ export interface OsmMapProps {
5
+ lat: number
6
+ lng: number
7
+ zoom?: number
8
+ minZoom?: number
9
+ maxZoom?: number
10
+ height?: string
11
+ width?: string
12
+ tileLayer?: 'osm' | 'osm-hot' | 'carto-light' | 'carto-dark' | 'carto-voyager' | 'opentopomap' | 'esri-satellite' | 'stadia-alidade'
13
+ tileUrl?: string | null
14
+ tileOptions?: Record<string, unknown>
15
+ tileFilter?: 'grayscale' | 'invert' | 'sepia' | string | null
16
+ showMarker?: boolean
17
+ markerIcon?: string | null
18
+ markerIconSize?: [number, number]
19
+ markerAnchor?: [number, number] | null
20
+ markerPopup?: string | null
21
+ controls?: 'all' | 'zoom' | 'none' | Array<'zoom' | 'scale' | 'attribution'>
22
+ draggable?: boolean
23
+ scrollWheelZoom?: boolean
24
+ doubleClickZoom?: boolean
25
+ attributionControl?: boolean
26
+ }
27
+
28
+ export interface OsmMapEmits {
29
+ (e: 'map-ready', payload: { map: L.Map }): void
30
+ (e: 'click', payload: { latlng: L.LatLng; originalEvent: MouseEvent }): void
31
+ (e: 'zoom-change', payload: { zoom: number }): void
32
+ (e: 'move-end', payload: { center: L.LatLng }): void
33
+ (e: 'marker-click', payload: { latlng: L.LatLng }): void
34
+ }
35
+
36
+ export interface OsmMapExpose {
37
+ flyTo(lat: number, lng: number, zoom?: number): void
38
+ setView(lat: number, lng: number, zoom?: number): void
39
+ getLeafletMap(): L.Map | null
40
+ addMarker(options: {
41
+ lat: number
42
+ lng: number
43
+ icon?: string
44
+ iconSize?: [number, number]
45
+ iconAnchor?: [number, number]
46
+ popup?: string
47
+ }): L.Marker | null
48
+ clearMarkers(): void
49
+ }
50
+
51
+ export interface OsmMapEmbedProps {
52
+ lat: number
53
+ lng: number
54
+ zoom?: number
55
+ height?: string
56
+ width?: string
57
+ markerLat?: number | null
58
+ markerLng?: number | null
59
+ embedSrc?: string | null
60
+ title?: string
61
+ sandbox?: string | null
62
+ }
63
+
64
+ export declare const OsmMap: DefineComponent<OsmMapProps>
65
+ export declare const OsmMapEmbed: DefineComponent<OsmMapEmbedProps>
66
+
67
+ declare const plugin: {
68
+ install(app: unknown): void
69
+ }
70
+
71
+ export default plugin
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "abn-osmvue",
3
+ "version": "0.1.0",
4
+ "description": "Vue 2/Vue 3 component library for OpenStreetMap powered by Leaflet",
5
+ "author": "ABN",
6
+ "license": "MIT",
7
+ "files": ["dist"],
8
+ "main": "./dist/abn-osmvue.cjs",
9
+ "module": "./dist/abn-osmvue.js",
10
+ "types": "./dist/types.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/abn-osmvue.js",
14
+ "require": "./dist/abn-osmvue.cjs"
15
+ },
16
+ "./dist/style.css": "./dist/style.css"
17
+ },
18
+ "scripts": {
19
+ "dev": "vite",
20
+ "build": "vite build && vue-demi-switch 3 && cp src/types.d.ts dist/types.d.ts",
21
+ "build:vue2": "vue-demi-switch 2 && vite build",
22
+ "preview": "vite preview"
23
+ },
24
+ "peerDependencies": {
25
+ "vue": "^2.7.0 || ^3.0.0"
26
+ },
27
+ "dependencies": {
28
+ "leaflet": "^1.9.0",
29
+ "vue-demi": "^0.14.0"
30
+ },
31
+ "devDependencies": {
32
+ "@vitejs/plugin-vue": "^5.0.0",
33
+ "vite": "^5.0.0",
34
+ "vite-plugin-dts": "^3.0.0",
35
+ "vue": "^3.4.0"
36
+ }
37
+ }