168 lines
4.4 KiB
JavaScript
168 lines
4.4 KiB
JavaScript
import { useState } from "react";
|
|
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,
|
|
alertingList,
|
|
userCoords,
|
|
routeCoords,
|
|
route,
|
|
alertCoords,
|
|
}) {
|
|
// Check if we have valid coordinates
|
|
const hasUserCoords =
|
|
userCoords && userCoords.longitude !== null && userCoords.latitude !== null;
|
|
|
|
const list = useShallowMemo(() => {
|
|
const computedList = alertingList.map((row) => {
|
|
const { oneAlert } = row;
|
|
const { coordinates: alertCoords } = oneAlert.location;
|
|
|
|
const [longitude, latitude] = alertCoords;
|
|
let distance;
|
|
if (longitude && latitude && hasUserCoords) {
|
|
distance = getDistance(
|
|
{ longitude, latitude },
|
|
{
|
|
longitude: userCoords.longitude,
|
|
latitude: userCoords.latitude,
|
|
},
|
|
);
|
|
}
|
|
return { ...row, alert: { ...oneAlert, distance } };
|
|
});
|
|
|
|
return computedList;
|
|
}, [alertingList, userCoords, hasUserCoords]);
|
|
|
|
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}:initial`;
|
|
|
|
features.push({
|
|
type: "Feature",
|
|
id,
|
|
properties: {
|
|
id,
|
|
icon: "origin",
|
|
level: alert.level,
|
|
alert,
|
|
coordinates,
|
|
isInitialLocation: true,
|
|
},
|
|
geometry: {
|
|
type: "Point",
|
|
coordinates,
|
|
},
|
|
});
|
|
}
|
|
});
|
|
|
|
return {
|
|
type: "FeatureCollection",
|
|
features,
|
|
};
|
|
}, [list]);
|
|
|
|
const superCluster = useShallowMemo(() => {
|
|
const cluster = new Supercluster({ radius: 40, maxZoom: 16 });
|
|
cluster.load(featureCollection.features);
|
|
return cluster;
|
|
}, [featureCollection.features]);
|
|
// console.log({ superCluster: JSON.stringify(superCluster) });
|
|
|
|
const [shape, setShape] = useState({
|
|
type: "FeatureCollection",
|
|
features: clusterFeature,
|
|
});
|
|
|
|
useShallowEffect(() => {
|
|
// Early return if no user coordinates
|
|
if (!hasUserCoords) {
|
|
setShape({ type: "FeatureCollection", features: clusterFeature });
|
|
return;
|
|
}
|
|
|
|
const userCoordinates = [userCoords.longitude, userCoords.latitude];
|
|
const features = [...clusterFeature];
|
|
|
|
// Only add route line if we have valid route data
|
|
const isRouteEnding = route?.distance !== 0 || routeCoords?.length === 0;
|
|
const hasValidAlertCoords =
|
|
Array.isArray(alertCoords) && alertCoords.length === 2;
|
|
|
|
if (isRouteEnding) {
|
|
const lineCoordinates = [userCoordinates];
|
|
|
|
// Add route coordinates if available
|
|
if (Array.isArray(routeCoords) && routeCoords.length > 0) {
|
|
lineCoordinates.push(...routeCoords);
|
|
}
|
|
|
|
// Add alert coordinates if valid
|
|
if (hasValidAlertCoords) {
|
|
lineCoordinates.push(alertCoords);
|
|
}
|
|
|
|
const lineString = {
|
|
type: "Feature",
|
|
properties: {},
|
|
geometry: {
|
|
type: "LineString",
|
|
coordinates: lineCoordinates,
|
|
},
|
|
};
|
|
features.push(lineString);
|
|
}
|
|
|
|
// console.log("features", JSON.stringify(features));
|
|
setShape({ type: "FeatureCollection", features });
|
|
}, [
|
|
setShape,
|
|
clusterFeature,
|
|
userCoords,
|
|
hasUserCoords,
|
|
routeCoords,
|
|
alertCoords,
|
|
route?.distance,
|
|
]);
|
|
|
|
return { superCluster, shape };
|
|
}
|