From beb0eea5cc043327d16592865e0d2afab721bf85 Mon Sep 17 00:00:00 2001 From: Lucas Merrill Brown Date: Mon, 27 Dec 2021 12:05:59 -0500 Subject: [PATCH 1/4] Alternative definition of DACs for comparison (#1068) * Alternative energy-related definition of DACs --- .../data_pipeline/etl/constants.py | 5 + .../README.md | 0 .../__init__.py | 0 .../etl.py | 113 ++++++++++++++++++ .../ipython/scoring_comparison.ipynb | 25 ++++ .../data_pipeline/score/field_names.py | 21 ++++ 6 files changed, 164 insertions(+) create mode 100644 data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/README.md create mode 100644 data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/__init__.py create mode 100644 data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/etl.py diff --git a/data/data-pipeline/data_pipeline/etl/constants.py b/data/data-pipeline/data_pipeline/etl/constants.py index 59dafe2b..f0b2dbe0 100644 --- a/data/data-pipeline/data_pipeline/etl/constants.py +++ b/data/data-pipeline/data_pipeline/etl/constants.py @@ -89,6 +89,11 @@ DATASET_LIST = [ "module_dir": "hud_recap", "class_name": "HudRecapETL", }, + { + "name": "energy_definition_alternative_draft", + "module_dir": "energy_definition_alternative_draft", + "class_name": "EnergyDefinitionAlternativeDraft", + }, { "name": "tree_equity_score", "module_dir": "tree_equity_score", diff --git a/data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/README.md b/data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/README.md new file mode 100644 index 00000000..e69de29b diff --git a/data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/__init__.py b/data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/etl.py b/data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/etl.py new file mode 100644 index 00000000..c8a95fe1 --- /dev/null +++ b/data/data-pipeline/data_pipeline/etl/sources/energy_definition_alternative_draft/etl.py @@ -0,0 +1,113 @@ +from pathlib import Path +import pandas as pd + +from data_pipeline.config import settings +from data_pipeline.etl.base import ExtractTransformLoad +from data_pipeline.score import field_names +from data_pipeline.utils import get_module_logger, unzip_file_from_url + +logger = get_module_logger(__name__) + + +class EnergyDefinitionAlternativeDraft(ExtractTransformLoad): + def __init__(self): + self.DEFINITION_ALTERNATIVE_FILE_URL = ( + settings.AWS_JUSTICE40_DATASOURCES_URL + + "/alternative DAC definition.csv.zip" + ) + + self.OUTPUT_PATH: Path = ( + self.DATA_PATH / "dataset" / "energy_definition_alternative_draft" + ) + + self.TRACT_INPUT_COLUMN_NAME = "GEOID" + self.ALTERNATIVE_DEFINITION_INPUT_COLUMN_NAME = "J40_DAC" + + # Constants for output + self.COLUMNS_TO_KEEP = [ + self.GEOID_TRACT_FIELD_NAME, + field_names.ENERGY_RELATED_COMMUNITIES_DEFINITION_ALTERNATIVE, + field_names.COAL_EMPLOYMENT, + field_names.OUTAGE_EVENTS, + field_names.HOMELESSNESS, + field_names.DISABLED_POPULATION, + field_names.OUTAGE_DURATION, + field_names.JOB_ACCESS, + field_names.FOSSIL_ENERGY_EMPLOYMENT, + field_names.FOOD_DESERT, + field_names.INCOMPLETE_PLUMBING, + field_names.NON_GRID_CONNECTED_HEATING_FUEL, + field_names.PARKS, + field_names.GREATER_THAN_30_MIN_COMMUTE, + field_names.INTERNET_ACCESS, + field_names.MOBILE_HOME, + field_names.SINGLE_PARENT, + field_names.TRANSPORTATION_COSTS, + ] + + self.df: pd.DataFrame + + def extract(self) -> None: + logger.info("Starting data download.") + + unzip_file_from_url( + file_url=self.DEFINITION_ALTERNATIVE_FILE_URL, + download_path=self.TMP_PATH, + unzipped_file_path=self.TMP_PATH + / "energy_definition_alternative_draft", + ) + + self.df = pd.read_csv( + filepath_or_buffer=self.TMP_PATH + / "energy_definition_alternative_draft" + / "J40 alternative DAC definition.csv", + # The following need to remain as strings for all of their digits, not get converted to numbers. + dtype={ + self.TRACT_INPUT_COLUMN_NAME: "string", + }, + low_memory=False, + ) + + def transform(self) -> None: + logger.info("Starting transforms.") + + self.df = self.df.rename( + columns={ + self.TRACT_INPUT_COLUMN_NAME: self.GEOID_TRACT_FIELD_NAME, + self.ALTERNATIVE_DEFINITION_INPUT_COLUMN_NAME: field_names.ENERGY_RELATED_COMMUNITIES_DEFINITION_ALTERNATIVE, + "Coal_Emp_Ratio": field_names.COAL_EMPLOYMENT, + "COUNT_Outage_Events": field_names.OUTAGE_EVENTS, + "den_hmls_pop": field_names.HOMELESSNESS, + "disability_pct": field_names.DISABLED_POPULATION, + "Duration_in_Minutes": field_names.OUTAGE_DURATION, + "emp_ovrll_ndx": field_names.JOB_ACCESS, + "FE_Emp_Ratio": field_names.FOSSIL_ENERGY_EMPLOYMENT, + "Food_LAhalfand10": field_names.FOOD_DESERT, + "incomplete_plumbing_pct": field_names.INCOMPLETE_PLUMBING, + "nongrid_heat_pct": field_names.NON_GRID_CONNECTED_HEATING_FUEL, + "num_parks": field_names.PARKS, + "Per_MoT_Dur_gte30": field_names.GREATER_THAN_30_MIN_COMMUTE, + "Per_NoInt": field_names.INTERNET_ACCESS, + "population_mobile_home_pct": field_names.MOBILE_HOME, + "single_parent_pct": field_names.SINGLE_PARENT, + "t_ami": field_names.TRANSPORTATION_COSTS, + } + ) + + # Convert to boolean: + self.df[field_names.ENERGY_RELATED_COMMUNITIES_DEFINITION_ALTERNATIVE] = \ + self.df[field_names.ENERGY_RELATED_COMMUNITIES_DEFINITION_ALTERNATIVE + ].astype('bool') + + def validate(self) -> None: + logger.info("Validating data") + + pass + + def load(self) -> None: + logger.info("Saving CSV") + + self.OUTPUT_PATH.mkdir(parents=True, exist_ok=True) + self.df[self.COLUMNS_TO_KEEP].to_csv( + path_or_buf=self.OUTPUT_PATH / "usa.csv", index=False + ) diff --git a/data/data-pipeline/data_pipeline/ipython/scoring_comparison.ipynb b/data/data-pipeline/data_pipeline/ipython/scoring_comparison.ipynb index e5e02974..fa7b46bd 100644 --- a/data/data-pipeline/data_pipeline/ipython/scoring_comparison.ipynb +++ b/data/data-pipeline/data_pipeline/ipython/scoring_comparison.ipynb @@ -276,6 +276,25 @@ "mapping_inequality_df" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "605af1ff", + "metadata": {}, + "outputs": [], + "source": [ + "# Load alternative energy-related definition \n", + "energy_definition_alternative_draft_path = (\n", + " DATA_DIR / \"dataset\" / \"energy_definition_alternative_draft\" / \"usa.csv\"\n", + ")\n", + "energy_definition_alternative_draft_df = pd.read_csv(\n", + " energy_definition_alternative_draft_path,\n", + " dtype={ExtractTransformLoad.GEOID_TRACT_FIELD_NAME: \"string\"},\n", + ")\n", + "\n", + "energy_definition_alternative_draft_df" + ] + }, { "cell_type": "code", "execution_count": null, @@ -291,6 +310,7 @@ " calenviroscreen_df,\n", " persistent_poverty_df,\n", " mapping_inequality_df,\n", + " energy_definition_alternative_draft_df,\n", "]\n", "\n", "merged_df = functools.reduce(\n", @@ -431,6 +451,11 @@ " priority_communities_field=PERSISTENT_POVERTY_TRACT_LEVEL_FIELD,\n", " other_census_tract_fields_to_keep=[],\n", " ),\n", + " Index(\n", + " method_name=field_names.ENERGY_RELATED_COMMUNITIES_DEFINITION_ALTERNATIVE,\n", + " priority_communities_field=field_names.ENERGY_RELATED_COMMUNITIES_DEFINITION_ALTERNATIVE,\n", + " other_census_tract_fields_to_keep=[],\n", + " ),\n", " ]\n", " # Insert indices for each of the HOLC factors.\n", " # Note: since these involve no renaming, we write them using list comprehension.\n", diff --git a/data/data-pipeline/data_pipeline/score/field_names.py b/data/data-pipeline/data_pipeline/score/field_names.py index bdca25d5..f9d3c806 100644 --- a/data/data-pipeline/data_pipeline/score/field_names.py +++ b/data/data-pipeline/data_pipeline/score/field_names.py @@ -230,6 +230,27 @@ IMPENETRABLE_SURFACES_FIELD = "Percent impenetrable surface areas" READING_FIELD = "Third grade reading proficiency" LOW_READING_FIELD = "Low third grade reading proficiency" +# Alternative energy-related definition of DACs +ENERGY_RELATED_COMMUNITIES_DEFINITION_ALTERNATIVE = ( + "Energy-related alternative definition of communities" +) +COAL_EMPLOYMENT = "Coal employment" +OUTAGE_EVENTS = "Outage Events" +HOMELESSNESS = "Homelessness" +DISABLED_POPULATION = "Disabled population" +OUTAGE_DURATION = "Outage Duration" +JOB_ACCESS = "Job Access" +FOSSIL_ENERGY_EMPLOYMENT = "Fossil energy employment" +FOOD_DESERT = "Food Desert" +INCOMPLETE_PLUMBING = "Incomplete Plumbing" +NON_GRID_CONNECTED_HEATING_FUEL = "Non-grid-connected heating fuel" +PARKS = "Parks" +GREATER_THAN_30_MIN_COMMUTE = "Greater than 30 min commute" +INTERNET_ACCESS = "Internet Access" +MOBILE_HOME = "Mobile Home" +SINGLE_PARENT = "Single Parent" +TRANSPORTATION_COSTS = "Transportation Costs" + ##### # Names for individual factors being exceeded # Climate Change From 356e16950f5f36909681c4d7d5ed78d1ced55baf Mon Sep 17 00:00:00 2001 From: Vim <86254807+vim-usds@users.noreply.github.com> Date: Tue, 28 Dec 2021 18:30:22 -0500 Subject: [PATCH 2/4] 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 --- .../LegacyTests/mapZoomLatLong.spec.js | 92 +++++------ .../LegacyTests/mapZoomTerritories.spec.js | 72 +++++---- client/src/components/AreaDetail/index.tsx | 10 +- client/src/components/J40Map.tsx | 147 +++++++++++++----- .../src/components/territoryFocusControl.tsx | 45 +----- client/src/data/constants.tsx | 16 +- client/src/data/copy/explore.tsx | 2 +- .../0002-mapping-visualization-library.md | 6 +- 8 files changed, 223 insertions(+), 167 deletions(-) diff --git a/client/cypress/integration/LegacyTests/mapZoomLatLong.spec.js b/client/cypress/integration/LegacyTests/mapZoomLatLong.spec.js index 7023c89c..484aabeb 100644 --- a/client/cypress/integration/LegacyTests/mapZoomLatLong.spec.js +++ b/client/cypress/integration/LegacyTests/mapZoomLatLong.spec.js @@ -9,53 +9,53 @@ describe('Does the map zoom and adjust to lat/long correctly?', () => { cy.get('.mapboxgl-ctrl-icon.mapboxgl-ctrl-zoom-in').click({force: true}); cy.url().should('include', '#4'); }); - // it('should show the correct lat/lng coordinates in the URL', - // { - // retries: { - // runMode: 3, - // openMode: 3, - // }, - // defaultCommandTimeout: 4000, - // execTimeout: 10000, - // taskTimeout: 10000, - // pageLoadTimeout: 10000, - // requestTimeout: 5000, - // responseTimeout: 10000, - // }, - // () => { - // cy.getMap().then((map) => { - // cy.panTo(map, [-77.9, 35.04]); - // cy.url().should('include', '#4/35.04/-77.9'); - // }); - // }); + it('should show the correct lat/lng coordinates in the URL', + { + retries: { + runMode: 3, + openMode: 3, + }, + defaultCommandTimeout: 4000, + execTimeout: 10000, + taskTimeout: 10000, + pageLoadTimeout: 10000, + requestTimeout: 5000, + responseTimeout: 10000, + }, + () => { + cy.getMap().then((map) => { + cy.panTo(map, [-77.9, 35.04]); + cy.url().should('include', '#4/35.04/-77.9'); + }); + }); // This test hangs intermittently (30% of the time) need to investigate why - // it('allows user to specify alternative starting URL', - // { - // retries: { - // runMode: 3, - // openMode: 3, - // }, - // defaultCommandTimeout: 4000, - // execTimeout: 10000, - // taskTimeout: 10000, - // pageLoadTimeout: 10000, - // requestTimeout: 5000, - // responseTimeout: 10000, - // }, - // () => { - // const [expectedZoom, expectedLat, expectedLng] = [12.05, 41.40965, -75.65978]; - // const expectedURL = `http://localhost:8000/en/cejst/#${expectedZoom}/${expectedLat}/${expectedLng}`; - // cy.visit(expectedURL); - // cy.getMap().then((map) => { - // cy.waitForMapIdle(map); - // cy.url().should('equal', expectedURL); - // const actualZoom = map.getZoom(); - // const actualCenter = map.getCenter(); - // expect(actualCenter.lat).to.eq(expectedLat); - // expect(actualCenter.lng).to.eq(expectedLng); - // expect(actualZoom).to.eq(expectedZoom); - // }); - // }); + it('allows user to specify alternative starting URL', + { + retries: { + runMode: 3, + openMode: 3, + }, + defaultCommandTimeout: 4000, + execTimeout: 10000, + taskTimeout: 10000, + pageLoadTimeout: 10000, + requestTimeout: 5000, + responseTimeout: 10000, + }, + () => { + const [expectedZoom, expectedLat, expectedLng] = [12.05, 41.40965, -75.65978]; + const expectedURL = `http://localhost:8000/en/cejst/#${expectedZoom}/${expectedLat}/${expectedLng}`; + cy.visit(expectedURL); + cy.getMap().then((map) => { + cy.waitForMapIdle(map); + cy.url().should('equal', expectedURL); + const actualZoom = map.getZoom(); + const actualCenter = map.getCenter(); + expect(actualCenter.lat).to.eq(expectedLat); + expect(actualCenter.lng).to.eq(expectedLng); + expect(actualZoom).to.eq(expectedZoom); + }); + }); }); diff --git a/client/cypress/integration/LegacyTests/mapZoomTerritories.spec.js b/client/cypress/integration/LegacyTests/mapZoomTerritories.spec.js index 841fac32..dba8a48d 100644 --- a/client/cypress/integration/LegacyTests/mapZoomTerritories.spec.js +++ b/client/cypress/integration/LegacyTests/mapZoomTerritories.spec.js @@ -1,32 +1,48 @@ // / -describe('Will it zoom into territories correctly?', () => { - beforeEach(() => { - cy.viewport('macbook-13'); - cy.visit('http://localhost:8000/en/cejst'); - }); - - // The below values all assume a 13-inch MB as set in viewport above. - // Values will be different for different screens - - // Removing z as each tests has variance on it's value - const tests = { - 'Lower 48': '/38.07/-95.87', - - // Todo: Understand what causes these two to hang intermittently ticket #579 - // 'Puerto Rico': '/18.2/-66.583', - // 'Alaska': '/63.28/-162.39', - // 'Hawaii': '5.35/20.574/-161.438', - }; - - for (const [territory, xy] of Object.entries(tests)) { - it(`Can focus on ${territory} `, () => { - cy.getMap().then((map) => { - cy.get(`[aria-label="Focus on ${territory}"]`).click(); - cy.waitForMapIdle(map); - cy.log(cy.url()); - cy.url().should('include', xy); +describe('Will it zoom into territories correctly?', + { + retries: { + runMode: 3, + openMode: 3, + }, + defaultCommandTimeout: 4000, + execTimeout: 10000, + taskTimeout: 10000, + pageLoadTimeout: 10000, + requestTimeout: 5000, + responseTimeout: 10000, + }, + () => { + beforeEach(() => { + cy.viewport('macbook-13'); + cy.visit('http://localhost:8000/en/cejst'); }); + + // The below values all assume a 13-inch MB as set in viewport above. + // Values will be different for different screens + + // Removing z as each tests has variance on it's value + const tests = { + 'Lower 48': '3/33.47/-97.5', + + // Todo: Understand what causes these two to hang intermittently ticket #579 + // 'Puerto Rico': '7.71/18.2/-66.583', + // 'Alaska': '3/63.28/-162.39', + // 'American Samoa': '6.55/-13.804/-171.117', + // 'Commonwealth of Northern Mariana Islands': '5.98/16.901/145.472', + // 'Hawaii': '5.73/20.657/-157.697', + }; + for (let i=0; i<1; i++) { + for (const [territory, zxy] of Object.entries(tests)) { + it(`Can focus on ${territory} `, () => { + cy.getMap().then((map) => { + cy.get(`[aria-label="Focus on ${territory}"]`).click(); + cy.waitForMapIdle(map); + cy.log(cy.url()); + cy.url().should('include', zxy); + }); + }); + }; + } }); - }; -}); diff --git a/client/src/components/AreaDetail/index.tsx b/client/src/components/AreaDetail/index.tsx index 550224ec..b017b6bd 100644 --- a/client/src/components/AreaDetail/index.tsx +++ b/client/src/components/AreaDetail/index.tsx @@ -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, }}/> - {/* eslint-disable-next-line max-len */} - {/* {EXPLORE_COPY.COMMUNITY.SEND_FEEDBACK} */} + {/* + {EXPLORE_COPY.COMMUNITY.SEND_FEEDBACK} + */} diff --git a/client/src/components/J40Map.tsx b/client/src/components/J40Map.tsx index 4123534b..a015ce9d 100644 --- a/client/src/components/J40Map.tsx +++ b/client/src/components/J40Map.tsx @@ -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({ - 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(); @@ -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) => { + // 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 ?
Geolocation in progress...
: ''} - + {'fs' in flags ? :'' } diff --git a/client/src/components/territoryFocusControl.tsx b/client/src/components/territoryFocusControl.tsx index fb7e21f1..67a842d7 100644 --- a/client/src/components/territoryFocusControl.tsx +++ b/client/src/components/territoryFocusControl.tsx @@ -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):void; } -const TerritoryFocusControl = ({goToPlace}: ITerritoryFocusControl) => { +const TerritoryFocusControl = ({onClick}: ITerritoryFocusControl) => { const intl = useIntl(); - const onClickTerritoryFocusButton = (event: React.MouseEvent) => { - 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) => {