mirror of
https://github.com/DOI-DO/j40-cejst-2.git
synced 2025-07-29 06:51:16 -07:00
Fixes #280 - adds territory focus buttons for Alaska, Hawaii, Lower 48, and Puerto Rico to enable easy zoom to these locations (#315)
This commit is contained in:
parent
2257627938
commit
5bade764c6
5 changed files with 166 additions and 16 deletions
25
client/cypress/e2e/map.spec.js
Normal file
25
client/cypress/e2e/map.spec.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// / <reference types="Cypress" />
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
|
@ -12,3 +12,32 @@ $sidebar-color: #ffffff;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
pointer-events: all !important;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ declare namespace J40MapModuleScssNamespace {
|
||||||
export interface IJ40MapModuleScss {
|
export interface IJ40MapModuleScss {
|
||||||
mapContainer: string;
|
mapContainer: string;
|
||||||
j40Popup: string;
|
j40Popup: string;
|
||||||
|
territoryFocusButton: string;
|
||||||
|
territoryFocusContainer: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,12 @@ import maplibregl, {LngLatBoundsLike,
|
||||||
PopupOptions,
|
PopupOptions,
|
||||||
Popup,
|
Popup,
|
||||||
LngLatLike} from 'maplibre-gl';
|
LngLatLike} from 'maplibre-gl';
|
||||||
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
||||||
import mapStyle from '../data/mapStyle';
|
import mapStyle from '../data/mapStyle';
|
||||||
import ZoomWarning from './zoomWarning';
|
import ZoomWarning from './zoomWarning';
|
||||||
import PopupContent from './popupContent';
|
import PopupContent from './popupContent';
|
||||||
import * as constants from '../data/constants';
|
import * as constants from '../data/constants';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import 'maplibre-gl/dist/maplibre-gl.css';
|
||||||
import * as styles from './J40Map.module.scss';
|
import * as styles from './J40Map.module.scss';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -24,13 +24,10 @@ type ClickEvent = maplibregl.MapMouseEvent & maplibregl.EventData;
|
||||||
|
|
||||||
const J40Map = () => {
|
const J40Map = () => {
|
||||||
const mapContainer = React.useRef<HTMLDivElement>(null);
|
const mapContainer = React.useRef<HTMLDivElement>(null);
|
||||||
const map = useRef<Map>() as React.MutableRefObject<Map>;
|
const mapRef = useRef<Map>() as React.MutableRefObject<Map>;
|
||||||
const [zoom, setZoom] = useState(constants.GLOBAL_MIN_ZOOM);
|
const [zoom, setZoom] = useState(constants.GLOBAL_MIN_ZOOM);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Only initialize once
|
|
||||||
if (map.current && mapContainer.current) return;
|
|
||||||
|
|
||||||
const initialMap = new Map({
|
const initialMap = new Map({
|
||||||
container: mapContainer.current!,
|
container: mapContainer.current!,
|
||||||
style: mapStyle,
|
style: mapStyle,
|
||||||
|
@ -56,8 +53,8 @@ const J40Map = () => {
|
||||||
|
|
||||||
initialMap.on('click', handleClick);
|
initialMap.on('click', handleClick);
|
||||||
initialMap.addControl(new NavigationControl({showCompass: false}), 'top-left');
|
initialMap.addControl(new NavigationControl({showCompass: false}), 'top-left');
|
||||||
map.current = initialMap;
|
mapRef.current = initialMap;
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
const handleClick = (e: ClickEvent) => {
|
const handleClick = (e: ClickEvent) => {
|
||||||
const map = e.target;
|
const map = e.target;
|
||||||
|
@ -82,20 +79,78 @@ const J40Map = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!map.current) return; // wait for map to initialize
|
mapRef.current.on('move', () => {
|
||||||
map.current.on('move', () => {
|
setZoom(mapRef.current.getZoom());
|
||||||
setZoom(map.current.getZoom());
|
|
||||||
});
|
});
|
||||||
map.current.on('mouseenter', 'score', () => {
|
mapRef.current.on('mouseenter', 'score', () => {
|
||||||
map.current.getCanvas().style.cursor = 'pointer';
|
mapRef.current.getCanvas().style.cursor = 'pointer';
|
||||||
});
|
});
|
||||||
map.current.on('mouseleave', 'score', () => {
|
mapRef.current.on('mouseleave', 'score', () => {
|
||||||
map.current.getCanvas().style.cursor = '';
|
mapRef.current.getCanvas().style.cursor = '';
|
||||||
});
|
});
|
||||||
});
|
}, [mapRef]);
|
||||||
|
|
||||||
|
const goToPlace = (bounds:number[][]) => {
|
||||||
|
mapRef.current.fitBounds(bounds as LngLatBoundsLike);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onClickTerritoryFocusButton = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
// 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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
<div className={styles.territoryFocusContainer}>
|
||||||
|
<button
|
||||||
|
id={'48'}
|
||||||
|
onClick={onClickTerritoryFocusButton}
|
||||||
|
className={styles.territoryFocusButton}
|
||||||
|
aria-label="Zoom to Lower 48" >
|
||||||
|
48
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id={'AK'}
|
||||||
|
onClick={onClickTerritoryFocusButton}
|
||||||
|
className={styles.territoryFocusButton}
|
||||||
|
aria-label="Zoom to Alaska" >
|
||||||
|
AK
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id={'HI'}
|
||||||
|
onClick={onClickTerritoryFocusButton}
|
||||||
|
className={styles.territoryFocusButton}
|
||||||
|
aria-label="Zoom to Hawaii" >
|
||||||
|
HI
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
id={'PR'}
|
||||||
|
onClick={onClickTerritoryFocusButton}
|
||||||
|
className={styles.territoryFocusButton}
|
||||||
|
aria-label="Zoom to Puerto Rico" >
|
||||||
|
PR
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div ref={mapContainer} className={styles.mapContainer}/>
|
<div ref={mapContainer} className={styles.mapContainer}/>
|
||||||
<ZoomWarning zoomLevel={zoom} />
|
<ZoomWarning zoomLevel={zoom} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,46 @@ export const GLOBAL_MIN_ZOOM_HIGH = 9;
|
||||||
export const GLOBAL_MAX_ZOOM_HIGH = 12;
|
export const GLOBAL_MAX_ZOOM_HIGH = 12;
|
||||||
|
|
||||||
// Bounds
|
// 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];
|
export const DEFAULT_CENTER = [32.4687126, -86.502136];
|
||||||
|
|
||||||
// Opacity
|
// Opacity
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue