diff --git a/client/cypress/e2e/map.spec.js b/client/cypress/e2e/map.spec.js new file mode 100644 index 00000000..b1d5067a --- /dev/null +++ b/client/cypress/e2e/map.spec.js @@ -0,0 +1,25 @@ +// / + +describe('Tests for the Explore the Map page', () => { + 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 + const tests = { + 'Lower 48': '3.83/38.07/-95.87', + 'Alaska': '3.36/63.28/-140.24', + 'Hawaii': '5.94/20.574/-161.438', + 'Puerto Rico': '8.24/18.2/-66.583', + }; + + for (const [territory, zxy] of Object.entries(tests)) { + it(`Can zoom to ${territory} `, () => { + cy.get(`[aria-label="Zoom to ${territory}"]`).click(); + cy.url().should('include', zxy); + }); + }; +}); + diff --git a/client/src/components/J40Map.module.scss b/client/src/components/J40Map.module.scss index e423ba90..85ea6dd3 100644 --- a/client/src/components/J40Map.module.scss +++ b/client/src/components/J40Map.module.scss @@ -12,3 +12,32 @@ $sidebar-color: #ffffff; overflow-y: scroll; pointer-events: all !important; } + +.territoryFocusButton { + width: 40px; + height: 40px; + border-width: 1px 2px; + border-color: #000000; + border-style: solid; + background-color: #ffffff; +} + +.territoryFocusContainer { + display: flex; + flex-direction: column; + text-align: center; + font-size: 16px; + line-height: 40px; + position: absolute; + left: 20px; + top: 300px; + z-index: 10; +} + +.territoryFocusButton:first-child { + border-top-width: 2px; +} + +.territoryFocusButton:last-child { + border-bottom-width: 2px; +} diff --git a/client/src/components/J40Map.module.scss.d.ts b/client/src/components/J40Map.module.scss.d.ts index ec1e79e0..0390637c 100644 --- a/client/src/components/J40Map.module.scss.d.ts +++ b/client/src/components/J40Map.module.scss.d.ts @@ -2,6 +2,8 @@ declare namespace J40MapModuleScssNamespace { export interface IJ40MapModuleScss { mapContainer: string; j40Popup: string; + territoryFocusButton: string; + territoryFocusContainer: string; } } diff --git a/client/src/components/J40Map.tsx b/client/src/components/J40Map.tsx index 219bb62d..fc36d979 100644 --- a/client/src/components/J40Map.tsx +++ b/client/src/components/J40Map.tsx @@ -6,12 +6,12 @@ import maplibregl, {LngLatBoundsLike, PopupOptions, Popup, LngLatLike} from 'maplibre-gl'; -import 'maplibre-gl/dist/maplibre-gl.css'; import mapStyle from '../data/mapStyle'; import ZoomWarning from './zoomWarning'; import PopupContent from './popupContent'; import * as constants from '../data/constants'; import ReactDOM from 'react-dom'; +import 'maplibre-gl/dist/maplibre-gl.css'; import * as styles from './J40Map.module.scss'; declare global { @@ -24,13 +24,10 @@ type ClickEvent = maplibregl.MapMouseEvent & maplibregl.EventData; const J40Map = () => { const mapContainer = React.useRef(null); - const map = useRef() as React.MutableRefObject; + const mapRef = useRef() as React.MutableRefObject; const [zoom, setZoom] = useState(constants.GLOBAL_MIN_ZOOM); useEffect(() => { - // Only initialize once - if (map.current && mapContainer.current) return; - const initialMap = new Map({ container: mapContainer.current!, style: mapStyle, @@ -56,8 +53,8 @@ const J40Map = () => { initialMap.on('click', handleClick); initialMap.addControl(new NavigationControl({showCompass: false}), 'top-left'); - map.current = initialMap; - }); + mapRef.current = initialMap; + }, []); const handleClick = (e: ClickEvent) => { const map = e.target; @@ -82,20 +79,78 @@ const J40Map = () => { }; useEffect(() => { - if (!map.current) return; // wait for map to initialize - map.current.on('move', () => { - setZoom(map.current.getZoom()); + mapRef.current.on('move', () => { + setZoom(mapRef.current.getZoom()); }); - map.current.on('mouseenter', 'score', () => { - map.current.getCanvas().style.cursor = 'pointer'; + mapRef.current.on('mouseenter', 'score', () => { + mapRef.current.getCanvas().style.cursor = 'pointer'; }); - map.current.on('mouseleave', 'score', () => { - map.current.getCanvas().style.cursor = ''; + mapRef.current.on('mouseleave', 'score', () => { + mapRef.current.getCanvas().style.cursor = ''; }); - }); + }, [mapRef]); + + const goToPlace = (bounds:number[][]) => { + mapRef.current.fitBounds(bounds as LngLatBoundsLike); + }; + + const onClickTerritoryFocusButton = (event: React.MouseEvent) => { + // currentTarget always refers to the element to which the event handler + // has been attached, as opposed to Event.target, which identifies + // the element on which the event occurred and which may be its descendant. + const buttonID = event.target && event.currentTarget.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; + + default: + break; + } + }; return (
+
+ + + + +
diff --git a/client/src/data/constants.tsx b/client/src/data/constants.tsx index 94ae3840..34280012 100644 --- a/client/src/data/constants.tsx +++ b/client/src/data/constants.tsx @@ -13,7 +13,46 @@ export const GLOBAL_MIN_ZOOM_HIGH = 9; export const GLOBAL_MAX_ZOOM_HIGH = 12; // Bounds -export const GLOBAL_MAX_BOUNDS = [[-167.276413, 5.499550], [-52.233040, 83.162102]]; +export const GLOBAL_MAX_BOUNDS = [ + [-180.118306, 5.499550], + [-65.0, 83.162102], +]; + +export const LOWER_48_BOUNDS = [ + [-124.7844079, 24.7433195], + [-66.9513812, 49.3457868], +]; + +export const ALASKA_BOUNDS = [ + [-183.856888, 50.875311], + [-140.932617, 71.958797], +]; + +export const HAWAII_BOUNDS = [ + [-168.118306, 18.748115], + [-154.757881, 22.378413], +]; + +export const PUERTO_RICO_BOUNDS = [ + [-67.945404, 17.88328], + [-65.220703, 18.515683], +]; + +export const GUAM_BOUNDS = [ + [-215.389709, 13.225909], + [-215.040894, 13.663335], +]; + +export const MARIANA_ISLAND_BOUNDS = [ + [-215.313449, 14.007801], + [-213.742404, 19.750326], +]; + +export const AMERICAN_SAMOA_BOUNDS = [ + [-171.089874, -14.548699], + [-168.1433, -11.046934], +]; + export const DEFAULT_CENTER = [32.4687126, -86.502136]; // Opacity