vue-geojson-view-ts 1.3.17 → 1.3.18

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.
@@ -1,716 +1,718 @@
1
- <template>
2
- <div class="map-container" :style="`height:${configurationMap?.height}`">
3
- <div :id="idMap" style="height: 100%"></div>
4
- </div>
5
- </template>
6
-
7
- <script lang="ts">
8
- import { defineComponent } from "vue";
9
- import { markerDefault } from "../helpers/imgBase64";
10
- import homeIconUrl from "../assets/home.png";
11
- import endIconUrl from "../assets/end.png";
12
- import trackingIconUrl from "../assets/tracking.png";
13
- import * as L from "leaflet";
14
- import "leaflet-draw";
15
- import "leaflet/dist/leaflet.css";
16
- import "leaflet-draw/dist/leaflet.draw.css";
17
- import drawLocales from "leaflet-draw-locales";
18
- import axios from "axios";
19
- import "leaflet.fullscreen/Control.FullScreen.css";
20
- import "leaflet.fullscreen";
21
- import gpsIcon from "../assets/gps.svg";
22
- import sateliteIcon from "../assets/satelite.svg";
23
-
24
- declare global {
25
- interface Window {
26
- type: boolean;
27
- }
28
- }
29
-
30
- L.Edit.Circle = L.Edit.CircleMarker.extend({
31
- _createResizeMarker: function () {
32
- var center = this._shape.getLatLng(),
33
- resizemarkerPoint = this._getResizeMarkerPoint(center);
34
-
35
- this._resizeMarkers = [];
36
- this._resizeMarkers.push(
37
- this._createMarker(resizemarkerPoint, this.options.resizeIcon)
38
- );
39
- },
40
-
41
- _getResizeMarkerPoint: function (latlng: any) {
42
- var delta = this._shape._radius * Math.cos(Math.PI / 4),
43
- point = this._map.project(latlng);
44
- return this._map.unproject([point.x + delta, point.y - delta]);
45
- },
46
-
47
- _resize: function (latlng: any) {
48
- var moveLatLng = this._moveMarker.getLatLng();
49
- var radius;
50
-
51
- if (L.GeometryUtil.isVersion07x()) {
52
- radius = moveLatLng.distanceTo(latlng);
53
- } else {
54
- radius = this._map.distance(moveLatLng, latlng);
55
- }
56
-
57
- // **** This fixes the cicle resizing ****
58
- this._shape.setRadius(radius);
59
-
60
- this._map.fire(L.Draw.Event.EDITRESIZE, { layer: this._shape });
61
- },
62
- });
63
-
64
- export default defineComponent({
65
- name: "MapView",
66
- props: {
67
- loadPolygon: Boolean,
68
- reverseCoordinatesPolygon: Boolean,
69
- dataPolygon: Object,
70
- configurationMap: Object as any,
71
- coordinatesMap: Array,
72
- getGeoJSON: Function,
73
- getCoodMarker: Function,
74
- isSatelite: Boolean,
75
- },
76
- data() {
77
- return {
78
- idMap: "",
79
- mapRender: null as L.Map | null,
80
- markerRender: null as L.Marker | null,
81
- renderCoordinates: this.coordinatesMap,
82
- renderGeojson: this.dataPolygon as any,
83
- markerIcon: {
84
- iconUrl: markerDefault,
85
- iconSize: [25, 41],
86
- iconAnchor: [12, 41],
87
- },
88
- layersFeatureGroup: null as any,
89
- featuresData: null as any,
90
- currentTileLayer: null as L.TileLayer | null,
91
- isSatelliteView: false,
92
- };
93
- },
94
- mounted() {
95
- this.makeid(10);
96
- this.renderMap();
97
- },
98
- methods: {
99
- createSatelliteControl(): L.Control {
100
- const SatelliteControl = L.Control.extend({
101
- onAdd: (map: L.Map) => {
102
- const container = L.DomUtil.create(
103
- "div",
104
- "leaflet-control-draw leaflet-bar leaflet-control"
105
- );
106
-
107
- const satelliteButton = L.DomUtil.create(
108
- "a",
109
- "leaflet-draw-draw-satellite",
110
- container
111
- );
112
-
113
- satelliteButton.href = "#";
114
- satelliteButton.title = this.isSatelliteView
115
- ? "Vista Normal"
116
- : "Vista Satélite";
117
-
118
- // Usar el mismo estilo que los otros botones de draw
119
- satelliteButton.style.backgroundImage = this.isSatelliteView
120
- ? `url(${gpsIcon})`
121
- : `url(${sateliteIcon})`;
122
- satelliteButton.style.backgroundPosition = "center";
123
- satelliteButton.style.backgroundRepeat = "no-repeat";
124
- satelliteButton.style.backgroundSize = "20px 20px";
125
-
126
- L.DomEvent.disableClickPropagation(satelliteButton);
127
- L.DomEvent.on(
128
- satelliteButton,
129
- "click",
130
- this.toggleSatelliteView,
131
- this
132
- );
133
-
134
- return container;
135
- },
136
- });
137
-
138
- return new SatelliteControl({ position: "topleft" });
139
- },
140
- toggleSatelliteView(): void {
141
- if (!this.mapRender || !this.currentTileLayer) return;
142
-
143
- this.isSatelliteView = !this.isSatelliteView;
144
-
145
- // Remover la capa actual
146
- this.mapRender.removeLayer(this.currentTileLayer as unknown as L.Layer);
147
-
148
- // Agregar la nueva capa
149
- if (this.isSatelliteView) {
150
- this.currentTileLayer = L.tileLayer(
151
- "https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=t8mWT2ozs1JWBqMZOnZr",
152
- {
153
- attribution:
154
- '&copy; <a href="https://www.maptiler.com/">MapTiler</a> &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
155
- }
156
- );
157
- } else {
158
- this.currentTileLayer = L.tileLayer(
159
- "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
160
- {
161
- attribution:
162
- '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
163
- }
164
- );
165
- }
166
-
167
- this.currentTileLayer.addTo(this.mapRender as L.Map);
168
-
169
- // Actualizar el ícono del control satelital
170
- const satelliteButtons = document.querySelectorAll(
171
- ".leaflet-draw-draw-satellite"
172
- );
173
- satelliteButtons.forEach((button) => {
174
- const htmlButton = button as HTMLElement;
175
- htmlButton.style.backgroundImage = this.isSatelliteView
176
- ? `url(${gpsIcon})`
177
- : `url(${sateliteIcon})`;
178
- htmlButton.title = this.isSatelliteView
179
- ? "Vista Normal"
180
- : "Vista Satélite";
181
- });
182
- },
183
- getLayersFeaturesInGeoJson() {
184
- const geojson = L.geoJSON().addTo(this.mapRender as any);
185
- this.featuresData.eachLayer((layer: any) => {
186
- geojson.addLayer(layer);
187
- });
188
- const geojsonString = [geojson.toGeoJSON()]; //JSON.stringify([geojson.toGeoJSON()]);
189
- return geojsonString;
190
- },
191
- triggerSaveEdit(): void {
192
- const buttons =
193
- document.getElementsByClassName(
194
- "leaflet-draw-actions leaflet-draw-actions-top"
195
- ) ||
196
- document.getElementsByClassName(
197
- "leaflet-draw-actions leaflet-draw-actions-top leaflet-draw-actions-bottom"
198
- );
199
- buttons[0]?.querySelector("li")?.querySelector("a")?.click();
200
- },
201
- makeid(length: number): void {
202
- let result = "";
203
- const characters = "abcdefghijklmnopqrstuvwxyz";
204
- const charactersLength = characters.length;
205
- let counter = 0;
206
- while (counter < length) {
207
- result += characters.charAt(
208
- Math.floor(Math.random() * charactersLength)
209
- );
210
- counter += 1;
211
- }
212
- this.idMap = result;
213
- },
214
- renderMap(): void {
215
- drawLocales("es");
216
- setTimeout(() => {
217
- if (this.loadPolygon) {
218
- this.viewMap();
219
- } else {
220
- this.createMap();
221
- }
222
- }, 500);
223
- },
224
- createMap(): void {
225
- const iconDefaultMarket = this.configurationMap
226
- ? this.configurationMap.iconMarker
227
- ? this.configurationMap.iconMarker
228
- : this.markerIcon
229
- : this.markerIcon;
230
- window.type = true;
231
- const map = L.map(this.idMap, { fullscreenControl: true } as any).setView(
232
- [
233
- this.renderCoordinates ? (this.renderCoordinates[0] as number) : 0,
234
- this.renderCoordinates ? (this.renderCoordinates[1] as number) : 0,
235
- ],
236
- this.renderCoordinates ? (this.renderCoordinates[2] as number) : 0
237
- );
238
- this.mapRender = map;
239
-
240
- // Inicializar con la vista correcta según el prop
241
- this.isSatelliteView = this.isSatelite || false;
242
- if (this.isSatelliteView) {
243
- this.currentTileLayer = L.tileLayer(
244
- "https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=t8mWT2ozs1JWBqMZOnZr",
245
- {
246
- attribution:
247
- '&copy; <a href="https://www.maptiler.com/">MapTiler</a> &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
248
- }
249
- );
250
- } else {
251
- this.currentTileLayer = L.tileLayer(
252
- "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
253
- {
254
- attribution:
255
- '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
256
- }
257
- );
258
- }
259
- this.currentTileLayer.addTo(map);
260
-
261
- // Agregar el control satelital si está habilitado
262
- if (this.isSatelite !== undefined) {
263
- const satelliteControl = this.createSatelliteControl();
264
- map.addControl(satelliteControl);
265
- }
266
-
267
- map.setZoom(this.configurationMap?.maxZoom);
268
- if (this.configurationMap.renderMarker) {
269
- const marker = L.marker(
270
- [
271
- this.renderCoordinates ? (this.renderCoordinates[0] as number) : 0,
272
- this.renderCoordinates ? (this.renderCoordinates[1] as number) : 0,
273
- ],
274
- {
275
- icon: L.icon(iconDefaultMarket),
276
- draggable: this.configurationMap.dragMarker,
277
- }
278
- ).addTo(map);
279
- this.markerRender = marker;
280
- if (this.getCoodMarker) {
281
- marker.on("dragend", (event) => {
282
- const updatedCoordinates = event.target.getLatLng();
283
- const lat = updatedCoordinates.lat;
284
- const lng = updatedCoordinates.lng;
285
- if (this.getCoodMarker) this.getCoodMarker(lat, lng);
286
- });
287
- }
288
- }
289
- const featuresData = L.featureGroup();
290
- this.featuresData = featuresData;
291
- const featureGroup = featuresData.addTo(map);
292
- let contextEdit = {
293
- featureGroup: featureGroup, // Crea un nuevo grupo de capas para los polígonos
294
- edit: false,
295
- remove: this.configurationMap?.editFigures.remove,
296
- };
297
- if (this.configurationMap?.editFigures.edit) {
298
- contextEdit = {
299
- featureGroup: featureGroup, // Crea un nuevo grupo de capas para los polígonos
300
- ...this.configurationMap?.editFigures.edit,
301
- remove: this.configurationMap?.editFigures.remove,
302
- };
303
- }
304
- const drawControl = new L.Control.Draw({
305
- position: "topleft",
306
- draw: {
307
- polygon: this.configurationMap?.createFigures.polygon,
308
- circle: false, //this.configurationMap?.createFigures.circle,
309
- rectangle: this.configurationMap?.createFigures.rectangle
310
- ? {
311
- shapeOptions: {
312
- color: "blue",
313
- },
314
- }
315
- : false,
316
- marker: this.configurationMap?.createFigures.marker
317
- ? {
318
- icon: L.icon(iconDefaultMarket),
319
- }
320
- : false,
321
- polyline: this.configurationMap?.createFigures.polyline
322
- ? {
323
- shapeOptions: {
324
- color: "blue",
325
- },
326
- }
327
- : false,
328
- circlemarker: this.configurationMap?.createFigures.multipoint,
329
- },
330
- edit: contextEdit as any,
331
- });
332
- map.addControl(drawControl);
333
-
334
- map.on("draw:created", (event: any) => {
335
- const layer = event.layer;
336
- featureGroup.addLayer(layer);
337
- let geojson = layer.toGeoJSON();
338
- // *** AGREGADO: Manejo especial para CircleMarker (convertir a MultiPoint) ***
339
- if (event.layerType === "circlemarker") {
340
- // Convertir CircleMarker a formato MultiPoint para consistencia
341
- geojson = {
342
- type: "Feature",
343
- geometry: {
344
- type: "MultiPoint",
345
- coordinates: [geojson.geometry.coordinates],
346
- },
347
- properties: {
348
- ...geojson.properties,
349
- pointType: "multipoint",
350
- style: {
351
- color:
352
- this.configurationMap?.createFigures?.multipoint?.color ||
353
- "green",
354
- fillColor:
355
- this.configurationMap?.createFigures?.multipoint?.fillColor ||
356
- "green",
357
- fillOpacity:
358
- this.configurationMap?.createFigures?.multipoint
359
- ?.fillOpacity || 0.8,
360
- radius:
361
- this.configurationMap?.createFigures?.multipoint?.radius || 6,
362
- weight:
363
- this.configurationMap?.createFigures?.multipoint?.weight || 2,
364
- },
365
- },
366
- };
367
- }
368
- if (this.getGeoJSON) this.getGeoJSON([geojson]);
369
- });
370
-
371
- map.on("draw:edited", (event: any) => {
372
- const layers = event.layers;
373
- layers.eachLayer((layer: any) => {
374
- const geojson = layer.toGeoJSON();
375
- if (this.getGeoJSON) this.getGeoJSON([geojson]);
376
- });
377
- });
378
- },
379
- viewMap(): void {
380
- const iconDefaultMarket = this.configurationMap
381
- ? this.configurationMap.iconMarker
382
- ? this.configurationMap.iconMarker
383
- : this.markerIcon
384
- : this.markerIcon;
385
- window.type = true;
386
- const map = L.map(this.idMap, { fullscreenControl: true } as any).setView(
387
- [
388
- this.renderCoordinates ? (this.renderCoordinates[0] as number) : 0,
389
- this.renderCoordinates ? (this.renderCoordinates[1] as number) : 0,
390
- ],
391
- this.renderCoordinates ? (this.renderCoordinates[2] as number) : 0
392
- );
393
- this.mapRender = map;
394
-
395
- // Inicializar con la vista correcta según el prop
396
- this.isSatelliteView = this.isSatelite || false;
397
- if (this.isSatelliteView) {
398
- this.currentTileLayer = L.tileLayer(
399
- "https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=t8mWT2ozs1JWBqMZOnZr",
400
- {
401
- attribution:
402
- '&copy; <a href="https://www.maptiler.com/">MapTiler</a> &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
403
- }
404
- );
405
- } else {
406
- this.currentTileLayer = L.tileLayer(
407
- "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
408
- {
409
- attribution:
410
- '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
411
- }
412
- );
413
- }
414
- this.currentTileLayer.addTo(map);
415
-
416
- // Agregar el control satelital si está habilitado
417
- if (this.isSatelite !== undefined) {
418
- const satelliteControl = this.createSatelliteControl();
419
- map.addControl(satelliteControl);
420
- }
421
-
422
- map.setZoom(this.configurationMap?.maxZoom);
423
- const featuresData = L.featureGroup();
424
- this.featuresData = featuresData;
425
- const featureGroup = featuresData.addTo(map);
426
- let contextEdit = {
427
- featureGroup: featureGroup, // Crea un nuevo grupo de capas para los polígonos
428
- edit: false,
429
- remove: this.configurationMap?.editFigures.remove,
430
- };
431
- if (this.configurationMap?.editFigures.edit) {
432
- contextEdit = {
433
- featureGroup: featureGroup, // Crea un nuevo grupo de capas para los polígonos
434
- ...this.configurationMap?.editFigures.edit,
435
- remove: this.configurationMap?.editFigures.remove,
436
- };
437
- }
438
-
439
- const renderGeojson = this.renderGeojson;
440
- if (renderGeojson && renderGeojson.length) {
441
- renderGeojson.forEach((item: any) => {
442
- if (item.type === "FeatureCollection") {
443
- item.features.forEach((feature: any) => {
444
- if (
445
- feature.geometry.type === "Polygon" ||
446
- feature.geometry.type === "MultiPolygon" ||
447
- feature.geometry.type === "LineString" ||
448
- feature.geometry.type === "MultiLineString" ||
449
- feature.geometry.type === "Point"
450
- ) {
451
- const self = this;
452
- L.geoJson(feature, {
453
- pointToLayer: this.getPointToLayer.bind(this),
454
- onEachFeature: function (feature, layer) {
455
- featureGroup.addLayer(layer);
456
- // Mostrar popup para Point
457
- if (feature.geometry.type === "Point") {
458
- var popupContent = self.getPopupContent(feature);
459
- layer.bindPopup(popupContent);
460
- }
461
- // Mostrar popup para Polygon y MultiPolygon al hacer clic
462
- else if (
463
- feature.geometry.type === "Polygon" ||
464
- feature.geometry.type === "MultiPolygon"
465
- ) {
466
- var tooltipContent =
467
- self.getPolygonTooltipContent(feature);
468
- layer.bindPopup(tooltipContent);
469
- }
470
- },
471
- });
472
- }
473
- });
474
- } else if (item.type === "Feature") {
475
- if (
476
- item.geometry.type === "Polygon" ||
477
- item.geometry.type === "MultiPolygon" ||
478
- item.geometry.type === "LineString" ||
479
- item.geometry.type === "MultiLineString" ||
480
- item.geometry.type === "Point" ||
481
- item.geometry.type === "MultiPoint"
482
- ) {
483
- const self = this;
484
- L.geoJson(item, {
485
- onEachFeature: function (feature, layer) {
486
- featureGroup.addLayer(layer);
487
- // Mostrar popup para Point
488
- if (feature.geometry.type === "Point") {
489
- var popupContent = self.getPopupContent(feature);
490
- layer.bindPopup(popupContent);
491
- }
492
- // Mostrar popup para Polygon y MultiPolygon al hacer clic
493
- else if (
494
- feature.geometry.type === "Polygon" ||
495
- feature.geometry.type === "MultiPolygon"
496
- ) {
497
- var tooltipContent = self.getPolygonTooltipContent(feature);
498
- layer.bindPopup(tooltipContent);
499
- }
500
- },
501
- });
502
- }
503
- }
504
- });
505
- const bounds = featureGroup.getBounds();
506
- map.fitBounds(bounds);
507
- }
508
- const drawControl = new L.Control.Draw({
509
- position: "topleft",
510
- draw: {
511
- polygon: this.configurationMap?.createFigures.polygon,
512
- circle: false, //this.configurationMap?.createFigures.circle,
513
- rectangle: this.configurationMap?.createFigures.rectangle
514
- ? {
515
- shapeOptions: {
516
- color: "blue",
517
- },
518
- }
519
- : false,
520
- marker: this.configurationMap?.createFigures.marker
521
- ? {
522
- icon: L.icon(iconDefaultMarket),
523
- }
524
- : false,
525
- polyline: this.configurationMap?.createFigures.polyline
526
- ? {
527
- shapeOptions: {
528
- color: "blue",
529
- },
530
- }
531
- : false,
532
- circlemarker: this.configurationMap?.createFigures.multipoint,
533
- },
534
- edit: contextEdit as any,
535
- });
536
- map.addControl(drawControl);
537
-
538
- map.on("draw:created", (event: any) => {
539
- const layer = event.layer;
540
- featureGroup.addLayer(layer);
541
- let geojson = layer.toGeoJSON();
542
- // *** AGREGADO: Manejo especial para CircleMarker (convertir a MultiPoint) ***
543
- if (event.layerType === "circlemarker") {
544
- // Convertir CircleMarker a formato MultiPoint para consistencia
545
- geojson = {
546
- type: "Feature",
547
- geometry: {
548
- type: "MultiPoint",
549
- coordinates: [geojson.geometry.coordinates],
550
- },
551
- properties: {
552
- ...geojson.properties,
553
- pointType: "multipoint",
554
- style: {
555
- color:
556
- this.configurationMap?.createFigures?.multipoint?.color ||
557
- "green",
558
- fillColor:
559
- this.configurationMap?.createFigures?.multipoint?.fillColor ||
560
- "green",
561
- fillOpacity:
562
- this.configurationMap?.createFigures?.multipoint
563
- ?.fillOpacity || 0.8,
564
- radius:
565
- this.configurationMap?.createFigures?.multipoint?.radius || 6,
566
- weight:
567
- this.configurationMap?.createFigures?.multipoint?.weight || 2,
568
- },
569
- },
570
- };
571
- }
572
- if (this.getGeoJSON) this.getGeoJSON(geojson);
573
- });
574
-
575
- map.on("draw:edited", (event: any) => {
576
- const layers = event.layers;
577
- layers.eachLayer((layer: any) => {
578
- const geojson = layer.toGeoJSON();
579
- if (this.getGeoJSON) this.getGeoJSON(geojson);
580
- });
581
- });
582
- },
583
- getPointToLayer(feature: any, latlng: any) {
584
- const geometryType = feature.geometry?.type;
585
-
586
- // Point: icono según properties.tipo
587
- if (geometryType === "Point") {
588
- const tipo = feature.properties?.tipo;
589
- const firstIcon = L.icon({
590
- iconUrl: homeIconUrl,
591
- iconSize: [38, 38],
592
- iconAnchor: [16, 41],
593
- });
594
- const lastIcon = L.icon({
595
- iconUrl: endIconUrl,
596
- iconSize: [38, 38],
597
- iconAnchor: [16, 41],
598
- });
599
- const pointerIcon = L.icon({
600
- iconUrl: trackingIconUrl,
601
- iconSize: [38, 38],
602
- iconAnchor: [16, 41],
603
- });
604
-
605
- let icon = pointerIcon;
606
- if (tipo === 0) icon = firstIcon;
607
- else if (tipo === 1) icon = lastIcon;
608
-
609
- return L.marker(latlng, { icon });
610
- }
611
-
612
- // Otros tipos: icono por defecto
613
- return L.marker(latlng);
614
- },
615
- async searchAddress(query: string) {
616
- const address = await axios.get(
617
- location.protocol + "//nominatim.openstreetmap.org/search?",
618
- {
619
- params: {
620
- //query
621
- q: query,
622
- limit: 1,
623
- format: "json",
624
- },
625
- }
626
- );
627
- if (address.data.length === 1) {
628
- const lat = parseFloat(address.data[0].lat);
629
- const lng = parseFloat(address.data[0].lon);
630
- const coord = { lng, lat };
631
- this.setCoordinates({ ...coord, moveMarker: true });
632
- return address.data[0];
633
- }
634
- return address.data;
635
- },
636
- setCoordinates({
637
- lat,
638
- lng,
639
- }: {
640
- lat: number;
641
- lng: number;
642
- moveMarker?: boolean;
643
- }): void {
644
- if (this.mapRender) {
645
- const newCenter = L.latLng(lat, lng);
646
- this.mapRender.panTo(newCenter, { animate: true, duration: 0.5 });
647
- }
648
- },
649
- getPopupContent(feature: any): string {
650
- // Puedes personalizar el contenido del popup aquí
651
- const props = feature.properties || {};
652
- // Solo toma en cuenta descripcion y fechaHoraLlegada
653
- const descripcion = props.descripcion || "";
654
- const fechaHoraLlegada = props.fechaHoraLlegada || "";
655
- // url de la foto
656
- const fotoId = props.fotoId || "";
657
-
658
- const formatIsoPreserve = (iso: string): string => {
659
- const d = new Date(iso);
660
- if (isNaN(d.getTime())) return iso; // fallback: devolver la cadena original si no es válida
661
- const pad = (n: number) => n.toString().padStart(2, "0");
662
- // Usar métodos UTC para evitar que el navegador convierta a la zona local
663
- const day = pad(d.getUTCDate());
664
- const month = pad(d.getUTCMonth() + 1);
665
- const year = d.getUTCFullYear();
666
- const hours = pad(d.getUTCHours());
667
- const minutes = pad(d.getUTCMinutes());
668
- const seconds = pad(d.getUTCSeconds());
669
- return `${day}-${month}-${year} ${hours}:${minutes}:${seconds}`;
670
- };
671
-
672
- // Formatear fecha a dd-MM-yyyy hh:mm:ss
673
- let fechaFormateada = "";
674
- if (fechaHoraLlegada) {
675
- /* const fecha = new Date(fechaHoraLlegada);
676
- const pad = (n: number) => n.toString().padStart(2, "0");
677
- fechaFormateada = `${pad(fecha.getDate())}-${pad(
678
- fecha.getMonth() + 1
679
- )}-${fecha.getFullYear()} ${pad(fecha.getHours())}:${pad(
680
- fecha.getMinutes()
681
- )}:${pad(fecha.getSeconds())}`; */
682
- fechaFormateada = formatIsoPreserve(fechaHoraLlegada);
683
- }
684
- let html = "<div>";
685
- if (fotoId) {
686
- html += `<img src="${fotoId}" style="width: 200px; height: auto; margin-bottom: 5px;"><br>`;
687
- }
688
- html += `<b>Descripción:</b> ${descripcion}<br>`;
689
- if (fechaFormateada) {
690
- html += `<b>Fecha Hora Llegada:</b> ${fechaFormateada}<br>`;
691
- }
692
- html += "</div>";
693
- return html;
694
- },
695
- getPolygonTooltipContent(feature: any): string {
696
- const props = feature.properties || {};
697
- const descripcion = props.descripcion || props.name || "Sin descripción";
698
-
699
- return `<div style="font-weight: bold; padding: 5px;">${descripcion}</div>`;
700
- },
701
- },
702
- watch: {
703
- coordinatesMap(newVal) {
704
- this.renderCoordinates = newVal;
705
- if (this.mapRender && this.markerRender) {
706
- const newLatLng = L.latLng([newVal[0], newVal[1]]);
707
- this.mapRender.setView([newVal[0], newVal[1]], newVal[2]);
708
- this.markerRender.setLatLng(newLatLng);
709
- }
710
- },
711
- dataPolygon(newVal) {
712
- this.renderGeojson = newVal;
713
- },
714
- },
715
- });
716
- </script>
1
+ <template>
2
+ <div class="map-container" :style="`height:${configurationMap?.height}`">
3
+ <div :id="idMap" style="height: 100%"></div>
4
+ </div>
5
+ </template>
6
+
7
+ <script lang="ts">
8
+ import { defineComponent } from "vue";
9
+ import { markerDefault } from "../helpers/imgBase64";
10
+ import homeIconUrl from "../assets/home.png";
11
+ import endIconUrl from "../assets/end.png";
12
+ import trackingIconUrl from "../assets/tracking.png";
13
+ import * as L from "leaflet";
14
+ import "leaflet-draw";
15
+ import "leaflet/dist/leaflet.css";
16
+ import "leaflet-draw/dist/leaflet.draw.css";
17
+ import drawLocales from "leaflet-draw-locales";
18
+ import axios from "axios";
19
+ import "leaflet.fullscreen/Control.FullScreen.css";
20
+ import "leaflet.fullscreen";
21
+ import gpsIcon from "../assets/gps.svg";
22
+ import sateliteIcon from "../assets/satelite.svg";
23
+
24
+ declare global {
25
+ interface Window {
26
+ type: boolean;
27
+ }
28
+ }
29
+
30
+ L.Edit.Circle = L.Edit.CircleMarker.extend({
31
+ _createResizeMarker: function () {
32
+ var center = this._shape.getLatLng(),
33
+ resizemarkerPoint = this._getResizeMarkerPoint(center);
34
+
35
+ this._resizeMarkers = [];
36
+ this._resizeMarkers.push(
37
+ this._createMarker(resizemarkerPoint, this.options.resizeIcon)
38
+ );
39
+ },
40
+
41
+ _getResizeMarkerPoint: function (latlng: any) {
42
+ var delta = this._shape._radius * Math.cos(Math.PI / 4),
43
+ point = this._map.project(latlng);
44
+ return this._map.unproject([point.x + delta, point.y - delta]);
45
+ },
46
+
47
+ _resize: function (latlng: any) {
48
+ var moveLatLng = this._moveMarker.getLatLng();
49
+ var radius;
50
+
51
+ if (L.GeometryUtil.isVersion07x()) {
52
+ radius = moveLatLng.distanceTo(latlng);
53
+ } else {
54
+ radius = this._map.distance(moveLatLng, latlng);
55
+ }
56
+
57
+ // **** This fixes the cicle resizing ****
58
+ this._shape.setRadius(radius);
59
+
60
+ this._map.fire(L.Draw.Event.EDITRESIZE, { layer: this._shape });
61
+ },
62
+ });
63
+
64
+ export default defineComponent({
65
+ name: "MapView",
66
+ props: {
67
+ loadPolygon: Boolean,
68
+ reverseCoordinatesPolygon: Boolean,
69
+ dataPolygon: Object,
70
+ configurationMap: Object as any,
71
+ coordinatesMap: Array,
72
+ getGeoJSON: Function,
73
+ getCoodMarker: Function,
74
+ isSatelite: Boolean,
75
+ },
76
+ data() {
77
+ return {
78
+ idMap: "",
79
+ mapRender: null as L.Map | null,
80
+ markerRender: null as L.Marker | null,
81
+ renderCoordinates: this.coordinatesMap,
82
+ renderGeojson: this.dataPolygon as any,
83
+ markerIcon: {
84
+ iconUrl: markerDefault,
85
+ iconSize: [25, 41],
86
+ iconAnchor: [12, 41],
87
+ },
88
+ layersFeatureGroup: null as any,
89
+ featuresData: null as any,
90
+ currentTileLayer: null as L.TileLayer | null,
91
+ isSatelliteView: false,
92
+ };
93
+ },
94
+ mounted() {
95
+ this.makeid(10);
96
+ this.renderMap();
97
+ },
98
+ methods: {
99
+ createSatelliteControl(): L.Control {
100
+ const SatelliteControl = L.Control.extend({
101
+ onAdd: (map: L.Map) => {
102
+ const container = L.DomUtil.create(
103
+ "div",
104
+ "leaflet-control-draw leaflet-bar leaflet-control"
105
+ );
106
+
107
+ const satelliteButton = L.DomUtil.create(
108
+ "a",
109
+ "leaflet-draw-draw-satellite",
110
+ container
111
+ );
112
+
113
+ satelliteButton.href = "#";
114
+ satelliteButton.title = this.isSatelliteView
115
+ ? "Vista Normal"
116
+ : "Vista Satélite";
117
+
118
+ // Usar el mismo estilo que los otros botones de draw
119
+ satelliteButton.style.backgroundImage = this.isSatelliteView
120
+ ? `url(${gpsIcon})`
121
+ : `url(${sateliteIcon})`;
122
+ satelliteButton.style.backgroundPosition = "center";
123
+ satelliteButton.style.backgroundRepeat = "no-repeat";
124
+ satelliteButton.style.backgroundSize = "20px 20px";
125
+
126
+ L.DomEvent.disableClickPropagation(satelliteButton);
127
+ L.DomEvent.on(
128
+ satelliteButton,
129
+ "click",
130
+ this.toggleSatelliteView,
131
+ this
132
+ );
133
+
134
+ return container;
135
+ },
136
+ });
137
+
138
+ return new SatelliteControl({ position: "topleft" });
139
+ },
140
+ toggleSatelliteView(): void {
141
+ if (!this.mapRender || !this.currentTileLayer) return;
142
+
143
+ this.isSatelliteView = !this.isSatelliteView;
144
+
145
+ // Remover la capa actual
146
+ this.mapRender.removeLayer(this.currentTileLayer as unknown as L.Layer);
147
+
148
+ // Agregar la nueva capa
149
+ if (this.isSatelliteView) {
150
+ this.currentTileLayer = L.tileLayer(
151
+ "https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=t8mWT2ozs1JWBqMZOnZr",
152
+ {
153
+ attribution:
154
+ '&copy; <a href="https://www.maptiler.com/">MapTiler</a> &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
155
+ }
156
+ );
157
+ } else {
158
+ this.currentTileLayer = L.tileLayer(
159
+ "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
160
+ {
161
+ attribution:
162
+ '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
163
+ }
164
+ );
165
+ }
166
+
167
+ this.currentTileLayer.addTo(this.mapRender as L.Map);
168
+
169
+ // Actualizar el ícono del control satelital
170
+ const satelliteButtons = document.querySelectorAll(
171
+ ".leaflet-draw-draw-satellite"
172
+ );
173
+ satelliteButtons.forEach((button) => {
174
+ const htmlButton = button as HTMLElement;
175
+ htmlButton.style.backgroundImage = this.isSatelliteView
176
+ ? `url(${gpsIcon})`
177
+ : `url(${sateliteIcon})`;
178
+ htmlButton.title = this.isSatelliteView
179
+ ? "Vista Normal"
180
+ : "Vista Satélite";
181
+ });
182
+ },
183
+ getLayersFeaturesInGeoJson() {
184
+ const geojson = L.geoJSON().addTo(this.mapRender as any);
185
+ this.featuresData.eachLayer((layer: any) => {
186
+ geojson.addLayer(layer);
187
+ });
188
+ const geojsonString = [geojson.toGeoJSON()]; //JSON.stringify([geojson.toGeoJSON()]);
189
+ return geojsonString;
190
+ },
191
+ triggerSaveEdit(): void {
192
+ const buttons =
193
+ document.getElementsByClassName(
194
+ "leaflet-draw-actions leaflet-draw-actions-top"
195
+ ) ||
196
+ document.getElementsByClassName(
197
+ "leaflet-draw-actions leaflet-draw-actions-top leaflet-draw-actions-bottom"
198
+ );
199
+ buttons[0]?.querySelector("li")?.querySelector("a")?.click();
200
+ },
201
+ makeid(length: number): void {
202
+ let result = "";
203
+ const characters = "abcdefghijklmnopqrstuvwxyz";
204
+ const charactersLength = characters.length;
205
+ let counter = 0;
206
+ while (counter < length) {
207
+ result += characters.charAt(
208
+ Math.floor(Math.random() * charactersLength)
209
+ );
210
+ counter += 1;
211
+ }
212
+ this.idMap = result;
213
+ },
214
+ renderMap(): void {
215
+ drawLocales("es");
216
+ setTimeout(() => {
217
+ if (this.loadPolygon) {
218
+ this.viewMap();
219
+ } else {
220
+ this.createMap();
221
+ }
222
+ }, 500);
223
+ },
224
+ createMap(): void {
225
+ const iconDefaultMarket = this.configurationMap
226
+ ? this.configurationMap.iconMarker
227
+ ? this.configurationMap.iconMarker
228
+ : this.markerIcon
229
+ : this.markerIcon;
230
+ window.type = true;
231
+ const map = L.map(this.idMap, { fullscreenControl: true } as any).setView(
232
+ [
233
+ this.renderCoordinates ? (this.renderCoordinates[0] as number) : 0,
234
+ this.renderCoordinates ? (this.renderCoordinates[1] as number) : 0,
235
+ ],
236
+ this.renderCoordinates ? (this.renderCoordinates[2] as number) : 0
237
+ );
238
+ this.mapRender = map;
239
+
240
+ // Inicializar con la vista correcta según el prop
241
+ this.isSatelliteView = this.isSatelite || false;
242
+ if (this.isSatelliteView) {
243
+ this.currentTileLayer = L.tileLayer(
244
+ "https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=t8mWT2ozs1JWBqMZOnZr",
245
+ {
246
+ attribution:
247
+ '&copy; <a href="https://www.maptiler.com/">MapTiler</a> &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
248
+ }
249
+ );
250
+ } else {
251
+ this.currentTileLayer = L.tileLayer(
252
+ "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
253
+ {
254
+ attribution:
255
+ '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
256
+ }
257
+ );
258
+ }
259
+ this.currentTileLayer.addTo(map);
260
+
261
+ // Agregar el control satelital si está habilitado
262
+ if (this.isSatelite !== undefined) {
263
+ const satelliteControl = this.createSatelliteControl();
264
+ map.addControl(satelliteControl);
265
+ }
266
+
267
+ map.setZoom(this.configurationMap?.maxZoom);
268
+ if (this.configurationMap.renderMarker) {
269
+ const marker = L.marker(
270
+ [
271
+ this.renderCoordinates ? (this.renderCoordinates[0] as number) : 0,
272
+ this.renderCoordinates ? (this.renderCoordinates[1] as number) : 0,
273
+ ],
274
+ {
275
+ icon: L.icon(iconDefaultMarket),
276
+ draggable: this.configurationMap.dragMarker,
277
+ }
278
+ ).addTo(map);
279
+ this.markerRender = marker;
280
+ if (this.getCoodMarker) {
281
+ marker.on("dragend", (event) => {
282
+ const updatedCoordinates = event.target.getLatLng();
283
+ const lat = updatedCoordinates.lat;
284
+ const lng = updatedCoordinates.lng;
285
+ if (this.getCoodMarker) this.getCoodMarker(lat, lng);
286
+ });
287
+ }
288
+ }
289
+ const featuresData = L.featureGroup();
290
+ this.featuresData = featuresData;
291
+ const featureGroup = featuresData.addTo(map);
292
+ let contextEdit = {
293
+ featureGroup: featureGroup, // Crea un nuevo grupo de capas para los polígonos
294
+ edit: false,
295
+ remove: this.configurationMap?.editFigures.remove,
296
+ };
297
+ if (this.configurationMap?.editFigures.edit) {
298
+ contextEdit = {
299
+ featureGroup: featureGroup, // Crea un nuevo grupo de capas para los polígonos
300
+ ...this.configurationMap?.editFigures.edit,
301
+ remove: this.configurationMap?.editFigures.remove,
302
+ };
303
+ }
304
+ const drawControl = new L.Control.Draw({
305
+ position: "topleft",
306
+ draw: {
307
+ polygon: this.configurationMap?.createFigures.polygon,
308
+ circle: false, //this.configurationMap?.createFigures.circle,
309
+ rectangle: this.configurationMap?.createFigures.rectangle
310
+ ? {
311
+ shapeOptions: {
312
+ color: "blue",
313
+ },
314
+ }
315
+ : false,
316
+ marker: this.configurationMap?.createFigures.marker
317
+ ? {
318
+ icon: L.icon(iconDefaultMarket),
319
+ }
320
+ : false,
321
+ polyline: this.configurationMap?.createFigures.polyline
322
+ ? {
323
+ shapeOptions: {
324
+ color: "blue",
325
+ },
326
+ }
327
+ : false,
328
+ circlemarker: this.configurationMap?.createFigures.multipoint,
329
+ },
330
+ edit: contextEdit as any,
331
+ });
332
+ map.addControl(drawControl);
333
+
334
+ map.on("draw:created", (event: any) => {
335
+ const layer = event.layer;
336
+ featureGroup.addLayer(layer);
337
+ let geojson = layer.toGeoJSON();
338
+ // *** AGREGADO: Manejo especial para CircleMarker (convertir a MultiPoint) ***
339
+ if (event.layerType === "circlemarker") {
340
+ // Convertir CircleMarker a formato MultiPoint para consistencia
341
+ geojson = {
342
+ type: "Feature",
343
+ geometry: {
344
+ type: "MultiPoint",
345
+ coordinates: [geojson.geometry.coordinates],
346
+ },
347
+ properties: {
348
+ ...geojson.properties,
349
+ pointType: "multipoint",
350
+ style: {
351
+ color:
352
+ this.configurationMap?.createFigures?.multipoint?.color ||
353
+ "green",
354
+ fillColor:
355
+ this.configurationMap?.createFigures?.multipoint?.fillColor ||
356
+ "green",
357
+ fillOpacity:
358
+ this.configurationMap?.createFigures?.multipoint
359
+ ?.fillOpacity || 0.8,
360
+ radius:
361
+ this.configurationMap?.createFigures?.multipoint?.radius || 6,
362
+ weight:
363
+ this.configurationMap?.createFigures?.multipoint?.weight || 2,
364
+ },
365
+ },
366
+ };
367
+ }
368
+ if (this.getGeoJSON) this.getGeoJSON([geojson]);
369
+ });
370
+
371
+ map.on("draw:edited", (event: any) => {
372
+ const layers = event.layers;
373
+ layers.eachLayer((layer: any) => {
374
+ const geojson = layer.toGeoJSON();
375
+ if (this.getGeoJSON) this.getGeoJSON([geojson]);
376
+ });
377
+ });
378
+ },
379
+ viewMap(): void {
380
+ const iconDefaultMarket = this.configurationMap
381
+ ? this.configurationMap.iconMarker
382
+ ? this.configurationMap.iconMarker
383
+ : this.markerIcon
384
+ : this.markerIcon;
385
+ window.type = true;
386
+ const map = L.map(this.idMap, { fullscreenControl: true } as any).setView(
387
+ [
388
+ this.renderCoordinates ? (this.renderCoordinates[0] as number) : 0,
389
+ this.renderCoordinates ? (this.renderCoordinates[1] as number) : 0,
390
+ ],
391
+ this.renderCoordinates ? (this.renderCoordinates[2] as number) : 0
392
+ );
393
+ this.mapRender = map;
394
+
395
+ // Inicializar con la vista correcta según el prop
396
+ this.isSatelliteView = this.isSatelite || false;
397
+ if (this.isSatelliteView) {
398
+ this.currentTileLayer = L.tileLayer(
399
+ "https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=t8mWT2ozs1JWBqMZOnZr",
400
+ {
401
+ attribution:
402
+ '&copy; <a href="https://www.maptiler.com/">MapTiler</a> &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
403
+ }
404
+ );
405
+ } else {
406
+ this.currentTileLayer = L.tileLayer(
407
+ "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
408
+ {
409
+ attribution:
410
+ '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
411
+ }
412
+ );
413
+ }
414
+ this.currentTileLayer.addTo(map);
415
+
416
+ // Agregar el control satelital si está habilitado
417
+ if (this.isSatelite !== undefined) {
418
+ const satelliteControl = this.createSatelliteControl();
419
+ map.addControl(satelliteControl);
420
+ }
421
+
422
+ map.setZoom(this.configurationMap?.maxZoom);
423
+ const featuresData = L.featureGroup();
424
+ this.featuresData = featuresData;
425
+ const featureGroup = featuresData.addTo(map);
426
+ let contextEdit = {
427
+ featureGroup: featureGroup, // Crea un nuevo grupo de capas para los polígonos
428
+ edit: false,
429
+ remove: this.configurationMap?.editFigures.remove,
430
+ };
431
+ if (this.configurationMap?.editFigures.edit) {
432
+ contextEdit = {
433
+ featureGroup: featureGroup, // Crea un nuevo grupo de capas para los polígonos
434
+ ...this.configurationMap?.editFigures.edit,
435
+ remove: this.configurationMap?.editFigures.remove,
436
+ };
437
+ }
438
+
439
+ const renderGeojson = this.renderGeojson;
440
+ if (renderGeojson && renderGeojson.length) {
441
+ renderGeojson.forEach((item: any) => {
442
+ if (item.type === "FeatureCollection") {
443
+ item.features.forEach((feature: any) => {
444
+ if (
445
+ feature.geometry.type === "Polygon" ||
446
+ feature.geometry.type === "MultiPolygon" ||
447
+ feature.geometry.type === "LineString" ||
448
+ feature.geometry.type === "MultiLineString" ||
449
+ feature.geometry.type === "Point" ||
450
+ feature.geometry.type === "MultiPoint"
451
+ ) {
452
+ const self = this;
453
+ L.geoJson(feature, {
454
+ pointToLayer: this.getPointToLayer.bind(this),
455
+ onEachFeature: function (feature, layer) {
456
+ featureGroup.addLayer(layer);
457
+ // Mostrar popup para Point
458
+ if (feature.geometry.type === "Point") {
459
+ var popupContent = self.getPopupContent(feature);
460
+ layer.bindPopup(popupContent);
461
+ }
462
+ // Mostrar popup para Polygon y MultiPolygon al hacer clic
463
+ else if (
464
+ feature.geometry.type === "Polygon" ||
465
+ feature.geometry.type === "MultiPolygon"
466
+ ) {
467
+ var tooltipContent =
468
+ self.getPolygonTooltipContent(feature);
469
+ layer.bindPopup(tooltipContent);
470
+ }
471
+ },
472
+ });
473
+ }
474
+ });
475
+ } else if (item.type === "Feature") {
476
+ if (
477
+ item.geometry.type === "Polygon" ||
478
+ item.geometry.type === "MultiPolygon" ||
479
+ item.geometry.type === "LineString" ||
480
+ item.geometry.type === "MultiLineString" ||
481
+ item.geometry.type === "Point" ||
482
+ item.geometry.type === "MultiPoint"
483
+ ) {
484
+ const self = this;
485
+ L.geoJson(item, {
486
+ pointToLayer: this.getPointToLayer.bind(this),
487
+ onEachFeature: function (feature, layer) {
488
+ featureGroup.addLayer(layer);
489
+ // Mostrar popup para Point
490
+ if (feature.geometry.type === "Point") {
491
+ var popupContent = self.getPopupContent(feature);
492
+ layer.bindPopup(popupContent);
493
+ }
494
+ // Mostrar popup para Polygon y MultiPolygon al hacer clic
495
+ else if (
496
+ feature.geometry.type === "Polygon" ||
497
+ feature.geometry.type === "MultiPolygon"
498
+ ) {
499
+ var tooltipContent = self.getPolygonTooltipContent(feature);
500
+ layer.bindPopup(tooltipContent);
501
+ }
502
+ },
503
+ });
504
+ }
505
+ }
506
+ });
507
+ const bounds = featureGroup.getBounds();
508
+ map.fitBounds(bounds);
509
+ }
510
+ const drawControl = new L.Control.Draw({
511
+ position: "topleft",
512
+ draw: {
513
+ polygon: this.configurationMap?.createFigures.polygon,
514
+ circle: false, //this.configurationMap?.createFigures.circle,
515
+ rectangle: this.configurationMap?.createFigures.rectangle
516
+ ? {
517
+ shapeOptions: {
518
+ color: "blue",
519
+ },
520
+ }
521
+ : false,
522
+ marker: this.configurationMap?.createFigures.marker
523
+ ? {
524
+ icon: L.icon(iconDefaultMarket),
525
+ }
526
+ : false,
527
+ polyline: this.configurationMap?.createFigures.polyline
528
+ ? {
529
+ shapeOptions: {
530
+ color: "blue",
531
+ },
532
+ }
533
+ : false,
534
+ circlemarker: this.configurationMap?.createFigures.multipoint,
535
+ },
536
+ edit: contextEdit as any,
537
+ });
538
+ map.addControl(drawControl);
539
+
540
+ map.on("draw:created", (event: any) => {
541
+ const layer = event.layer;
542
+ featureGroup.addLayer(layer);
543
+ let geojson = layer.toGeoJSON();
544
+ // *** AGREGADO: Manejo especial para CircleMarker (convertir a MultiPoint) ***
545
+ if (event.layerType === "circlemarker") {
546
+ // Convertir CircleMarker a formato MultiPoint para consistencia
547
+ geojson = {
548
+ type: "Feature",
549
+ geometry: {
550
+ type: "MultiPoint",
551
+ coordinates: [geojson.geometry.coordinates],
552
+ },
553
+ properties: {
554
+ ...geojson.properties,
555
+ pointType: "multipoint",
556
+ style: {
557
+ color:
558
+ this.configurationMap?.createFigures?.multipoint?.color ||
559
+ "green",
560
+ fillColor:
561
+ this.configurationMap?.createFigures?.multipoint?.fillColor ||
562
+ "green",
563
+ fillOpacity:
564
+ this.configurationMap?.createFigures?.multipoint
565
+ ?.fillOpacity || 0.8,
566
+ radius:
567
+ this.configurationMap?.createFigures?.multipoint?.radius || 6,
568
+ weight:
569
+ this.configurationMap?.createFigures?.multipoint?.weight || 2,
570
+ },
571
+ },
572
+ };
573
+ }
574
+ if (this.getGeoJSON) this.getGeoJSON(geojson);
575
+ });
576
+
577
+ map.on("draw:edited", (event: any) => {
578
+ const layers = event.layers;
579
+ layers.eachLayer((layer: any) => {
580
+ const geojson = layer.toGeoJSON();
581
+ if (this.getGeoJSON) this.getGeoJSON(geojson);
582
+ });
583
+ });
584
+ },
585
+ getPointToLayer(feature: any, latlng: any) {
586
+ const geometryType = feature.geometry?.type;
587
+
588
+ // Point: icono según properties.tipo
589
+ if (geometryType === "Point") {
590
+ const tipo = feature.properties?.tipo;
591
+ const firstIcon = L.icon({
592
+ iconUrl: homeIconUrl,
593
+ iconSize: [38, 38],
594
+ iconAnchor: [16, 41],
595
+ });
596
+ const lastIcon = L.icon({
597
+ iconUrl: endIconUrl,
598
+ iconSize: [38, 38],
599
+ iconAnchor: [16, 41],
600
+ });
601
+ const pointerIcon = L.icon({
602
+ iconUrl: trackingIconUrl,
603
+ iconSize: [38, 38],
604
+ iconAnchor: [16, 41],
605
+ });
606
+
607
+ let icon = pointerIcon;
608
+ if (tipo === 0) icon = firstIcon;
609
+ else if (tipo === 1) icon = lastIcon;
610
+
611
+ return L.marker(latlng, { icon });
612
+ }
613
+
614
+ // Otros tipos: icono por defecto
615
+ return L.marker(latlng);
616
+ },
617
+ async searchAddress(query: string) {
618
+ const address = await axios.get(
619
+ location.protocol + "//nominatim.openstreetmap.org/search?",
620
+ {
621
+ params: {
622
+ //query
623
+ q: query,
624
+ limit: 1,
625
+ format: "json",
626
+ },
627
+ }
628
+ );
629
+ if (address.data.length === 1) {
630
+ const lat = parseFloat(address.data[0].lat);
631
+ const lng = parseFloat(address.data[0].lon);
632
+ const coord = { lng, lat };
633
+ this.setCoordinates({ ...coord, moveMarker: true });
634
+ return address.data[0];
635
+ }
636
+ return address.data;
637
+ },
638
+ setCoordinates({
639
+ lat,
640
+ lng,
641
+ }: {
642
+ lat: number;
643
+ lng: number;
644
+ moveMarker?: boolean;
645
+ }): void {
646
+ if (this.mapRender) {
647
+ const newCenter = L.latLng(lat, lng);
648
+ this.mapRender.panTo(newCenter, { animate: true, duration: 0.5 });
649
+ }
650
+ },
651
+ getPopupContent(feature: any): string {
652
+ // Puedes personalizar el contenido del popup aquí
653
+ const props = feature.properties || {};
654
+ // Solo toma en cuenta descripcion y fechaHoraLlegada
655
+ const descripcion = props.descripcion || "";
656
+ const fechaHoraLlegada = props.fechaHoraLlegada || "";
657
+ // url de la foto
658
+ const fotoId = props.fotoId || "";
659
+
660
+ const formatIsoPreserve = (iso: string): string => {
661
+ const d = new Date(iso);
662
+ if (isNaN(d.getTime())) return iso; // fallback: devolver la cadena original si no es válida
663
+ const pad = (n: number) => n.toString().padStart(2, "0");
664
+ // Usar métodos UTC para evitar que el navegador convierta a la zona local
665
+ const day = pad(d.getUTCDate());
666
+ const month = pad(d.getUTCMonth() + 1);
667
+ const year = d.getUTCFullYear();
668
+ const hours = pad(d.getUTCHours());
669
+ const minutes = pad(d.getUTCMinutes());
670
+ const seconds = pad(d.getUTCSeconds());
671
+ return `${day}-${month}-${year} ${hours}:${minutes}:${seconds}`;
672
+ };
673
+
674
+ // Formatear fecha a dd-MM-yyyy hh:mm:ss
675
+ let fechaFormateada = "";
676
+ if (fechaHoraLlegada) {
677
+ /* const fecha = new Date(fechaHoraLlegada);
678
+ const pad = (n: number) => n.toString().padStart(2, "0");
679
+ fechaFormateada = `${pad(fecha.getDate())}-${pad(
680
+ fecha.getMonth() + 1
681
+ )}-${fecha.getFullYear()} ${pad(fecha.getHours())}:${pad(
682
+ fecha.getMinutes()
683
+ )}:${pad(fecha.getSeconds())}`; */
684
+ fechaFormateada = formatIsoPreserve(fechaHoraLlegada);
685
+ }
686
+ let html = "<div>";
687
+ if (fotoId) {
688
+ html += `<img src="${fotoId}" style="width: 200px; height: auto; margin-bottom: 5px;"><br>`;
689
+ }
690
+ html += `<b>Descripción:</b> ${descripcion}<br>`;
691
+ if (fechaFormateada) {
692
+ html += `<b>Fecha Hora Llegada:</b> ${fechaFormateada}<br>`;
693
+ }
694
+ html += "</div>";
695
+ return html;
696
+ },
697
+ getPolygonTooltipContent(feature: any): string {
698
+ const props = feature.properties || {};
699
+ const descripcion = props.descripcion || props.name || "Sin descripción";
700
+
701
+ return `<div style="font-weight: bold; padding: 5px;">${descripcion}</div>`;
702
+ },
703
+ },
704
+ watch: {
705
+ coordinatesMap(newVal) {
706
+ this.renderCoordinates = newVal;
707
+ if (this.mapRender && this.markerRender) {
708
+ const newLatLng = L.latLng([newVal[0], newVal[1]]);
709
+ this.mapRender.setView([newVal[0], newVal[1]], newVal[2]);
710
+ this.markerRender.setLatLng(newLatLng);
711
+ }
712
+ },
713
+ dataPolygon(newVal) {
714
+ this.renderGeojson = newVal;
715
+ },
716
+ },
717
+ });
718
+ </script>