Fix territory shortcuts when census tract is selected (#1082)

* Refactor map click event architecture

- combine territory map clickHandlers
- centers AS on the map

* Center US on the map

- make the east and west coast both viewable
- make clicking on the 48, show the same zoom/lat/long as initial map
- centers Hawaii on map

* Update link to map performance

* Explicitly show links as the links return a 403

* Removes link and spells link out
This commit is contained in:
Vim 2021-12-28 18:30:22 -05:00 committed by GitHub
commit 356e16950f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 223 additions and 167 deletions

View file

@ -28,6 +28,7 @@ export interface indicatorInfo {
const AreaDetail = ({properties}:IAreaDetailProps) => {
const intl = useIntl();
// console.log the properties of the census that is selected:
console.log("Area Detail properies: ", properties);
const score = properties[constants.SCORE_PROPERTY_HIGH] ? properties[constants.SCORE_PROPERTY_HIGH] as number : 0;
@ -38,10 +39,6 @@ const AreaDetail = ({properties}:IAreaDetailProps) => {
const isCommunityFocus = score >= constants.SCORE_BOUNDARY_PRIORITIZED;
// const sidePanelFeedbackHref = `
// mailto:screeningtool.feedback@usds.gov?subject=Feedback on Census Tract: ${blockGroup}
// `;
// Define each indicator in the side panel with constants from copy file (for intl)
// Indicators are grouped by category
const expAgLoss:indicatorInfo = {
@ -382,8 +379,9 @@ const AreaDetail = ({properties}:IAreaDetailProps) => {
totalCount: constants.TOTAL_NUMBER_OF_INDICATORS,
}}/>
</div>
{/* eslint-disable-next-line max-len */}
{/* <a className={styles.feedbackLink} href={sidePanelFeedbackHref}>{EXPLORE_COPY.COMMUNITY.SEND_FEEDBACK}</a> */}
{/* <a className={styles.feedbackLink} href={sidePanelFeedbackHref}>
{EXPLORE_COPY.COMMUNITY.SEND_FEEDBACK}
</a> */}
</div>

View file

@ -1,3 +1,4 @@
/* eslint-disable valid-jsdoc */
/* eslint-disable no-unused-vars */
// External Libs:
import React, {useRef, useState, useMemo} from 'react';
@ -55,12 +56,23 @@ export interface IDetailViewInterface {
const J40Map = ({location}: IJ40Interface) => {
// Hash portion of URL is of the form #zoom/lat/lng
/**
* Initializes the zoom, and the map's center point (lat, lng) via the URL hash #{z}/{lat}/{long}
* where:
* z = zoom
* lat = map center's latitude
* long = map center's longitude
*/
const [zoom, lat, lng] = location.hash.slice(1).split('/');
/**
* If the URL has no #{z}/{lat}/{long} specified in the hash, then set the map's intial viewport state
* to use constants. This is so that we can load URLs with certain zoom/lat/long specified:
*/
const [viewport, setViewport] = useState<ViewportProps>({
latitude: lat && parseFloat(lat) || constants.DEFAULT_CENTER[0],
longitude: lng && parseFloat(lng) || constants.DEFAULT_CENTER[1],
zoom: zoom && parseFloat(zoom) || constants.GLOBAL_MIN_ZOOM,
latitude: lat && parseFloat(lat) ? parseFloat(lat) : constants.DEFAULT_CENTER[0],
longitude: lng && parseFloat(lng) ? parseFloat(lng) : constants.DEFAULT_CENTER[1],
zoom: zoom && parseFloat(zoom) ? parseFloat(zoom) : constants.GLOBAL_MIN_ZOOM,
});
const [selectedFeature, setSelectedFeature] = useState<MapboxGeoJSONFeature>();
@ -76,37 +88,102 @@ const J40Map = ({location}: IJ40Interface) => {
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);
/**
* This function will return the bounding box of the current map. Comment in when needed.
* {
* _ne: {lng:number, lat:number}
* _sw: {lng:number, lat:number}
* }
* @returns {LngLatBounds}
*/
const getCurrentMapBoundingBox = () => {
return mapRef.current ? console.log('mapRef getBounds(): ', mapRef.current.getMap().getBounds()) : null;
};
/**
* This onClick event handler will listen and handle clicks on the map. It will listen for clicks on the
* territory controls and it will listen to clicks on the map.
*
* It will NOT listen to clicks into the search field or the zoom controls. These clickHandlers are
* captured in their own respective components.
*/
const onClick = (event: MapEvent | React.MouseEvent<HTMLButtonElement>) => {
// Stop all propagation / bubbling / capturing
event.preventDefault();
event.stopPropagation();
getCurrentMapBoundingBox();
// Check if the click is for territories. Given the territories component's design, it can be
// guaranteed that each territory control will have an id. We use this ID to determine
// if the click is coming from a territory control
if (event.target && (event.target as HTMLElement).id) {
const buttonID = event.target && (event.target as HTMLElement).id;
switch (buttonID) {
case '48':
goToPlace(constants.LOWER_48_BOUNDS);
break;
case 'AK':
goToPlace(constants.ALASKA_BOUNDS);
break;
case 'HI':
goToPlace(constants.HAWAII_BOUNDS);
break;
case 'PR':
goToPlace(constants.PUERTO_RICO_BOUNDS);
break;
case 'GU':
goToPlace(constants.GUAM_BOUNDS);
break;
case 'AS':
goToPlace(constants.AMERICAN_SAMOA_BOUNDS);
break;
case 'MP':
goToPlace(constants.MARIANA_ISLAND_BOUNDS);
break;
case 'VI':
goToPlace(constants.US_VIRGIN_ISLANDS_BOUNDS);
break;
default:
break;
}
} else {
// This else clause will fire when the ID is null or empty. This is the case where the map is clicked
const feature = event.features && event.features[0];
console.log(feature);
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);
} else {
setSelectedFeature(undefined);
}
const popupInfo = {
longitude: longitude,
latitude: latitude,
zoom: zoom,
properties: feature.properties,
};
goToPlace([
[minLng, minLat],
[maxLng, maxLat],
]);
setDetailViewData(popupInfo);
}
const popupInfo = {
longitude: longitude,
latitude: latitude,
zoom: zoom,
properties: feature.properties,
};
goToPlace([
[minLng, minLat],
[maxLng, maxLat],
]);
setDetailViewData(popupInfo);
}
};
@ -251,7 +328,7 @@ const J40Map = ({location}: IJ40Interface) => {
onClick={onClickGeolocate}
/> : ''}
{geolocationInProgress ? <div>Geolocation in progress...</div> : ''}
<TerritoryFocusControl goToPlace={goToPlace}/>
<TerritoryFocusControl onClick={onClick}/>
{'fs' in flags ? <FullscreenControl className={styles.fullscreenControl}/> :'' }
</ReactMapGL>

View file

@ -1,54 +1,18 @@
import {useIntl} from 'gatsby-plugin-intl';
import React from 'react';
import {LngLatBoundsLike} from 'mapbox-gl';
import {MapEvent} from 'react-map-gl';
import * as styles from './territoryFocusControl.module.scss';
import * as EXPLORE_COPY from '../data/copy/explore';
import * as constants from '../data/constants';
interface ITerritoryFocusControl {
goToPlace(bounds: LngLatBoundsLike): void;
onClick(event: MapEvent | React.MouseEvent<HTMLButtonElement>):void;
}
const TerritoryFocusControl = ({goToPlace}: ITerritoryFocusControl) => {
const TerritoryFocusControl = ({onClick}: ITerritoryFocusControl) => {
const intl = useIntl();
const onClickTerritoryFocusButton = (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation();
const buttonID = event.target && (event.target as HTMLElement).id;
switch (buttonID) {
case '48':
goToPlace(constants.LOWER_48_BOUNDS);
break;
case 'AK':
goToPlace(constants.ALASKA_BOUNDS);
break;
case 'HI':
goToPlace(constants.HAWAII_BOUNDS);
break;
case 'PR':
goToPlace(constants.PUERTO_RICO_BOUNDS);
break;
case 'GU':
goToPlace(constants.GUAM_BOUNDS);
break;
case 'AS':
goToPlace(constants.AMERICAN_SAMOA_BOUNDS);
break;
case 'MP':
goToPlace(constants.MARIANA_ISLAND_BOUNDS);
break;
case 'VI':
goToPlace(constants.US_VIRGIN_ISLANDS_BOUNDS);
break;
default:
break;
}
};
const territories = [
{
short: intl.formatMessage(EXPLORE_COPY.MAP.LOWER48_SHORT),
@ -102,7 +66,8 @@ const TerritoryFocusControl = ({goToPlace}: ITerritoryFocusControl) => {
<button
id={territory.short}
key={territory.short}
onClick={(e) => onClickTerritoryFocusButton(e)}
// onClickCapture={(e) => onClickTerritoryFocusButton(e)}
onClickCapture={(e) => onClick(e)}
className={'mapboxgl-ctrl-icon ' + territoriesIconClassName[index]}
aria-label={intl.formatMessage(
{