Skip to content

Commit

Permalink
Rearrange controls in narrow mode
Browse files Browse the repository at this point in the history
  • Loading branch information
cdauth committed Apr 26, 2024
1 parent e585e59 commit e9f6475
Show file tree
Hide file tree
Showing 12 changed files with 265 additions and 90 deletions.
3 changes: 2 additions & 1 deletion frontend/src/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,8 @@
},
"leaflet-map": {
"open-full-size": "{{appName}} als ganze Seite öffnen",
"loading": "Wird geladen…"
"loading": "Wird geladen…",
"attribution-notice": "Diese App basiert auf Kartendaten von [OpenStreetMap](https://www.openstreetmap.org/copyright/de). Mehr Details im Dialog „[Über {{appName}}](#about-dialog)“ im Hilfe-Menü."
},
"leaflet-map-components": {
"pois-too-many-results": "Nicht alle POIs konnten geladen werden, weil zu viele gefunden wurden. Zoom Sie weiter hinein, um alle POIs anzuzeigen.",
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,8 @@
},
"leaflet-map": {
"open-full-size": "Open {{appName}} in full size",
"loading": "Loading…"
"loading": "Loading…",
"attribution-notice": "This app is based on map data from [OpenStreetMap](https://www.openstreetmap.org/copyright). Find out more in the “[About {{appName}}](#about-dialog)” dialog in the Help menu."
},
"leaflet-map-components": {
"pois-too-many-results": "Not all POIs are shown because there are too many results. Zoom in to show all results.",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { type InjectionKey, type Ref, inject, onScopeDispose, provide, shallowReactive, toRef, watch, reactive, readonly, shallowReadonly } from "vue";
import { useMaxBreakpoint } from "../../utils/bootstrap";
import { useIsNarrow } from "../../utils/bootstrap";
import type { FacilMapComponents, FacilMapContext, FacilMapSettings } from "./facil-map-context";
const contextInject = Symbol("contextInject") as InjectionKey<FacilMapContext>;
Expand Down Expand Up @@ -45,7 +45,7 @@
appName: "FacilMap"
});
const isNarrow = useMaxBreakpoint("sm");
const isNarrow = useIsNarrow();
const components = shallowReactive<FacilMapComponents>({});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type MapContextEvents = {
};

export interface MapComponents {
zoomControl: L.Control.Zoom;
attribution: AttributionControl;
bboxHandler: BboxHandler;
container: HTMLElement;
Expand Down
161 changes: 109 additions & 52 deletions frontend/src/lib/components/leaflet-map/leaflet-map-components.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type Ref, ref, watch, markRaw, reactive, watchEffect, shallowRef, shallowReadonly, type Raw, nextTick } from "vue";
import { type Control, latLng, latLngBounds, type Map, map as leafletMap, DomUtil, control } from "leaflet";
import { type Ref, ref, watch, markRaw, reactive, watchEffect, shallowRef, shallowReadonly, type Raw, nextTick, effectScope, onScopeDispose } from "vue";
import { Control, latLng, latLngBounds, type Map, map as leafletMap, DomUtil, control } from "leaflet";
import "leaflet/dist/leaflet.css";
import { BboxHandler, getIconHtml, getVisibleLayers, HashHandler, LinesLayer, MarkersLayer, SearchResultsLayer, OverpassLayer, OverpassLoadStatus, displayView, getInitialView, coreIconList } from "facilmap-leaflet";
import "leaflet.locatecontrol";
Expand All @@ -18,17 +18,20 @@ import { requireClientContext } from "../facil-map-context-provider/facil-map-co
import { type Optional } from "facilmap-utils";
import { getI18n, i18nResourceChangeCounter } from "../../utils/i18n";
import { AttributionControl } from "./attribution";
import { fixOnCleanup } from "../../utils/vue";
import { isMaxBreakpoint, isNarrowBreakpoint } from "../../utils/bootstrap";

type MapContextWithoutComponents = Optional<WritableMapContext, 'components'>;
type OnCleanup = (cleanupFn: () => void) => void;

