From 91dd2c81e38b0ab29f7ec48193804d0293493a5a Mon Sep 17 00:00:00 2001 From: Corentin Huet Date: Mon, 9 Mar 2026 16:48:58 +0100 Subject: [PATCH] feat: :sparkles: show pin markers on zoom out and enable site navigation on marker double-click --- .../fo/components/LeafletMapVueComponent.vue | 49 +++++++++++++++++-- resources/ts/fo/utilities/fontawesome.ts | 4 +- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/resources/ts/fo/components/LeafletMapVueComponent.vue b/resources/ts/fo/components/LeafletMapVueComponent.vue index ffbca7e..f4b95f5 100644 --- a/resources/ts/fo/components/LeafletMapVueComponent.vue +++ b/resources/ts/fo/components/LeafletMapVueComponent.vue @@ -31,6 +31,7 @@ import trans from "../../modules/trans"; type Site = { name: string; + slug: string; /** WYSIWYG text */ description: string; employees: number; @@ -44,6 +45,7 @@ type Site = { title: string; }, divIcon: DivIcon, + pinIcon: DivIcon, marker: Marker|null }; @@ -139,12 +141,14 @@ export default defineComponent({ }); this.oms.addListener("click", this.selectedMarker); this.oms.addListener("spiderfy", this.clearSelectedMarkers); + this.map.on("zoomend", this.updateMarkers); }, parseSiteModelList(siteModelList: LaravelModelList) { const bodyFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize); siteModelList.forEach((site) => { this.siteList.push({ name: String(site.name), + slug: String(site.slug), description: String(site.description), employees: Number.parseInt(String(site.employees)), coords: { @@ -168,6 +172,11 @@ export default defineComponent({ } ), iconSize: [10*bodyFontSize, 3*bodyFontSize], + }), + pinIcon: new DivIcon({ + html: "", + className: "", + iconSize: [24, 18] }) }); }); @@ -187,15 +196,38 @@ export default defineComponent({ }, setupMarkers() { this.siteList.forEach((site) => { + const mapZoom = this.map.getZoom(); const marker = new Marker(site.coords, { title: site.name, alt: site.name, - icon: site.divIcon as Icon + icon: mapZoom >= 8 ? site.pinIcon as Icon : site.divIcon as Icon }); this.map.addLayer(marker); // @ts-ignore this.oms.addMarker(marker); site.marker = marker; + + marker.on("dblclick", () => { + window.location.href = `/sites/${site.slug}`; + }); + }); + }, + updateMarkers() { + this.siteList.forEach((site) => { + let newMarker = null; + const mapZoom = this.map.getZoom(); + + if (!site.marker) { + throw new Error("Missing Marker"); + } + + if (mapZoom >= 12) { + newMarker = site.divIcon; + } else { + newMarker = site.pinIcon; + } + + site.marker.setIcon(newMarker as Icon); }); }, truncateString(str: string, limit: number, end: string = "..") { @@ -211,11 +243,15 @@ export default defineComponent({ throw new Error("Could not fetch related Site"); } const pin = marker.getElement()!.firstChild as HTMLElement | null; + if(!pin) { throw new Error("Missing Marker Pin"); } - pin.classList.add("bg-primary", "text-white"); - pin.classList.remove("bg-white", "text-primary"); + + if (pin.tagName !== "svg") { + pin.classList.add("bg-primary", "text-white"); + pin.classList.remove("bg-white", "text-primary"); + } if(this.controlSliderId) { const slider = window.__SLIDERS.get(this.controlSliderId); @@ -231,8 +267,11 @@ export default defineComponent({ if(!pin) { throw new Error("Missing Marker Pin"); } - pin.classList.add("bg-white", "text-primary"); - pin.classList.remove("bg-primary", "text-white"); + + if (pin.tagName !== "svg") { + pin.classList.add("bg-white", "text-primary"); + pin.classList.remove("bg-primary", "text-white"); + } }); } }, diff --git a/resources/ts/fo/utilities/fontawesome.ts b/resources/ts/fo/utilities/fontawesome.ts index e15d068..132b00f 100644 --- a/resources/ts/fo/utilities/fontawesome.ts +++ b/resources/ts/fo/utilities/fontawesome.ts @@ -16,7 +16,8 @@ import { faPlus, faQuestionCircle, faUserGroup, - faUsers + faUsers, + faMapLocationDot } from "@fortawesome/free-solid-svg-icons"; config.autoReplaceSvg = false; @@ -37,5 +38,6 @@ library.add(faPlus); library.add(faPlay); library.add(faPause); library.add(faUsers); +library.add(faMapLocationDot); dom.watch();