/* eslint-disable no-unused-vars */ // External Libs: import React, {useRef, useState, useMemo} from 'react'; import {Map, MapboxGeoJSONFeature, LngLatBoundsLike} from 'maplibre-gl'; import ReactMapGL, { MapEvent, ViewportProps, WebMercatorViewport, NavigationControl, GeolocateControl, Popup, FlyToInterpolator, FullscreenControl, MapRef, Source, Layer} from 'react-map-gl'; import bbox from '@turf/bbox'; import * as d3 from 'd3-ease'; import {isMobile} from 'react-device-detect'; import {Grid} from '@trussworks/react-uswds'; import {useWindowSize} from 'react-use'; // Contexts: import {useFlags} from '../contexts/FlagContext'; // Components: import AreaDetail from './AreaDetail'; import MapInfoPanel from './mapInfoPanel'; import MapSearch from './MapSearch'; import TerritoryFocusControl from './territoryFocusControl'; // Styles and constants import {makeMapStyle} from '../data/mapStyle'; import 'maplibre-gl/dist/maplibre-gl.css'; import * as constants from '../data/constants'; import * as styles from './J40Map.module.scss'; declare global { interface Window { Cypress?: object; underlyingMap: Map; } } interface IJ40Interface { location: Location; }; export interface IDetailViewInterface { latitude: number longitude: number zoom: number properties: constants.J40Properties, }; const J40Map = ({location}: IJ40Interface) => { // Hash portion of URL is of the form #zoom/lat/lng const [zoom, lat, lng] = location.hash.slice(1).split('/'); const [viewport, setViewport] = useState({ latitude: lat && parseFloat(lat) || constants.DEFAULT_CENTER[0], longitude: lng && parseFloat(lng) || constants.DEFAULT_CENTER[1], zoom: zoom && parseFloat(zoom) || constants.GLOBAL_MIN_ZOOM, }); const [selectedFeature, setSelectedFeature] = useState(); const [detailViewData, setDetailViewData] = useState(); const [transitionInProgress, setTransitionInProgress] = useState(false); const [geolocationInProgress, setGeolocationInProgress] = useState(false); const [isMobileMapState, setIsMobileMapState] = useState(false); const {width: windowWidth} = useWindowSize(); const mapRef = useRef(null); const flags = useFlags(); const selectedFeatureId = (selectedFeature && selectedFeature.id) || ''; const filter = useMemo(() => ['in', constants.GEOID_PROPERTY, selectedFeatureId], [selectedFeature]); const onClick = (event: MapEvent) => { const feature = event.features && event.features[0]; if (feature) { const [minLng, minLat, maxLng, maxLat] = bbox(feature); const newViewPort = new WebMercatorViewport({height: viewport.height!, width: viewport.width!}); const {longitude, latitude, zoom} = newViewPort.fitBounds( [ [minLng, minLat], [maxLng, maxLat], ], { padding: 40, }, ); if (feature.id !== selectedFeatureId) { setSelectedFeature(feature); console.log(feature.properties); } else { setSelectedFeature(undefined); } const popupInfo = { longitude: longitude, latitude: latitude, zoom: zoom, properties: feature.properties, }; goToPlace([ [minLng, minLat], [maxLng, maxLat], ]); setDetailViewData(popupInfo); } }; const onLoad = () => { if (typeof window !== 'undefined' && window.Cypress && mapRef.current) { window.underlyingMap = mapRef.current.getMap(); } if (isMobile) setIsMobileMapState(true); }; const goToPlace = (bounds: LngLatBoundsLike ) => { const {longitude, latitude, zoom} = new WebMercatorViewport({height: viewport.height!, width: viewport.width!}) .fitBounds(bounds as [[number, number], [number, number]], { padding: 20, offset: [0, -100], }); setViewport({ ...viewport, longitude, latitude, zoom, transitionDuration: 1000, transitionInterpolator: new FlyToInterpolator(), transitionEasing: d3.easeCubic, }); }; const onTransitionStart = () => { setTransitionInProgress(true); }; const onTransitionEnd = () => { setTransitionInProgress(false); }; const onGeolocate = () => { setGeolocationInProgress(false); }; const onClickGeolocate = () => { setGeolocationInProgress(true); }; return ( <> {/* The MapSearch component is no longer wrapped in a div in order to allow this feature to be behind a feature flag. This was causing a bug for MapSearch to render correctly in a production build. Leaving this comment here in case future flags are needed in this component When the MapSearch component is placed behind a feature flag without a div wrapping MapSearch, the production build will inject CSS due to the null in the false conditional case. Any changes to this (ie, changes to MapSearch or removing feature flag, etc), should be tested with a production build via: npm run clean && npm run build && npm run serve to ensure the production build works and that MapSearch and the map (ReactMapGL) render correctly. */} {('fs' in flags && detailViewData && !transitionInProgress) && ( )} {'gl' in flags ? : ''} {geolocationInProgress ?
Geolocation in progress...
: ''} {'fs' in flags ? :'' }
); }; export default J40Map;