浏览代码

Allow cluster viewing

Matthias Rupp 2 年之前
父节点
当前提交
f49e122361

+ 42 - 20
web/src/lib/components/shared-components/leaflet/asset-marker-cluster.svelte

@@ -1,6 +1,7 @@
 <script lang="ts" context="module">
 <script lang="ts" context="module">
 	import { createContext } from '$lib/utils/context';
 	import { createContext } from '$lib/utils/context';
 
 
+	// @ts-ignore
 	const { get: getContext, set: setClusterContext } = createContext<() => L.MarkerClusterGroup>();
 	const { get: getContext, set: setClusterContext } = createContext<() => L.MarkerClusterGroup>();
 
 
 	export const getClusterContext = () => {
 	export const getClusterContext = () => {
@@ -13,45 +14,66 @@
 	import 'leaflet.markercluster';
 	import 'leaflet.markercluster';
 	import { getMapContext } from './map.svelte';
 	import { getMapContext } from './map.svelte';
 	import { MapMarkerResponseDto, getFileUrl } from '@api';
 	import { MapMarkerResponseDto, getFileUrl } from '@api';
-	import { Marker, Icon } from 'leaflet';
-	import { assetInteractionStore } from '$lib/stores/asset-interaction.store';
+	import L from 'leaflet';
+	import { createEventDispatcher } from 'svelte';
+
+	class AssetMarker extends L.Marker {
+		marker: MapMarkerResponseDto;
+
+		constructor(marker: MapMarkerResponseDto) {
+			super([marker.lat, marker.lon], {
+				icon: new L.Icon({
+					iconUrl: getFileUrl(marker.id, true),
+					iconRetinaUrl: getFileUrl(marker.id, true),
+					iconSize: [60, 60],
+					iconAnchor: [12, 41],
+					popupAnchor: [1, -34],
+					tooltipAnchor: [16, -28],
+					shadowSize: [41, 41]
+				}),
+			});
+
+			this.marker = marker;
+		}
+
+		getAssetId(): string {
+			return this.marker.id;
+		}
+	}
+
+	const dispatch = createEventDispatcher<{ view: { assets: string[] } }>();
 
 
 	export let markers: MapMarkerResponseDto[];
 	export let markers: MapMarkerResponseDto[];
 
 
 	const map = getMapContext();
 	const map = getMapContext();
+	// @ts-ignore
 	let cluster: L.MarkerClusterGroup;
 	let cluster: L.MarkerClusterGroup;
 
 
 	setClusterContext(() => cluster);
 	setClusterContext(() => cluster);
 
 
 	onMount(() => {
 	onMount(() => {
+		// @ts-ignore
 		cluster = new L.MarkerClusterGroup({
 		cluster = new L.MarkerClusterGroup({
 			showCoverageOnHover: false,
 			showCoverageOnHover: false,
-			zoomToBoundsOnClick: true,
-			spiderfyOnMaxZoom: true,
+			zoomToBoundsOnClick: false,
+			spiderfyOnMaxZoom: false,
 			maxClusterRadius: 30,
 			maxClusterRadius: 30,
 			spiderLegPolylineOptions: { opacity: 0 },
 			spiderLegPolylineOptions: { opacity: 0 },
 			spiderfyDistanceMultiplier: 3
 			spiderfyDistanceMultiplier: 3
 		});
 		});
 
 
-		for (let marker of markers) {
-
-			const icon = new Icon({
-				iconUrl: getFileUrl(marker.id, true),
-				iconRetinaUrl: getFileUrl(marker.id, true),
-				iconSize: [60, 60],
-				iconAnchor: [12, 41],
-				popupAnchor: [1, -34],
-				tooltipAnchor: [16, -28],
-				shadowSize: [41, 41]
-			});
+		// @ts-ignore
+		cluster.on('clusterclick', (event) => {
+			// @ts-ignore
+			const ids = event.layer.getAllChildMarkers().map(marker => marker.getAssetId());
+			dispatch('view', { assets: ids });
+		});
 
 
-			const leafletMarker = new Marker([marker.lat, marker.lon], {
-				icon,
-				alt: ''
-			});
+		for (let marker of markers) {
+			const leafletMarker = new AssetMarker(marker);
 
 
 			leafletMarker.on('click', () => {
 			leafletMarker.on('click', () => {
-				assetInteractionStore.setViewingAssetId(marker.id);
+				dispatch('view', { assets: [marker.id] });
 			});
 			});
 
 
 			cluster.addLayer(leafletMarker);
 			cluster.addLayer(leafletMarker);

+ 1 - 0
web/src/lib/components/shared-components/leaflet/tile-layer.svelte

@@ -11,6 +11,7 @@
 	const map = getMapContext();
 	const map = getMapContext();
 
 
 	onMount(() => {
 	onMount(() => {
+		// @ts-ignore
 		tileLayer = new L.tileLayer.colorFilter(urlTemplate, options).addTo(map);
 		tileLayer = new L.tileLayer.colorFilter(urlTemplate, options).addTo(map);
 	});
 	});
 
 

+ 28 - 4
web/src/routes/(user)/map/+page.svelte

@@ -7,18 +7,40 @@
 	import {
 	import {
 		assetInteractionStore,
 		assetInteractionStore,
 		isViewingAssetStoreState,
 		isViewingAssetStoreState,
-		viewingAssetStoreState
+		viewingAssetStoreState,
+		
 	} from '$lib/stores/asset-interaction.store';
 	} from '$lib/stores/asset-interaction.store';
 	import { colorTheme } from '$lib/stores/preferences.store';
 	import { colorTheme } from '$lib/stores/preferences.store';
 
 
 	export let data: PageData;
 	export let data: PageData;
 
 
-	let initialMapCenter = [48, 11];
+	let initialMapCenter: [number, number] = [48, 11];
 
 
 	if (data.mapMarkers.length) {
 	if (data.mapMarkers.length) {
 		let firstMarker = data.mapMarkers[0];
 		let firstMarker = data.mapMarkers[0];
 		initialMapCenter = [firstMarker.lat, firstMarker.lon];
 		initialMapCenter = [firstMarker.lat, firstMarker.lon];
 	}
 	}
+
+	let viewingAssets: string[] = [];
+	let viewingAssetCursor = 0;
+
+	function onViewAssets(assets: string[]) {
+		assetInteractionStore.setViewingAssetId(assets[0]);
+		viewingAssets = assets;
+		viewingAssetCursor = 0;
+	}
+
+	function navigateNext() {
+		if (viewingAssetCursor < viewingAssets.length - 1) {
+			assetInteractionStore.setViewingAssetId(viewingAssets[++viewingAssetCursor]);
+		}
+	}
+
+	function navigatePrevious() {
+		if (viewingAssetCursor > 0) {
+			assetInteractionStore.setViewingAssetId(viewingAssets[--viewingAssetCursor]);
+		}
+	}
 </script>
 </script>
 
 
 <UserPageLayout user={data.user} title={data.meta.title}>
 <UserPageLayout user={data.user} title={data.meta.title}>
@@ -48,7 +70,7 @@
 				/>
 				/>
 			{/if}
 			{/if}
 
 
-			<AssetMarkerCluster markers={data.mapMarkers} />
+			<AssetMarkerCluster markers={data.mapMarkers} on:view={event => onViewAssets(event.detail.assets)} />
 		</Map>
 		</Map>
 	</div>
 	</div>
 
 
@@ -58,7 +80,9 @@
 	{#if $isViewingAssetStoreState}
 	{#if $isViewingAssetStoreState}
 		<AssetViewer
 		<AssetViewer
 			asset={$viewingAssetStoreState}
 			asset={$viewingAssetStoreState}
-			showNavigation={false}
+			showNavigation={viewingAssets.length > 1}
+			on:navigate-next={navigateNext}
+			on:navigate-previous={navigatePrevious}
 			on:close={() => {
 			on:close={() => {
 				assetInteractionStore.setIsViewingAsset(false);
 				assetInteractionStore.setIsViewingAsset(false);
 			}}
 			}}