Skip to content

Commit

Permalink
Clean up counties. Still WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jayvarner committed Nov 15, 2024
1 parent ffae7f2 commit ac76380
Show file tree
Hide file tree
Showing 7 changed files with 3,219 additions and 41 deletions.
86 changes: 59 additions & 27 deletions app/components/mapping/Counties.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import { counties } from "~/config";
import { MapContext } from "~/contexts";
import { ClientOnly } from "remix-utils/client-only";
import PlacePopup from "../PlacePopup";
import { counties as countyStyle } from "~/mapStyles";
import type { MapGeoJSONFeature, MapMouseEvent } from "maplibre-gl";
import type { TPlace } from "~/types";
import type { TCounty } from "~/types";

const Counties = () => {
const Counties = ({ counties }: { counties: TCounty[] }) => {
const { map } = useContext(MapContext);
const hoveredId = useRef<string | undefined>(undefined);
const [activeCounty, setActiveCounty] = useState<TPlace | undefined>(
const [activeCounty, setActiveCounty] = useState<string | undefined>(
undefined
);
const [popupLocation, setPopupLocation] = useState<{
lat: number;
lon: number;
}>({ lat: 0, lon: 0 });

const handleMouseEnter = useCallback(
({ features }: MapMouseEvent & { features?: MapGeoJSONFeature[] }) => {
if (map) {
map.getCanvas().style.cursor = "pointer";
if (features && features.length > 0) {
for (const feature of features) {
if (hoveredId.current !== feature.id) {
map.setFeatureState(
{ source: "counties", id: hoveredId.current },
{ hovered: false }
);
}
// setActiveCounty((county) => {
// if (feature && county !== feature.properties.name)
// return undefined;
// return county;
// });
hoveredId.current = feature.properties.uuid;
map.setFeatureState(
{ source: "counties", id: feature.properties.uuid },
{ source: "counties", id: feature.id },
{ hovered: true }
);
}
Expand All @@ -38,46 +54,62 @@ const Counties = () => {
{ hovered: false }
);
hoveredId.current = undefined;
setActiveCounty(undefined);
}
}, [map]);

// const handleClick = useCallback(
// (
// event: MapMouseEvent & {
// features?: MapGeoJSONFeature[];
// }
// ) => {
// if (!map && !event.features) return;
// const clickedIsland = islands.find((island: TPlace) => {
// if (event.features)
// return island.name === event.features[0].properties.name;
// return undefined;
// });
// setActiveCounty(clickedIsland);
// },
// [map, islands]
// );
const handleClick = useCallback(
({
features,
lngLat,
}: MapMouseEvent & { features?: MapGeoJSONFeature[] }) => {
setPopupLocation({ lon: lngLat.lng, lat: lngLat.lat });
if (!map) return;
if (features && features.length > 0)
setActiveCounty(features[0].properties.name);
},
[map]
);

useEffect(() => {
if (!map) return;
for (const countyLayer of countyStyle.layers) {
map.setLayoutProperty(countyLayer.id, "visibility", "visible");
}

map.on("mouseenter", "counties-fill", handleMouseEnter);
map.on("mousemove", "counties-fill", handleMouseEnter);
map.on("mouseleave", "counties-fill", handleMouseLeave);
// map.on("click", "counties-fill", handleClick);
map.on("click", "counties-fill", handleClick);

return () => {
for (const countyLayer of countyStyle.layers) {
map.setLayoutProperty(countyLayer.id, "visibility", "none");
}
map.off("mouseenter", "counties-fill", handleMouseEnter);
map.off("mousemove", "counties-fill", handleMouseEnter);
map.off("mouseleave", "counties-fill", handleMouseLeave);
// map.off("click", "counties-fill", handleClick);
map.off("click", "counties-fill", handleClick);
};
}, [map, handleMouseEnter, handleMouseLeave]);
return <></>;
}, [map, handleMouseEnter, handleMouseLeave, handleClick]);
return (
<>
{counties.map((county) => {
return (
<ClientOnly key={county.uuid}>
{() => (
<PlacePopup
show={activeCounty === county.name}
onClose={() => setActiveCounty(undefined)}
zoomToFeature={false}
location={popupLocation}
>
<h4 className="text-xl">{county.name}</h4>
</PlacePopup>
)}
</ClientOnly>
);
})}
</>
);
};

export default Counties;
11 changes: 9 additions & 2 deletions app/components/mapping/Islands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ const Islands = ({ islands }: Props) => {
map.getCanvas().style.cursor = "pointer";
if (features && features.length > 0) {
for (const feature of features) {
if (hoveredId.current !== feature.id) {
map.setFeatureState(
{ source: "islands", id: hoveredId.current },
{ hovered: false }
);
}
hoveredId.current = feature.properties.uuid;
map.setFeatureState(
{ source: "islands", id: feature.properties.uuid },
Expand All @@ -37,6 +43,7 @@ const Islands = ({ islands }: Props) => {
);

const handleMouseLeave = useCallback(() => {
console.log("leave island");
if (map) {
map.getCanvas().style.cursor = "";
map.setFeatureState(
Expand Down Expand Up @@ -71,15 +78,15 @@ const Islands = ({ islands }: Props) => {
map.setLayoutProperty(islandLayer.id, "visibility", "visible");
}

map.on("mouseenter", "islands-fill", handleMouseEnter);
map.on("mousemove", "islands-fill", handleMouseEnter);
map.on("mouseleave", "islands-fill", handleMouseLeave);
map.on("click", "islands-fill", handleClick);

return () => {
for (const islandLayer of islandStyle.layers) {
map.setLayoutProperty(islandLayer.id, "visibility", "none");
}
map.off("mouseenter", "islands-fill", handleMouseEnter);
map.off("mousemove", "islands-fill", handleMouseEnter);
map.off("mouseleave", "islands-fill", handleMouseLeave);
map.off("click", "islands-fill", handleClick);
};
Expand Down
12 changes: 6 additions & 6 deletions app/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,10 +465,10 @@ export const defaultBounds = () => {
};

export const counties: TCounty[] = [
{ name: "Bryan", id: "8fa8c48f-4eb6-5471-9d9f-dad09d0e7cb3" },
{ name: "Camden", id: "66bc87d3-4ae2-5b56-b2b4-f9146acce491" },
{ name: "Chatham", id: "43214e18-2a16-5d8a-a5a4-8db55479e3e2" },
{ name: "Glynn", id: "d6375cd7-a126-534d-a661-951fc482ce63" },
{ name: "Liberty", id: "2f0676be-462b-509e-8bb2-1cf287840f6f" },
{ name: "McIntosh", id: "4ca467df-916d-5a9e-86a4-263fc35b2a7b" },
{ name: "Bryan", uuid: "8fa8c48f-4eb6-5471-9d9f-dad09d0e7cb3" },
{ name: "Camden", uuid: "66bc87d3-4ae2-5b56-b2b4-f9146acce491" },
{ name: "Chatham", uuid: "43214e18-2a16-5d8a-a5a4-8db55479e3e2" },
{ name: "Glynn", uuid: "d6375cd7-a126-534d-a661-951fc482ce63" },
{ name: "Liberty", uuid: "2f0676be-462b-509e-8bb2-1cf287840f6f" },
{ name: "McIntosh", uuid: "4ca467df-916d-5a9e-86a4-263fc35b2a7b" },
];
22 changes: 22 additions & 0 deletions app/data/coredata.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
coreDataRelatedEndpoints,
countyIndexCollection,
dataHosts,
indexCollection,
keys,
Expand All @@ -11,6 +12,7 @@ import type {
TESHit,
TPlaceGeoJSON,
TSearchOptions,
TCounty,
} from "~/types";

const elasticSearchHeaders = () => {
Expand Down Expand Up @@ -121,6 +123,26 @@ export const fetchPlaceBySlug = async (slug: string | undefined) => {
return place;
};

export const fetchCounties = async () => {
const body = {
_source: {
includes: ["name", "location"],
},
};
const response = await fetch(
`${dataHosts.elasticSearch}/${countyIndexCollection}/_search`,
{
method: "POST",
body: JSON.stringify(body),
headers: elasticSearchHeaders(),
}
);

const data = await response.json();
const counties: TCounty[] = data.hits.hits.map((hit: TESHit) => hit._source);
return counties;
};

export const fetchPlacesByType = async (type: string) => {
const body = {
query: {
Expand Down
11 changes: 6 additions & 5 deletions app/routes/explore.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { useContext, useState, useEffect, Suspense } from "react";
import { MapContext } from "~/contexts";
import { useLoaderData, defer, useNavigation } from "@remix-run/react";
import { fetchPlacesByType } from "~/data/coredata";
import { fetchCounties, fetchPlacesByType } from "~/data/coredata";
import IntroModal from "~/components/layout/IntroModal";
import Loading from "~/components/layout/Loading";
import { defaultBounds, topBarHeight } from "~/config";
import type { TPlace } from "~/types";
import type { TCounty, TPlace } from "~/types";
import type { LoaderFunction } from "@remix-run/node";
import Counties from "~/components/mapping/Counties";
import Islands from "~/components/mapping/Islands";

export const loader: LoaderFunction = async () => {
const islands: TPlace[] = await fetchPlacesByType("Barrier Island");
return defer({ islands });
const counties: TCounty[] = await fetchCounties();
return defer({ islands, counties });
};

export const HydrateFallback = () => {
Expand All @@ -22,7 +23,7 @@ export const HydrateFallback = () => {
const Explore = () => {
const { map } = useContext(MapContext);
const [isModalOpen, setIsModalOpen] = useState<boolean>(true); // Modal state
const { islands } = useLoaderData<typeof loader>();
const { islands, counties } = useLoaderData<typeof loader>();
const navigation = useNavigation();

useEffect(() => {
Expand All @@ -36,7 +37,7 @@ const Explore = () => {
>
{isModalOpen && <IntroModal setIsOpen={setIsModalOpen} />}{" "}
<Suspense fallback={<Loading />}>
<Counties />
<Counties counties={counties} />
<Islands islands={islands} />
</Suspense>
</div>
Expand Down
6 changes: 5 additions & 1 deletion app/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,11 @@ export type TESHit = {

export type TCounty = {
name: string;
id: string;
uuid: string;
location?: {
lon: number;
lat: number;
};
};

export type TSearchFilter = {
Expand Down
Loading

0 comments on commit ac76380

Please sign in to comment.