diff --git a/app/src/frontend/map/map.tsx b/app/src/frontend/map/map.tsx index 095730ec..eb97df00 100644 --- a/app/src/frontend/map/map.tsx +++ b/app/src/frontend/map/map.tsx @@ -1,210 +1,209 @@ import React, { - FC, - useCallback, - useEffect, - useMemo, - useState, - useRef, - } from "react"; - import { - AttributionControl, - MapContainer, - ZoomControl, - useMapEvent, - Pane, - useMap, - } from "react-leaflet"; - - import 'leaflet/dist/leaflet.css'; - import "./map.css"; - - import { apiGet } from "../apiHelpers"; - import { - initialMapViewport, - mapBackgroundColor, - MapTheme, - LayerEnablementState, - } from "../config/map-config"; - - import mapboxgl from "mapbox-gl"; - - import { Building } from "../models/building"; - - import { CityMap } from "./layers/city-base-map-layer"; - import { CityBoundaryLayer } from "./layers/city-boundary-layer"; - import { BoroughBoundaryLayer } from "./layers/borough-boundary-layer"; - import { BoroughLabelLayer } from "./layers/borough-label-layer"; - import { ParcelBoundaryLayer } from "./layers/parcel-boundary-layer"; - import { HistoricDataLayer } from "./layers/historic-data-layer"; - import { HistoricMapLayer } from "./layers/historic-map-layer"; - import { FloodBoundaryLayer } from "./layers/flood-boundary-layer"; - import { ConservationAreaBoundaryLayer } from "./layers/conservation-boundary-layer"; - import { VistaBoundaryLayer } from "./layers/vista-boundary-layer"; - import { HousingBoundaryLayer } from "./layers/housing-boundary-layer"; - import { CreativeBoundaryLayer } from "./layers/creative-boundary-layer"; - import { BuildingBaseLayer } from "./layers/building-base-layer"; - import { BuildingDataLayer } from "./layers/building-data-layer"; - import { BuildingNumbersLayer } from "./layers/building-numbers-layer"; - import { BuildingHighlightLayer } from "./layers/building-highlight-layer"; - - import { Legend } from "./legend"; - import SearchBox from "./search-box"; - import ThemeSwitcher from "./theme-switcher"; - import DataLayerSwitcher from "./data-switcher"; - import { BoroughSwitcher } from "./borough-switcher"; - import { ParcelSwitcher } from "./parcel-switcher"; - import { FloodSwitcher } from "./flood-switcher"; - import { ConservationAreaSwitcher } from "./conservation-switcher"; - import { HistoricDataSwitcher } from "./historic-data-switcher"; - import { HistoricMapSwitcher } from "./historic-map-switcher"; - import { VistaSwitcher } from "./vista-switcher"; - import { CreativeSwitcher } from "./creative-switcher"; - import { HousingSwitcher } from "./housing-switcher"; - import { BuildingMapTileset } from "../config/tileserver-config"; - import { useDisplayPreferences } from "../displayPreferences-context"; - import { CategoryMapDefinition } from "../config/category-maps-config"; - - mapboxgl.accessToken = - "pk.eyJ1IjoiYWxpLWFkbGkiLCJhIjoiY2xuM2JtYjV1MGE5djJrb2d5OGp1ZWNyNiJ9.gENyP4xX6ElLAeZFlE0aDg"; - - interface ColouringMapProps { - selectedBuildingId: number; - mode: "basic" | "view" | "edit" | "multi-edit"; - revisionId: string; - onBuildingAction: (building: Building) => void; - mapColourScale: BuildingMapTileset; - onMapColourScale: (x: BuildingMapTileset) => void; - categoryMapDefinitions: CategoryMapDefinition[]; - } - - export const ColouringMap: FC = ({ - mode, - revisionId, - onBuildingAction, - selectedBuildingId, - mapColourScale, - onMapColourScale, - categoryMapDefinitions, - children, - }) => { - const { darkLightTheme, darkLightThemeSwitch, showLayerSelection } = - useDisplayPreferences(); - const [position, setPosition] = useState(initialMapViewport.position); - const [zoom, setZoom] = useState(initialMapViewport.zoom); - - const handleLocate = useCallback((lat: number, lng: number, zoom: number) => { - setPosition([lat, lng]); - setZoom(zoom); - }, []); - - const handleClick = useCallback( - async (e) => { - const { lat, lng } = e.latlng; - const data = await apiGet(`/api/buildings/locate?lat=${lat}&lng=${lng}`); - const building = data?.[0]; - onBuildingAction(building); - }, - [onBuildingAction] - ); - - const mapContainer = useRef(null); - const map = useRef(null); - const [lng, setLng] = useState(-73.5801403); - const [lat, setLat] = useState(45.4962261); - - useEffect(() => { - if (map.current) return; // initialize map only once - map.current = new mapboxgl.Map({ - container: mapContainer.current, - style: "mapbox://styles/mapbox/streets-v12", - center: [lng, lat], - zoom: zoom, - }); - - map.current.addControl(new mapboxgl.NavigationControl()); - - map.current.on("move", () => { - setLng(map.current.getCenter().lng.toFixed(4)); - setLat(map.current.getCenter().lat.toFixed(4)); - setZoom(map.current.getZoom().toFixed(2)); - }); + FC, + useCallback, + useEffect, + useMemo, + useState, + useRef, +} from "react"; +import { + AttributionControl, + MapContainer, + ZoomControl, + useMapEvent, + Pane, + useMap, +} from "react-leaflet"; + +import "leaflet/dist/leaflet.css"; +import "./map.css"; + +import { apiGet } from "../apiHelpers"; +import { + initialMapViewport, + mapBackgroundColor, + MapTheme, + LayerEnablementState, +} from "../config/map-config"; + +import mapboxgl from "mapbox-gl"; + +import { Building } from "../models/building"; + +import { CityMap } from "./layers/city-base-map-layer"; +import { CityBoundaryLayer } from "./layers/city-boundary-layer"; +import { BoroughBoundaryLayer } from "./layers/borough-boundary-layer"; +import { BoroughLabelLayer } from "./layers/borough-label-layer"; +import { ParcelBoundaryLayer } from "./layers/parcel-boundary-layer"; +import { HistoricDataLayer } from "./layers/historic-data-layer"; +import { HistoricMapLayer } from "./layers/historic-map-layer"; +import { FloodBoundaryLayer } from "./layers/flood-boundary-layer"; +import { ConservationAreaBoundaryLayer } from "./layers/conservation-boundary-layer"; +import { VistaBoundaryLayer } from "./layers/vista-boundary-layer"; +import { HousingBoundaryLayer } from "./layers/housing-boundary-layer"; +import { CreativeBoundaryLayer } from "./layers/creative-boundary-layer"; +import { BuildingBaseLayer } from "./layers/building-base-layer"; +import { BuildingDataLayer } from "./layers/building-data-layer"; +import { BuildingNumbersLayer } from "./layers/building-numbers-layer"; +import { BuildingHighlightLayer } from "./layers/building-highlight-layer"; + +import { Legend } from "./legend"; +import SearchBox from "./search-box"; +import ThemeSwitcher from "./theme-switcher"; +import DataLayerSwitcher from "./data-switcher"; +import { BoroughSwitcher } from "./borough-switcher"; +import { ParcelSwitcher } from "./parcel-switcher"; +import { FloodSwitcher } from "./flood-switcher"; +import { ConservationAreaSwitcher } from "./conservation-switcher"; +import { HistoricDataSwitcher } from "./historic-data-switcher"; +import { HistoricMapSwitcher } from "./historic-map-switcher"; +import { VistaSwitcher } from "./vista-switcher"; +import { CreativeSwitcher } from "./creative-switcher"; +import { HousingSwitcher } from "./housing-switcher"; +import { BuildingMapTileset } from "../config/tileserver-config"; +import { useDisplayPreferences } from "../displayPreferences-context"; +import { CategoryMapDefinition } from "../config/category-maps-config"; + +mapboxgl.accessToken = + "pk.eyJ1IjoiYWxpLWFkbGkiLCJhIjoiY2xuM2JtYjV1MGE5djJrb2d5OGp1ZWNyNiJ9.gENyP4xX6ElLAeZFlE0aDg"; + +interface ColouringMapProps { + selectedBuildingId: number; + mode: "basic" | "view" | "edit" | "multi-edit"; + revisionId: string; + onBuildingAction: (building: Building) => void; + mapColourScale: BuildingMapTileset; + onMapColourScale: (x: BuildingMapTileset) => void; + categoryMapDefinitions: CategoryMapDefinition[]; +} + +export const ColouringMap: FC = ({ + mode, + revisionId, + onBuildingAction, + selectedBuildingId, + mapColourScale, + onMapColourScale, + categoryMapDefinitions, + children, +}) => { + const { darkLightTheme, darkLightThemeSwitch, showLayerSelection } = + useDisplayPreferences(); + const [position, setPosition] = useState(initialMapViewport.position); + const [zoom, setZoom] = useState(initialMapViewport.zoom); + + const handleLocate = useCallback((lat: number, lng: number, zoom: number) => { + setPosition([lat, lng]); + setZoom(zoom); + }, []); + + const handleClick = useCallback( + async (e) => { + const { lat, lng } = e.latlng; + const data = await apiGet(`/api/buildings/locate?lat=${lat}&lng=${lng}`); + const building = data?.[0]; + onBuildingAction(building); + }, + [onBuildingAction] + ); + + const mapContainer = useRef(null); + const map = useRef(null); + const [lng, setLng] = useState(-73.5801403); + const [lat, setLat] = useState(45.4962261); + + useEffect(() => { + if (map.current) return; // initialize map only once + map.current = new mapboxgl.Map({ + container: mapContainer.current, + style: "mapbox://styles/mapbox/streets-v12", + center: [lng, lat], + zoom: zoom, }); - - return ( -
- {mode !== "basic" && ( - <> - - - - {showLayerSelection == "enabled" ? ( - <> - - - - - - - - - - - ) : ( - <> - )} - {/* TODO change remaining ones*/} - - - )} -
- ); - }; - - function ClickHandler({ onClick }: { onClick: (e) => void }) { - useMapEvent("click", (e) => onClick(e)); - - return null; - } - - function MapBackgroundColor({ theme }: { theme: MapTheme }) { - const map = useMap(); - useEffect(() => { - map.getContainer().style.backgroundColor = mapBackgroundColor[theme]; + + map.current.addControl(new mapboxgl.NavigationControl()); + + map.current.on("move", () => { + setLng(map.current.getCenter().lng.toFixed(4)); + setLat(map.current.getCenter().lat.toFixed(4)); + setZoom(map.current.getZoom().toFixed(2)); }); - - return null; - } - - function MapViewport({ - position, - zoom, - }: { - position: [number, number]; - zoom: number; - }) { - const map = useMap(); - - useEffect(() => { - map.setView(position, zoom); - }, [position, zoom]); - - return null; - } - \ No newline at end of file + }, []); + + return ( +
+ {mode !== "basic" && ( + <> + + + + {showLayerSelection == "enabled" ? ( + <> + + + + + + + + + + + ) : ( + <> + )} + {/* TODO change remaining ones*/} + + + )} +
+ ); +}; + +function ClickHandler({ onClick }: { onClick: (e) => void }) { + useMapEvent("click", (e) => onClick(e)); + + return null; +} + +function MapBackgroundColor({ theme }: { theme: MapTheme }) { + const map = useMap(); + useEffect(() => { + map.getContainer().style.backgroundColor = mapBackgroundColor[theme]; + }); + + return null; +} + +function MapViewport({ + position, + zoom, +}: { + position: [number, number]; + zoom: number; +}) { + const map = useMap(); + + useEffect(() => { + map.setView(position, zoom); + }, [position, zoom]); + + return null; +}