From c9cf8e13a88b56982aa5bc9cd9bd021353b339b1 Mon Sep 17 00:00:00 2001 From: devthejo Date: Sat, 31 May 2025 11:59:12 +0200 Subject: [PATCH] feat(follow-location): map wip --- src/assets/img/marker-origin.png | Bin 0 -> 8813 bytes src/containers/Map/FeatureImages.js | 2 + src/containers/Map/ShapePoints.js | 12 +++++ src/scenes/AlertCurMap/useFeatures.js | 67 +++++++++++++++++++------- 4 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 src/assets/img/marker-origin.png diff --git a/src/assets/img/marker-origin.png b/src/assets/img/marker-origin.png new file mode 100644 index 0000000000000000000000000000000000000000..9a2eaa35bd0c90d204d0cf672b8ddfa866e499e8 GIT binary patch literal 8813 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 ({ clusterCount: { textField: "{point_count_abbreviated}", @@ -46,6 +51,13 @@ export default function ShapePoints({ shape, children, ...shapeSourceProps }) { + + {children} ); diff --git a/src/scenes/AlertCurMap/useFeatures.js b/src/scenes/AlertCurMap/useFeatures.js index d14d001..0db219e 100644 --- a/src/scenes/AlertCurMap/useFeatures.js +++ b/src/scenes/AlertCurMap/useFeatures.js @@ -3,6 +3,7 @@ import { getDistance } from "geolib"; import Supercluster from "supercluster"; import useShallowMemo from "~/hooks/useShallowMemo"; import useShallowEffect from "~/hooks/useShallowEffect"; +import { deepEqual } from "fast-equals"; export default function useFeatures({ clusterFeature, @@ -38,35 +39,67 @@ export default function useFeatures({ return computedList; }, [alertingList, userCoords, hasUserCoords]); - const featureCollection = useShallowMemo( - () => ({ - type: "FeatureCollection", - features: list.map((row) => { - const { alert } = row; - const { level, state } = alert; - const [longitude, latitude] = alert.location.coordinates; + const featureCollection = useShallowMemo(() => { + const features = list.map((row) => { + const { alert } = row; + const { level, state } = alert; + const [longitude, latitude] = alert.location.coordinates; + const coordinates = [longitude, latitude]; + const id = `alert:${alert.id}`; + const icon = state === "open" ? level : `${level}Disabled`; + return { + type: "Feature", + id, + properties: { + id, + level, + icon, + alert, + coordinates, + }, + geometry: { + type: "Point", + coordinates, + }, + }; + }); + + // Add initial location marker if locations are different + list.forEach((row) => { + const { alert } = row; + if ( + alert.initialLocation && + alert.location && + !deepEqual(alert.initialLocation, alert.location) + ) { + const [longitude, latitude] = alert.initialLocation.coordinates; const coordinates = [longitude, latitude]; - const id = `alert:${alert.id}`; - const icon = state === "open" ? level : `${level}Disabled`; - return { + const id = `alert:${alert.id}:initial`; + + features.push({ type: "Feature", id, properties: { id, - level, - icon, + icon: "origin", + level: alert.level, alert, coordinates, + isInitialLocation: true, }, geometry: { type: "Point", coordinates, }, - }; - }), - }), - [list], - ); + }); + } + }); + + return { + type: "FeatureCollection", + features, + }; + }, [list]); const superCluster = useShallowMemo(() => { const cluster = new Supercluster({ radius: 40, maxZoom: 16 });