diff --git a/client/package.json b/client/package.json index 174cd331..37451587 100644 --- a/client/package.json +++ b/client/package.json @@ -27,9 +27,11 @@ "@ts-rest/react-query": "3.51.0", "class-variance-authority": "0.7.0", "clsx": "2.1.1", + "d3": "7.9.0", "framer-motion": "11.11.9", "jotai": "2.10.1", "lucide-react": "0.447.0", + "mapbox-expression": "0.0.3", "mapbox-gl": "3.7.0", "next": "14.2.10", "next-auth": "4.24.8", @@ -42,6 +44,8 @@ "zod": "catalog:" }, "devDependencies": { + "@types/d3": "7.4.3", + "@types/geojson": "7946.0.14", "@types/mapbox-gl": "3.4.0", "@types/node": "catalog:", "@types/react": "^18", diff --git a/client/src/app/(projects)/page.tsx b/client/src/app/(projects)/page.tsx index 1e013437..b9eb26db 100644 --- a/client/src/app/(projects)/page.tsx +++ b/client/src/app/(projects)/page.tsx @@ -43,7 +43,7 @@ export default function Projects() { </motion.aside> <div className="flex flex-1 flex-col"> <ProjectsHeader /> - <div className="grid flex-grow grid-rows-2"> + <div className="grid flex-grow grid-rows-2 gap-3"> <section className="flex-1"> <ProjectsMap /> </section> diff --git a/client/src/app/(projects)/store.ts b/client/src/app/(projects)/store.ts index d5a3bf17..e03c9d06 100644 --- a/client/src/app/(projects)/store.ts +++ b/client/src/app/(projects)/store.ts @@ -12,6 +12,12 @@ export const projectsUIState = atom<{ tableExpanded: "default", }); +export const projectsMapState = atom<{ + legendOpen: boolean; +}>({ + legendOpen: true, +}); + export const projectsFiltersState = atom<{ keyword: string | undefined; projectSize: (typeof PROJECT_PARAMETERS)[0]["options"][number]["value"]; diff --git a/client/src/containers/projects/map/controls/index.tsx b/client/src/containers/projects/map/controls/index.tsx new file mode 100644 index 00000000..00c05d33 --- /dev/null +++ b/client/src/containers/projects/map/controls/index.tsx @@ -0,0 +1,20 @@ +import { PropsWithChildren } from "react"; + +import { cn } from "@/lib/utils"; + +type ControlsProps = PropsWithChildren<{ + className?: HTMLDivElement["className"]; +}>; + +export default function Controls({ className, children }: ControlsProps) { + return ( + <div + className={cn( + "absolute right-4 top-4 flex flex-col items-center justify-center space-y-2", + className, + )} + > + {children} + </div> + ); +} diff --git a/client/src/containers/projects/map/controls/legend/index.tsx b/client/src/containers/projects/map/controls/legend/index.tsx new file mode 100644 index 00000000..d613699e --- /dev/null +++ b/client/src/containers/projects/map/controls/legend/index.tsx @@ -0,0 +1,33 @@ +import { useSetAtom } from "jotai"; +import { Layers } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +import { projectsMapState } from "@/app/(projects)/store"; + +const BUTTON_CLASSES = { + default: + "flex h-8 w-8 items-center justify-center rounded-full border border-white bg-white text-black shadow-md transition-colors", + hover: "hover:border-gray-400 active:border-gray-400", +}; + +export default function LegendControl() { + const setProjectsMapState = useSetAtom(projectsMapState); + const handleMapLegend = () => { + setProjectsMapState((prev) => ({ + ...prev, + legendOpen: !prev.legendOpen, + })); + }; + + return ( + <button + className={cn(BUTTON_CLASSES.default, BUTTON_CLASSES.hover)} + aria-label="Toggle legend" + type="button" + onClick={handleMapLegend} + > + <Layers className="h-4 w-4" /> + </button> + ); +} diff --git a/client/src/containers/projects/map/controls/zoom/index.tsx b/client/src/containers/projects/map/controls/zoom/index.tsx new file mode 100644 index 00000000..daa450ed --- /dev/null +++ b/client/src/containers/projects/map/controls/zoom/index.tsx @@ -0,0 +1,82 @@ +import { useCallback, MouseEvent } from "react"; + +import { useMap, MapRef } from "react-map-gl"; + +import { Plus, Minus } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +const BUTTON_CLASSES = { + default: + "flex h-8 w-8 items-center justify-center rounded-full border border-white bg-white text-black shadow-md transition-colors", + hover: "hover:border-gray-400 active:border-gray-400", + disabled: "opacity-50 cursor-default", +}; + +export default function ZoomControl({ + id = "default", + className, +}: { + id?: string; + className?: HTMLDivElement["className"]; +}) { + const { [id]: mapRef } = useMap(); + + const zoom = mapRef?.getZoom() as NonNullable<ReturnType<MapRef["getZoom"]>>; + const minZoom = mapRef?.getMinZoom() as NonNullable< + ReturnType<MapRef["getMinZoom"]> + >; + const maxZoom = mapRef?.getMaxZoom() as NonNullable< + ReturnType<MapRef["getMaxZoom"]> + >; + + const increaseZoom = useCallback( + (e: MouseEvent<HTMLButtonElement>) => { + e.stopPropagation(); + if (!mapRef) return null; + + mapRef.zoomIn(); + }, + [mapRef], + ); + + const decreaseZoom = useCallback( + (e: MouseEvent<HTMLButtonElement>) => { + e.stopPropagation(); + if (!mapRef) return null; + + mapRef.zoomOut(); + }, + [mapRef], + ); + + return ( + <div className={cn("inline-flex flex-col space-y-2", className)}> + <button + className={cn(BUTTON_CLASSES.default, { + [BUTTON_CLASSES.hover]: zoom < maxZoom, + [BUTTON_CLASSES.disabled]: zoom >= maxZoom, + })} + aria-label="Zoom in" + type="button" + disabled={zoom >= maxZoom} + onClick={increaseZoom} + > + <Plus className="h-6 w-6" /> + </button> + + <button + className={cn(BUTTON_CLASSES.default, { + [BUTTON_CLASSES.hover]: zoom > minZoom, + [BUTTON_CLASSES.disabled]: zoom <= minZoom, + })} + aria-label="Zoom out" + type="button" + disabled={zoom <= minZoom} + onClick={decreaseZoom} + > + <Minus className="h-6 w-6" /> + </button> + </div> + ); +} diff --git a/client/src/containers/projects/map/index.tsx b/client/src/containers/projects/map/index.tsx index e4b70af8..b6b91c9a 100644 --- a/client/src/containers/projects/map/index.tsx +++ b/client/src/containers/projects/map/index.tsx @@ -1,22 +1,45 @@ "use client"; -import { ExpandIcon } from "lucide-react"; +import { ComponentProps } from "react"; + +import { useAtomValue } from "jotai"; + +import { projectsMapState } from "@/app/(projects)/store"; + +import Controls from "@/containers/projects/map/controls"; +import LegendControl from "@/containers/projects/map/controls/legend"; +import ZoomControl from "@/containers/projects/map/controls/zoom"; +import ProjectsLayer from "@/containers/projects/map/layers/projects"; +import { MATRIX_COLORS } from "@/containers/projects/map/layers/projects/utils"; +import Legend from "@/containers/projects/map/legend"; +import MatrixLegend from "@/containers/projects/map/legend/types/matrix"; import Map from "@/components/map"; -import { Button } from "@/components/ui/button"; export default function ProjectsMap() { - const onToggleExpand = () => {}; + const { legendOpen } = useAtomValue(projectsMapState); + + const matrixItems: ComponentProps<typeof MatrixLegend>["intersections"] = + Object.keys(MATRIX_COLORS).map((key, index) => ({ + color: key, + id: index, + })); return ( <div className="h-full overflow-hidden rounded-2xl"> <Map> - <Button - onClick={onToggleExpand} - className="absolute right-2 top-2 z-50" - > - <ExpandIcon /> - </Button> + <Controls> + <ZoomControl /> + </Controls> + <Controls className="bottom-8 top-auto"> + <LegendControl /> + </Controls> + {legendOpen && ( + <Legend> + <MatrixLegend items={[]} intersections={matrixItems} /> + </Legend> + )} + <ProjectsLayer /> </Map> </div> ); diff --git a/client/src/containers/projects/map/layers/projects/index.tsx b/client/src/containers/projects/map/layers/projects/index.tsx new file mode 100644 index 00000000..d5da406f --- /dev/null +++ b/client/src/containers/projects/map/layers/projects/index.tsx @@ -0,0 +1,329 @@ +import { Source, Layer } from "react-map-gl"; + +import * as d3 from "d3"; +import { FeatureCollection, Geometry } from "geojson"; +import { FillLayerSpecification } from "mapbox-gl"; + +import { generateColorRamp } from "@/containers/projects/map/layers/projects/utils"; + +export default function ProjectsLayer() { + const _data: FeatureCollection< + Geometry, + { + cost: number; + abatement: number; + } + > = { + type: "FeatureCollection", + features: [ + { + type: "Feature", + properties: { + cost: 10, + abatement: 10, + }, + geometry: { + coordinates: [ + [ + [-1.0188997350152817, 19.339371896125982], + [-1.0188997350152817, 15.2827299773014], + [4.790209065497407, 15.2827299773014], + [4.790209065497407, 19.339371896125982], + [-1.0188997350152817, 19.339371896125982], + ], + ], + type: "Polygon", + }, + }, + { + type: "Feature", + properties: { + cost: 2, + abatement: 2, + }, + geometry: { + coordinates: [ + [ + [8.553884254294076, 22.347045198308763], + [8.553884254294076, 18.98034659264529], + [13.93901438502084, 18.98034659264529], + [13.93901438502084, 22.347045198308763], + [8.553884254294076, 22.347045198308763], + ], + ], + type: "Polygon", + }, + }, + { + type: "Feature", + properties: { + cost: 3, + abatement: 3, + }, + geometry: { + type: "Polygon", + coordinates: [ + [ + [10.266381087897429, 18.198922150882048], + [10.126800739719087, 18.192359148568762], + [9.988595064490216, 18.172734820447474], + [9.85312422606958, 18.14024251677739], + [9.721719567720436, 18.095202210312237], + [9.595669690810766, 18.038057113269076], + [9.476207106652101, 17.969369007114743], + [9.364495630484392, 17.889812349055255], + [9.261618669117883, 17.800167234433463], + [9.168568533490959, 17.701311307580816], + [9.086236885294658, 17.594210724810743], + [9.015406403773625, 17.479910282070346], + [8.956743735727128, 17.359522826272258], + [8.910793769403016, 17.23421807359045], + [8.877975252072886, 17.10521096018074], + [8.858577752113135, 16.973749651097236], + [8.85275994973774, 16.84110333187473], + [8.86054922630853, 16.708549904608123], + [8.8818425104034, 16.57736370665313], + [8.916408329433118, 16.448803365550514], + [8.963890008337529, 16.32409989865731], + [9.023809951462665, 16.204445160433327], + [9.095574939782063, 16.090980734512833], + [9.178482372830471, 15.984787361679347], + [9.27172738273566, 15.886874988704175], + [9.374410746275132, 15.79817351671959], + [9.485547519713867, 15.719524321363023], + [9.604076320125786, 15.65167261032016], + [9.728869175858854, 15.595260677076443], + [9.858741867725827, 15.550822102625256], + [9.992464681395326, 15.518776949553867], + [10.128773490365873, 15.49942798532747], + [10.266381087897429, 15.492957963729829], + [10.403988685428985, 15.49942798532747], + [10.540297494399534, 15.518776949553867], + [10.674020308069032, 15.550822102625256], + [10.803892999936004, 15.595260677076443], + [10.928685855669073, 15.65167261032016], + [11.047214656080993, 15.719524321363023], + [11.158351429519726, 15.79817351671959], + [11.261034793059197, 15.886874988704175], + [11.354279802964387, 15.984787361679347], + [11.437187236012795, 16.090980734512833], + [11.508952224332194, 16.204445160433327], + [11.56887216745733, 16.32409989865731], + [11.616353846361742, 16.448803365550514], + [11.65091966539146, 16.57736370665313], + [11.672212949486328, 16.708549904608123], + [11.68000222605712, 16.84110333187473], + [11.674184423681723, 16.973749651097236], + [11.654786923721971, 17.10521096018074], + [11.621968406391844, 17.23421807359045], + [11.576018440067731, 17.359522826272265], + [11.517355772021233, 17.479910282070346], + [11.4465252905002, 17.594210724810743], + [11.364193642303901, 17.701311307580816], + [11.271143506676976, 17.800167234433463], + [11.168266545310468, 17.889812349055255], + [11.056555069142757, 17.969369007114743], + [10.937092484984092, 18.03805711326907], + [10.811042608074422, 18.095202210312237], + [10.679637949725281, 18.14024251677739], + [10.544167111304644, 18.172734820447474], + [10.40596143607577, 18.192359148568762], + [10.266381087897429, 18.198922150882048], + ], + ], + }, + }, + { + type: "Feature", + properties: { + cost: 4, + abatement: 4, + }, + geometry: { + coordinates: [ + [ + [-9.690278800554552, 26.97972035213317], + [-9.690278800554552, 24.396370522145148], + [-3.8527118185513416, 24.396370522145148], + [-3.8527118185513416, 26.97972035213317], + [-9.690278800554552, 26.97972035213317], + ], + ], + type: "Polygon", + }, + }, + { + type: "Feature", + properties: { + cost: 5, + abatement: 5, + }, + geometry: { + coordinates: [ + [ + [-7.541068855664491, 41.43353951220527], + [-7.541068855664491, 38.528044523038034], + [-1.643841285199045, 38.528044523038034], + [-1.643841285199045, 41.43353951220527], + [-7.541068855664491, 41.43353951220527], + ], + ], + type: "Polygon", + }, + }, + { + type: "Feature", + properties: { + cost: 6, + abatement: 6, + }, + geometry: { + coordinates: [ + [ + [0.7726470601811286, 48.46965178808685], + [0.7726470601811286, 45.718470124797705], + [6.157258642562226, 45.718470124797705], + [6.157258642562226, 48.46965178808685], + [0.7726470601811286, 48.46965178808685], + ], + ], + type: "Polygon", + }, + }, + { + type: "Feature", + properties: { + cost: 7, + abatement: 7, + }, + geometry: { + coordinates: [ + [ + [18.520997774407675, 51.43117929808446], + [18.520997774407675, 47.08565668322254], + [25.385706207893833, 47.08565668322254], + [25.385706207893833, 51.43117929808446], + [18.520997774407675, 51.43117929808446], + ], + ], + type: "Polygon", + }, + }, + { + type: "Feature", + properties: { + cost: 8, + abatement: 8, + }, + geometry: { + coordinates: [ + [ + [35.91663289081157, 51.36524697256908], + [35.91663289081157, 45.31005648052533], + [45.92258788209065, 45.31005648052533], + [45.92258788209065, 51.36524697256908], + [35.91663289081157, 51.36524697256908], + ], + ], + type: "Polygon", + }, + }, + { + type: "Feature", + properties: { + cost: 9, + abatement: 9, + }, + geometry: { + coordinates: [ + [ + [-6.867226241868707, 54.62702931692684], + [-6.867226241868707, 51.419015757241226], + [2.883293358353882, 51.419015757241226], + [2.883293358353882, 54.62702931692684], + [-6.867226241868707, 54.62702931692684], + ], + ], + type: "Polygon", + }, + }, + { + type: "Feature", + properties: { + cost: 10, + abatement: 0, + }, + geometry: { + coordinates: [ + [ + [38.47505991918618, 37.280028551805856], + [38.47505991918618, 29.10048451439505], + [50.31049906445517, 29.10048451439505], + [50.31049906445517, 37.280028551805856], + [38.47505991918618, 37.280028551805856], + ], + ], + type: "Polygon", + }, + }, + ], + }; + + const costAbatementSource = { + id: "cost-abatement-source", + type: "geojson", + data: _data, + }; + + const maxCost = d3.max( + costAbatementSource.data.features, + (d) => d.properties.cost, + ); + const maxAbatement = d3.max( + costAbatementSource.data.features, + (d) => d.properties.abatement, + ); + + const COLOR_NUMBER = 2; + const colors = generateColorRamp(COLOR_NUMBER); + + const costAbatementLayer: FillLayerSpecification = { + id: "cost-abatement-layer", + type: "fill", + source: costAbatementSource.id, + paint: { + "fill-color": [ + "match", + [ + "concat", + [ + "ceil", + [ + "/", + ["*", ["/", ["get", "cost"], maxCost], 100], + 100 / COLOR_NUMBER, + ], + ], + [ + "ceil", + [ + "/", + ["*", ["/", ["get", "abatement"], maxAbatement], 100], + 100 / COLOR_NUMBER, + ], + ], + ], + ...colors, + "#FFF", + ], + "fill-opacity": 1, + }, + }; + + return ( + <> + <Source {...costAbatementSource} /> + <Layer {...costAbatementLayer} /> + </> + ); +} diff --git a/client/src/containers/projects/map/layers/projects/utils.ts b/client/src/containers/projects/map/layers/projects/utils.ts new file mode 100644 index 00000000..8282d577 --- /dev/null +++ b/client/src/containers/projects/map/layers/projects/utils.ts @@ -0,0 +1,35 @@ +export const MATRIX_COLORS: Record<string, string[]> = { + "#e8e8e8": ["00"], + "#e4acac": ["01"], + "#c85a5a": ["02"], + "#b0d5df": ["10"], + "#ad9ea5": ["11"], + "#985356": ["12"], + "#64acbe": ["20"], + "#627f8c": ["21"], + "#574249": ["22"], +}; + +export const generateColorRamp = function ( + COLOR_NUMBER: number = 3, + COLORS: Record<string, string[]> = MATRIX_COLORS, +) { + const colors = [...Array((COLOR_NUMBER + 1) * (COLOR_NUMBER + 1)).keys()]; + + return colors + .map((c, i) => { + const position = `${Math.floor((i / (COLOR_NUMBER + 1)) % (COLOR_NUMBER + 1))}${ + i % (COLOR_NUMBER + 1) + }`; + const color = Object.keys(COLORS).reduce((acc, k) => { + if (COLORS[k].includes(position) && !acc) { + return k; + } + + return acc; + }, ""); + + return [position, color]; + }) + .flat(); +}; diff --git a/client/src/containers/projects/map/legend/index.tsx b/client/src/containers/projects/map/legend/index.tsx new file mode 100644 index 00000000..964b1546 --- /dev/null +++ b/client/src/containers/projects/map/legend/index.tsx @@ -0,0 +1,21 @@ +import { PropsWithChildren } from "react"; + +import { cn } from "@/lib/utils"; + +export default function Legend({ + children, + className, +}: PropsWithChildren<{ + className?: HTMLDivElement["className"]; +}>) { + return ( + <div + className={cn( + "absolute bottom-8 right-16 rounded-2xl bg-blue-950 p-2 text-white", + className, + )} + > + {children} + </div> + ); +} diff --git a/client/src/containers/projects/map/legend/types/matrix.tsx b/client/src/containers/projects/map/legend/types/matrix.tsx new file mode 100644 index 00000000..9bbc1d88 --- /dev/null +++ b/client/src/containers/projects/map/legend/types/matrix.tsx @@ -0,0 +1,145 @@ +import React from "react"; + +export interface LegendMatrixIntersectionsProps { + intersections: Array<{ + id: number; + color: string; + }>; +} + +export interface LegendTypeProps { + className?: HTMLDivElement["className"]; +} + +export default function MatrixLegend({ + intersections = [], + colorNumber = 4, +}: LegendTypeProps & + LegendMatrixIntersectionsProps & { colorNumber?: number }) { + return ( + <div className="flex max-w-[250px] gap-3"> + <div> + <span>Abatement potential and cost $/tc02</span> + </div> + <div className="flex items-center space-x-14"> + <div className="relative w-20 flex-shrink-0 py-6 pl-5"> + <p + className="font-heading absolute bottom-7 left-0 rotate-180 transform text-xs font-medium text-white" + style={{ writingMode: "vertical-rl" }} + > + Cost + </p> + <p className="font-heading absolute bottom-1 left-1/2 -translate-x-1/2 transform text-xs font-medium text-white"> + Abatement + </p> + <div className="preserve-3d w-full transform"> + <div className="w-full" style={{ paddingBottom: "100%" }}> + <div className="absolute left-0 top-0 flex h-full w-full flex-wrap"> + {intersections.map((i) => ( + <div + key={i.id} + className="relative block" + style={{ + background: `${i.color}`, + width: `${100 / colorNumber}%`, + height: `${100 / colorNumber}%`, + }} + /> + ))} + </div> + + {/*<div className="font-heading text-xxs absolute bottom-0 left-full z-10 h-full w-2 transform justify-between text-white">*/} + {/* <div*/} + {/* className="absolute flex h-px items-center space-x-1 leading-none"*/} + {/* style={{ bottom: `${(100 / colorNumber) * 2}%` }}*/} + {/* >*/} + {/* <span className="relative top-px block h-px w-1 bg-gray-300" />*/} + {/* <span className="relative block -rotate-45 transform">*/} + {/* <span>10</span>*/} + {/* </span>*/} + {/* </div>*/} + {/* <div*/} + {/* className="absolute flex h-px items-center space-x-1 leading-none"*/} + {/* style={{ bottom: `${(100 / colorNumber) * 6}%` }}*/} + {/* >*/} + {/* <span className="relative top-px block h-px w-1 bg-gray-300" />*/} + {/* <span className="relative block -rotate-45 transform">*/} + {/* <span>50</span>*/} + {/* </span>*/} + {/* </div>*/} + {/* <div*/} + {/* className="absolute flex h-px items-center space-x-1 leading-none"*/} + {/* style={{ bottom: "100%" }}*/} + {/* >*/} + {/* <span className="relative top-px block h-px w-1 bg-gray-300" />*/} + {/* <span className="relative block -rotate-45 transform">*/} + {/* <span>100</span>*/} + {/* </span>*/} + {/* </div>*/} + {/*</div>*/} + + {/*<div className="font-heading text-xxs absolute -bottom-1 -left-1 z-10 h-full w-2 origin-bottom rotate-90 transform justify-between text-white">*/} + {/* <div*/} + {/* className="absolute flex h-px transform items-center space-x-1 leading-none"*/} + {/* style={{ bottom: `${100 - (100 / colorNumber) * 2}%` }}*/} + {/* >*/} + {/* <span className="relative top-px block h-px w-1 bg-gray-300" />*/} + {/* <span className="relative block -rotate-180 transform">*/} + {/* <span className="relative block rotate-45 transform">*/} + {/* 10*/} + {/* </span>*/} + {/* </span>*/} + {/* </div>*/} + {/* <div*/} + {/* className="absolute flex h-px transform items-center space-x-1 leading-none"*/} + {/* style={{ bottom: `${100 - (100 / colorNumber) * 6}%` }}*/} + {/* >*/} + {/* <span className="relative top-px block h-px w-1 bg-gray-300" />*/} + {/* <span className="relative block -rotate-180 transform">*/} + {/* <span className="relative block rotate-45 transform">*/} + {/* 50*/} + {/* </span>*/} + {/* </span>*/} + {/* </div>*/} + {/* <div*/} + {/* className="absolute flex h-px transform items-center space-x-1 leading-none"*/} + {/* style={{ bottom: "0%" }}*/} + {/* >*/} + {/* <span className="relative top-px block h-px w-1 bg-gray-300" />*/} + {/* <span className="relative block -rotate-180 transform">*/} + {/* <span className="relative block rotate-45 transform">*/} + {/* 100*/} + {/* </span>*/} + {/* </span>*/} + {/* </div>*/} + {/*</div>*/} + </div> + </div> + </div> + + {/*<div*/} + {/* className={cn({*/} + {/* [className]: !!className,*/} + {/* })}*/} + {/*>*/} + {/* <ul className="flex w-full flex-col space-y-2">*/} + {/* {items.map(({ value, color }) => (*/} + {/* <li*/} + {/* key={`${value}`}*/} + {/* className="font-heading flex items-center space-x-2 text-xs"*/} + {/* >*/} + {/* <div*/} + {/* className="h-2 w-2 flex-shrink-0 rounded-sm"*/} + {/* style={{*/} + {/* backgroundColor: color,*/} + {/* }}*/} + {/* />*/} + {/* <div className="clamp-2">{value}</div>*/} + {/* </li>*/} + {/* ))}*/} + {/* </ul>*/} + {/*</div>*/} + </div> + </div> + ); +} diff --git a/client/tsconfig.json b/client/tsconfig.json index 83f6e899..4de67b8c 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "../tsconfig.json", "compilerOptions": { + "target": "ES6", "lib": [ "dom", "dom.iterable", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39aff3f2..307585b7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -321,6 +321,9 @@ importers: clsx: specifier: 2.1.1 version: 2.1.1 + d3: + specifier: 7.9.0 + version: 7.9.0 framer-motion: specifier: 11.11.9 version: 11.11.9(@emotion/is-prop-valid@1.3.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -330,6 +333,9 @@ importers: lucide-react: specifier: 0.447.0 version: 0.447.0(react@18.3.1) + mapbox-expression: + specifier: 0.0.3 + version: 0.0.3(mapbox-gl@3.7.0) mapbox-gl: specifier: 3.7.0 version: 3.7.0 @@ -361,6 +367,12 @@ importers: specifier: 'catalog:' version: 3.23.8 devDependencies: + '@types/d3': + specifier: 7.4.3 + version: 7.4.3 + '@types/geojson': + specifier: 7946.0.14 + version: 7946.0.14 '@types/mapbox-gl': specifier: 3.4.0 version: 3.4.0 @@ -3062,6 +3074,99 @@ packages: '@types/cookiejar@2.1.5': resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} + '@types/d3-array@3.2.1': + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.6': + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.0': + resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.0.3': + resolution: {integrity: sha512-laXM4+1o5ImZv3RpFAsTRn3TEkzqkytiOY0Dz0sq5cnd1dtNlk6sHLon4OvqaiJb28T0S/TdsBI3Sjsy+keJrw==} + + '@types/d3-scale@4.0.8': + resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.6': + resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.3': + resolution: {integrity: sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -3938,6 +4043,10 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + commander@9.5.0: resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} engines: {node: ^12.20.0 || >=14} @@ -4066,6 +4175,133 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -4143,6 +4379,9 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -4883,6 +5122,10 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -4931,6 +5174,10 @@ packages: resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} engines: {node: '>= 0.4'} + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} @@ -5552,6 +5799,11 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + mapbox-expression@0.0.3: + resolution: {integrity: sha512-P2hiPXPxXzmOTZUP2zLa+kjN42QbvAM125tH/akt+hdOOu4QgxAvXGcffiKMLVxOFE28vceD8Qc11gWUbnkc/A==} + peerDependencies: + mapbox-gl: ^1.0 + mapbox-gl@3.7.0: resolution: {integrity: sha512-dCbVyH1uGobwv6f4QKRv2Z2wuVT/RmspsudK3sTxGRFxZi6Pd2P9axdbVyZpmGddCAREy44pHhvzvO0qgpdKAg==} @@ -6655,6 +6907,9 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rollup-plugin-esbuild-minify@1.1.2: resolution: {integrity: sha512-l8s3ggesd6WVpi7GPQG/X5MMhwg9thEQLRrsjO6X7xQMkKMxmmjm1NTunQid4pcIKcPYJdAkPwSo2vbI2Itf8Q==} engines: {node: '>= 14.18'} @@ -10893,6 +11148,123 @@ snapshots: '@types/cookiejar@2.1.5': {} + '@types/d3-array@3.2.1': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.14 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.6': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.14 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.0': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.0.3': {} + + '@types/d3-scale@4.0.8': + dependencies: + '@types/d3-time': 3.0.3 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.6': + dependencies: + '@types/d3-path': 3.1.0 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.3': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.0 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.8 + '@types/d3-scale-chromatic': 3.0.3 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.6 + '@types/d3-time': 3.0.3 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + '@types/estree@1.0.5': {} '@types/estree@1.0.6': {} @@ -12015,6 +12387,8 @@ snapshots: commander@4.1.1: {} + commander@7.2.0: {} + commander@9.5.0: {} comment-json@4.2.3: @@ -12143,6 +12517,158 @@ snapshots: csstype@3.1.3: {} + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.0: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + damerau-levenshtein@1.0.8: {} data-view-buffer@1.0.1: @@ -12228,6 +12754,10 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + delayed-stream@1.0.0: {} delegates@1.0.0: {} @@ -13243,6 +13773,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore-by-default@1.0.1: {} @@ -13314,6 +13848,8 @@ snapshots: hasown: 2.0.2 side-channel: 1.0.6 + internmap@2.0.3: {} + invariant@2.2.4: dependencies: loose-envify: 1.4.0 @@ -14110,6 +14646,10 @@ snapshots: dependencies: tmpl: 1.0.5 + mapbox-expression@0.0.3(mapbox-gl@3.7.0): + dependencies: + mapbox-gl: 3.7.0 + mapbox-gl@3.7.0: dependencies: '@mapbox/jsonlint-lines-primitives': 2.0.2 @@ -15202,6 +15742,8 @@ snapshots: dependencies: glob: 7.2.3 + robust-predicates@3.0.2: {} + rollup-plugin-esbuild-minify@1.1.2(rollup@4.24.0): dependencies: esbuild: 0.23.1