function useMap(element: Ref<HTMLElement>, mapContext: MapContextWithoutComponents): Ref<Raw<Map>> {
const mapRef = shallowRef(undefined as any as Map);
const interaction = ref(0);

watchEffect((onCleanup) => {
const map = mapRef.value = markRaw(leafletMap(element.value, { boxZoom: false, attributionControl: false }));
const map = mapRef.value = markRaw(leafletMap(element.value, {
boxZoom: false,
attributionControl: false,
zoomControl: false
}));

map._controlCorners.bottomcenter = DomUtil.create("div", "leaflet-bottom fm-leaflet-center", map._controlContainer);

Expand Down Expand Up @@ -80,7 +83,7 @@ function useMap(element: Ref<HTMLElement>, mapContext: MapContextWithoutComponen
function useMapComponent<T>(
map: Ref<Map>,
construct: () => T,
activate: (component: T, onCleanup: OnCleanup) => void
activate: (component: T, map: Map) => void
): Ref<T> {
const componentRef = shallowRef(undefined as any as T);
watchEffect(() => {
Expand All @@ -90,26 +93,56 @@ function useMapComponent<T>(
watch([
componentRef,
map
], ([component], prev, onCleanup_) => {
const onCleanup = fixOnCleanup(onCleanup_);
activate(component as T, onCleanup);
], ([component, map], prev, onCleanup) => {
const scope = effectScope();
scope.run(() => {
activate(component as any, map);
});
onCleanup(() => {
scope.stop();
});
}, { immediate: true });

return componentRef;
}

function useZoomControl(map: Ref<Map>): Ref<Raw<Control.Zoom>> {
return useMapComponent(
map,
() => markRaw(control.zoom()),
(zoomControl, map) => {
watch(() => isNarrowBreakpoint(), (isNarrow) => {
zoomControl.setPosition(isNarrow ? "bottomright" : "topleft");
}, { immediate: true });
map.addControl(zoomControl);

onScopeDispose(() => {
zoomControl.remove();
});
}
);
}

function useAttribution(map: Ref<Map>): Ref<Raw<AttributionControl>> {
return useMapComponent(
map,
() => markRaw(new AttributionControl()),
(attribution, onCleanup) => {
map.value.addControl(attribution);
(attribution, map) => {
watch(() => isNarrowBreakpoint(), (isNarrow) => {
if (isNarrow) {
attribution.remove();
} else {
map.addControl(attribution);
}
//attribution.setPosition(isNarrow ? "topleft" : "bottomright");
}, { immediate: true });

const i18nWatcher = watch(i18nResourceChangeCounter, () => {
watch(i18nResourceChangeCounter, () => {
attribution.update();
});
onCleanup(() => {
i18nWatcher();

onScopeDispose(() => {
attribution.remove();
});
}
);
Expand All @@ -119,9 +152,9 @@ function useBboxHandler(map: Ref<Map>, client: Ref<ClientContext>): Ref<Raw<Bbox
return useMapComponent(
map,
() => markRaw(new BboxHandler(map.value, client.value)),
(bboxHandler, onCleanup) => {
(bboxHandler) => {
bboxHandler.enable();
onCleanup(() => {
onScopeDispose(() => {
bboxHandler.disable();
});
}
Expand All @@ -132,9 +165,16 @@ function useGraphicScale(map: Ref<Map>): Ref<Raw<any>> {
return useMapComponent(
map,
() => markRaw(control.graphicScale({ fill: "hollow", position: "bottomcenter" })),
(graphicScale, onCleanup) => {
graphicScale.addTo(map.value);
onCleanup(() => {
(graphicScale, map) => {
watch(() => isNarrowBreakpoint(), (isNarrow) => {
if (isNarrow) {
graphicScale.remove();
} else {
graphicScale.addTo(map);
}
}, { immediate: true });

onScopeDispose(() => {
graphicScale.remove();
});
}
Expand All @@ -145,9 +185,9 @@ function useLinesLayer(map: Ref<Map>, client: Ref<ClientContext>): Ref<Raw<Lines
return useMapComponent(
map,
() => markRaw(new LinesLayer(client.value)),
(linesLayer, onCleanup) => {
linesLayer.addTo(map.value);
onCleanup(() => {
(linesLayer, map) => {
linesLayer.addTo(map);
onScopeDispose(() => {
linesLayer.remove();
});
}
Expand All @@ -159,10 +199,14 @@ function useLocateControl(map: Ref<Map>, context: FacilMapContext): Ref<Raw<Cont
map,
() => {
if (context.settings.locate) {
if (!coreIconList.includes("screenshot")) {
console.warn(`Icon "screenshot" is not in core icons.`);
}

let screenshotIconHtmlP = getIconHtml("currentColor", "1.5em", "screenshot");

return markRaw(control.locate({
flyTo: true,
icon: "a",
iconLoading: "a",
markerStyle: { pane: "fm-raised-marker", zIndexOffset: 10000 },
locateOptions: {
enableHighAccuracy: true
Expand All @@ -171,25 +215,29 @@ function useLocateControl(map: Ref<Map>, context: FacilMapContext): Ref<Raw<Cont
inView: "stop",
outOfView: "setView",
inViewNotFollowing: "outOfView"
},
createButtonCallback: (container, options) => {
const { link, icon } = (Control.Locate.prototype.options as Control.LocateOptions).createButtonCallback!(container, options) as any as { link: HTMLElement; icon: HTMLElement };
icon.remove();
const newIcon = document.createElement("span");
link.appendChild(newIcon);
screenshotIconHtmlP.then((iconHtml) => {
newIcon.innerHTML = iconHtml;
}).catch(console.error);
return { link, icon: newIcon };
}
}));
}
},
(locateControl, onCleanup) => {
(locateControl, map) => {
if (locateControl) {
locateControl.addTo(map.value);
watch(() => isNarrowBreakpoint(), (isNarrow) => {
locateControl.setPosition(isNarrow ? "bottomright" : "topleft");
}, { immediate: true });

if (!coreIconList.includes("screenshot")) {
console.warn(`Icon "screenshot" is not in core icons.`);
}

getIconHtml("currentColor", "1.5em", "screenshot").then((html) => {
locateControl._container.querySelector("a")?.insertAdjacentHTML("beforeend", html);
}).catch((err) => {
console.error("Error loading locate control icon", err);
});
locateControl.addTo(map);

onCleanup(() => {
onScopeDispose(() => {
locateControl.remove();
});
}
Expand All @@ -201,9 +249,9 @@ function useMarkersLayer(map: Ref<Map>, client: Ref<ClientContext>): Ref<Raw<Mar
return useMapComponent(
map,
() => markRaw(new MarkersLayer(client.value)),
(markersLayer, onCleanup) => {
markersLayer.addTo(map.value);
onCleanup(() => {
(markersLayer, map) => {
markersLayer.addTo(map);
onScopeDispose(() => {
markersLayer.remove();
});
}
Expand All @@ -214,9 +262,16 @@ function useMousePosition(map: Ref<Map>): Ref<Raw<Control.MousePosition>> {
return useMapComponent(
map,
() => markRaw(control.mousePosition({ emptyString: "0, 0", separator: ", ", position: "bottomright" })),
(mousePosition, onCleanup) => {
mousePosition.addTo(map.value);
onCleanup(() => {
(mousePosition, map) => {
watch(() => isNarrowBreakpoint(), (isNarrow) => {
if (isNarrow) {
mousePosition.remove();
} else {
mousePosition.addTo(map);
}
}, { immediate: true });

onScopeDispose(() => {
mousePosition.remove();
});
}
Expand Down Expand Up @@ -252,9 +307,9 @@ function useOverpassLayer(map: Ref<Map>, mapContext: MapContextWithoutComponents
.on("clear", () => {
mapContext.overpassMessage = undefined;
}),
(overpassLayer, onCleanup) => {
overpassLayer.addTo(map.value)
onCleanup(() => {
(overpassLayer, map) => {
overpassLayer.addTo(map)
onScopeDispose(() => {
overpassLayer.remove();
});
}
Expand All @@ -265,9 +320,9 @@ function useSearchResultsLayer(map: Ref<Map>): Ref<Raw<SearchResultsLayer>> {
return useMapComponent(
map,
() => markRaw(new SearchResultsLayer(undefined, { pathOptions: { weight: 7 } })),
(searchResultsLayer, onCleanup) => {
searchResultsLayer.addTo(map.value);
onCleanup(() => {
(searchResultsLayer, map) => {
searchResultsLayer.addTo(map);
onScopeDispose(() => {
searchResultsLayer.remove();
});
}
Expand Down Expand Up @@ -301,9 +356,9 @@ function useSelectionHandler(map: Ref<Map>, context: FacilMapContext, mapContext

return selectionHandler;
},
(selectionHandler, onCleanup) => {
(selectionHandler) => {
selectionHandler.enable();
onCleanup(() => {
onScopeDispose(() => {
selectionHandler.disable();
});
}
Expand Down Expand Up @@ -339,8 +394,8 @@ function useHashHandler(map: Ref<Map>, client: Ref<ClientContext>, context: Faci
}
});
},
(hashHandler, onCleanup) => {
onCleanup(() => {
(hashHandler) => {
onScopeDispose(() => {
hashHandler.disable();
});
}
Expand All @@ -351,6 +406,7 @@ function useMapComponents(context: FacilMapContext, mapContext: MapContextWithou
const client = requireClientContext(context);
const map = useMap(mapRef, mapContext);
const attribution = useAttribution(map);
const zoomControl = useZoomControl(map);
const bboxHandler = useBboxHandler(map, client);
const graphicScale = useGraphicScale(map);
const linesLayer = useLinesLayer(map, client);
Expand All @@ -364,6 +420,7 @@ function useMapComponents(context: FacilMapContext, mapContext: MapContextWithou

const components: MapComponents = reactive({
map,
zoomControl,
attribution,
bboxHandler,
graphicScale,
Expand Down
Loading

0 comments on commit e9f6475

Please sign in to comment.