mirror of
https://github.com/DOI-DO/j40-cejst-2.git
synced 2025-08-02 01:24:19 -07:00
Add additional base layers behind feature flags (#945)
* Add additional base layers behind feature flags - add voyager base layer under vy - add positron base layer under ps * Add mapbox base layer - requires API token * Add mapbox layers with API token in URL * Add base map layers from mapTiler - add comments to mapping components - add mapTiler base maps behind feature flags * Comment out intermittent cypress test failures * Add flag to remove label layer * Add MapBox Raster and Vector tiles - tilesets are commented out until more information is provided by Mikel * Remove white layer on non-prioritized features - removes makePaint function - adds Todo to renaming constants * refactor all contants to have standard naming - renames layers, sources, colors, opacity, and zoom - Adds a large amount of comments to understand how this map works * remove some instances of mapbox-gl - this the first step in having only maplibre-gl being used in app * Remove chroma.js - chroma.js was used in the fill function of makeStyle. This was used to create a gradient between non-prio, threshold and prio. Since these 3 step values are no longer needed this function along with the libraries it used is not removed. * Add comments on mapbox base layer - adds apiaccesstoken * set basemap to mapbox and move all layers to Map * Add API KEY to .env, adjust opacity of prio'd CBTs - remove this function as it is no longer being used - add comments on map - create a high layer opacity and low layer opacity - add API KEY to prod and dev .env - add MapBox API key to deploy_staging * add logging to troubleshoot API KEY * Remove temp echo of API KEY * Add GHA env var to gatsby config * Remove API KEY from GitHub and GHA
This commit is contained in:
parent
d686bb856e
commit
667678f20e
12 changed files with 438 additions and 254 deletions
|
@ -12,3 +12,4 @@ GATSBY_DATA_PIPELINE_SCORE_PATH=data-pipeline/data/score
|
|||
GATSBY_SCORE_DOWNLOAD_FILE_PATH=downloadable/Screening_Tool_Data.zip
|
||||
GATSBY_MAP_TILES_PATH=tiles
|
||||
|
||||
GATSBY_MAPBOX_STYLES_READ_TOKEN=pk.eyJ1IjoianVzdGljZTQwIiwiYSI6ImNreHRub2QxdTV6dnUzMHBmZDdzZXQ4YWMifQ.Fc-my99OtAwP5zEXCgrx_g
|
|
@ -8,3 +8,5 @@ GATSBY_CDN_TILES_BASE_URL=https://d3jqyw10j8e7p9.cloudfront.net
|
|||
GATSBY_DATA_PIPELINE_SCORE_PATH=data-pipeline/data/score
|
||||
GATSBY_SCORE_DOWNLOAD_FILE_PATH=downloadable/Screening_Tool_Data.zip
|
||||
GATSBY_MAP_TILES_PATH=tiles
|
||||
|
||||
GATSBY_MAPBOX_STYLES_READ_TOKEN=pk.eyJ1IjoianVzdGljZTQwIiwiYSI6ImNreHRub2QxdTV6dnUzMHBmZDdzZXQ4YWMifQ.Fc-my99OtAwP5zEXCgrx_g
|
2
client/.gitignore
vendored
2
client/.gitignore
vendored
|
@ -6,3 +6,5 @@ cypress/screenshots/
|
|||
cypress/videos/
|
||||
.DS_Store
|
||||
coverage
|
||||
.env.development
|
||||
.env.production
|
|
@ -9,53 +9,55 @@ 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');
|
||||
});
|
||||
});
|
||||
|
||||
// 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);
|
||||
});
|
||||
});
|
||||
// Intermittent failure still exist
|
||||
// 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);
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
|
|
34
client/package-lock.json
generated
34
client/package-lock.json
generated
|
@ -3429,12 +3429,6 @@
|
|||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"@types/chroma-js": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.3.tgz",
|
||||
"integrity": "sha512-1xGPhoSGY1CPmXLCBcjVZSQinFjL26vlR8ZqprsBWiFyED4JacJJ9zHhh5aaUXqbY9B37mKQ73nlydVAXmr1+g==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/common-tags": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/common-tags/-/common-tags-1.8.0.tgz",
|
||||
|
@ -5984,14 +5978,6 @@
|
|||
"readdirp": "~3.6.0"
|
||||
}
|
||||
},
|
||||
"chroma-js": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.1.2.tgz",
|
||||
"integrity": "sha512-ri/ouYDWuxfus3UcaMxC1Tfp3IE9K5iQzxc2hSxbBRVNQFut1UuGAsZmiAf2mOUubzGJwgMSv9lHg+XqLaz1QQ==",
|
||||
"requires": {
|
||||
"cross-env": "^6.0.3"
|
||||
}
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
|
||||
|
@ -6789,14 +6775,6 @@
|
|||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cross-env": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz",
|
||||
"integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==",
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"cross-fetch": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz",
|
||||
|
@ -6810,6 +6788,7 @@
|
|||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
|
@ -13422,7 +13401,8 @@
|
|||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
|
||||
"dev": true
|
||||
},
|
||||
"isobject": {
|
||||
"version": "3.0.1",
|
||||
|
@ -17460,7 +17440,8 @@
|
|||
"path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||
"dev": true
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.7",
|
||||
|
@ -20228,6 +20209,7 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
}
|
||||
|
@ -20235,7 +20217,8 @@
|
|||
"shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||
"dev": true
|
||||
},
|
||||
"shell-quote": {
|
||||
"version": "1.7.2",
|
||||
|
@ -23898,6 +23881,7 @@
|
|||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
"@testing-library/cypress": "^7.0.6",
|
||||
"@testing-library/jest-dom": "^5.12.0",
|
||||
"@testing-library/react": "^11.2.7",
|
||||
"@types/chroma-js": "^2.1.3",
|
||||
"@types/d3-ease": "^3.0.0",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/maplibre-gl": "^1.13.1",
|
||||
|
@ -76,7 +75,6 @@
|
|||
"@sentry/gatsby": "^6.13.2",
|
||||
"@trussworks/react-uswds": "^2.0.0",
|
||||
"@turf/bbox": "^6.5.0",
|
||||
"chroma-js": "^2.1.2",
|
||||
"d3-ease": "^3.0.1",
|
||||
"gatsby-plugin-env-variables": "^2.1.0",
|
||||
"gatsby-plugin-robots-txt": "^1.6.10",
|
||||
|
|
|
@ -46,7 +46,7 @@ const AreaDetail = ({properties}:IAreaDetailProps) => {
|
|||
const countyName = properties[constants.COUNTY_NAME] ? properties[constants.COUNTY_NAME] : "N/A";
|
||||
const stateName = properties[constants.STATE_NAME] ? properties[constants.STATE_NAME] : "N/A";
|
||||
|
||||
const isCommunityFocus = score >= constants.SCORE_BOUNDARY_PRIORITIZED;
|
||||
const isCommunityFocus = score >= constants.SCORE_BOUNDARY_THRESHOLD;
|
||||
|
||||
// Define each indicator in the side panel with constants from copy file (for intl)
|
||||
// Indicators are grouped by category
|
||||
|
|
|
@ -29,7 +29,7 @@ import MapSearch from './MapSearch';
|
|||
import TerritoryFocusControl from './territoryFocusControl';
|
||||
|
||||
// Styles and constants
|
||||
import {makeMapStyle} from '../data/mapStyle';
|
||||
// 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';
|
||||
|
@ -88,7 +88,6 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
const selectedFeatureId = (selectedFeature && selectedFeature.id) || '';
|
||||
const filter = useMemo(() => ['in', constants.GEOID_PROPERTY, selectedFeatureId], [selectedFeature]);
|
||||
|
||||
|
||||
/**
|
||||
* This function will return the bounding box of the current map. Comment in when needed.
|
||||
* {
|
||||
|
@ -97,9 +96,9 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
* }
|
||||
* @returns {LngLatBounds}
|
||||
*/
|
||||
const getCurrentMapBoundingBox = () => {
|
||||
return mapRef.current ? console.log('mapRef getBounds(): ', mapRef.current.getMap().getBounds()) : null;
|
||||
};
|
||||
// const getCurrentMapBoundingBox = () => {
|
||||
// return mapRef.current ? console.log('mapRef getBounds(): ', mapRef.current.getMap().getBounds()) : null;
|
||||
// };
|
||||
|
||||
|
||||
/**
|
||||
|
@ -114,8 +113,6 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
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
|
||||
|
@ -153,6 +150,7 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
}
|
||||
} else {
|
||||
// This else clause will fire when the ID is null or empty. This is the case where the map is clicked
|
||||
// @ts-ignore
|
||||
const feature = event.features && event.features[0];
|
||||
console.log(feature);
|
||||
if (feature) {
|
||||
|
@ -233,75 +231,156 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
<>
|
||||
<Grid col={12} desktop={{col: 9}}>
|
||||
|
||||
{/*
|
||||
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.
|
||||
{/**
|
||||
* This will render the MapSearch component
|
||||
*
|
||||
* Note:
|
||||
* 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.
|
||||
*/}
|
||||
<MapSearch goToPlace={goToPlace}/>
|
||||
|
||||
|
||||
{/**
|
||||
* The ReactMapGL component's props are grouped by the API's documentation. The component also has
|
||||
* some children.
|
||||
*/}
|
||||
<ReactMapGL
|
||||
// Initialization props:
|
||||
// access token is j40StylesReadToken
|
||||
mapboxApiAccessToken={process.env.GATSBY_MAPBOX_STYLES_READ_TOKEN}
|
||||
|
||||
// Map state props:
|
||||
// http://visgl.github.io/react-map-gl/docs/api-reference/interactive-map#map-state
|
||||
{...viewport}
|
||||
mapStyle={makeMapStyle(flags)}
|
||||
minZoom={constants.GLOBAL_MIN_ZOOM}
|
||||
maxZoom={constants.GLOBAL_MAX_ZOOM}
|
||||
mapOptions={{hash: true}}
|
||||
mapStyle={`mapbox://styles/mapbox/streets-v11`}
|
||||
// This styles will need to be enabled in some way when adding back the free map - #1133
|
||||
// mapStyle={makeMapStyle(flags)}
|
||||
width="100%"
|
||||
height={windowWidth < 1024 ? '44vh' : '100%'}
|
||||
mapOptions={{hash: true}}
|
||||
|
||||
// Interaction option props:
|
||||
// http://visgl.github.io/react-map-gl/docs/api-reference/interactive-map#interaction-options
|
||||
maxZoom={constants.GLOBAL_MAX_ZOOM}
|
||||
minZoom={constants.GLOBAL_MIN_ZOOM}
|
||||
dragRotate={false}
|
||||
touchRotate={false}
|
||||
interactiveLayerIds={[constants.HIGH_SCORE_LAYER_NAME]}
|
||||
interactiveLayerIds={[constants.HIGH_ZOOM_LAYER_ID, constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID]}
|
||||
|
||||
// Callback props:
|
||||
// http://visgl.github.io/react-map-gl/docs/api-reference/interactive-map#callbacks
|
||||
onViewportChange={setViewport}
|
||||
onClick={onClick}
|
||||
onLoad={onLoad}
|
||||
onTransitionStart={onTransitionStart}
|
||||
onTransitionEnd={onTransitionEnd}
|
||||
|
||||
ref={mapRef}
|
||||
data-cy={'reactMapGL'}
|
||||
>
|
||||
{/**
|
||||
* The low zoom source
|
||||
*/}
|
||||
<Source
|
||||
id={constants.HIGH_SCORE_SOURCE_NAME}
|
||||
id={constants.LOW_ZOOM_SOURCE_NAME}
|
||||
type="vector"
|
||||
promoteId={constants.GEOID_PROPERTY}
|
||||
tiles={[constants.FEATURE_TILE_LOW_ZOOM_URL]}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_LOW}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_LOW}
|
||||
>
|
||||
|
||||
{/* Low zoom layer - prioritized features only */}
|
||||
<Layer
|
||||
id={constants.LOW_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={['>', constants.SCORE_PROPERTY_LOW, constants.SCORE_BOUNDARY_THRESHOLD]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
|
||||
'fill-opacity': constants.LOW_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY}}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_LOW}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_LOW}
|
||||
/>
|
||||
</Source>
|
||||
|
||||
{/**
|
||||
* The high zoom source
|
||||
*/}
|
||||
<Source
|
||||
id={constants.HIGH_ZOOM_SOURCE_NAME}
|
||||
type="vector"
|
||||
promoteId={constants.GEOID_PROPERTY}
|
||||
tiles={[constants.FEATURE_TILE_HIGH_ZOOM_URL]}
|
||||
maxzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
minzoom={constants.GLOBAL_MAX_ZOOM_HIGH}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_HIGH}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
>
|
||||
|
||||
{/* High zoom layer - non-prioritized features only */}
|
||||
<Layer
|
||||
id={constants.CURRENTLY_SELECTED_FEATURE_HIGHLIGHT_LAYER_NAME}
|
||||
id={constants.HIGH_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
type='line'
|
||||
filter={['<', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'line-color': constants.DEFAULT_OUTLINE_COLOR,
|
||||
'line-width': constants.CURRENTLY_SELECTED_FEATURE_LAYER_WIDTH,
|
||||
'line-opacity': constants.CURRENTLY_SELECTED_FEATURE_LAYER_OPACITY,
|
||||
'fill-opacity': constants.NON_PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGHLIGHT}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_HIGHLIGHT}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
|
||||
{/* High zoom layer - prioritized features only */}
|
||||
<Layer
|
||||
id={constants.BLOCK_GROUP_BOUNDARY_LAYER_NAME}
|
||||
type='line'
|
||||
id={constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={['>', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD]}
|
||||
type='fill'
|
||||
paint={{
|
||||
'line-color': constants.BORDER_HIGHLIGHT_COLOR,
|
||||
'line-width': constants.HIGHLIGHT_BORDER_WIDTH,
|
||||
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
|
||||
'fill-opacity': constants.HIGH_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
}}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
|
||||
{/* High zoom layer - controls the border between features */}
|
||||
<Layer
|
||||
id={constants.FEATURE_BORDER_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
type='line'
|
||||
paint={{
|
||||
'line-color': constants.FEATURE_BORDER_COLOR,
|
||||
'line-width': constants.FEATURE_BORDER_WIDTH,
|
||||
'line-opacity': constants.FEATURE_BORDER_OPACITY,
|
||||
}}
|
||||
maxzoom={constants.GLOBAL_MAX_ZOOM_FEATURE_BORDER}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_FEATURE_BORDER}
|
||||
/>
|
||||
|
||||
{/* High zoom layer - border styling around the selected feature */}
|
||||
<Layer
|
||||
id={constants.SELECTED_FEATURE_BORDER_LAYER_ID}
|
||||
source-layer={constants.SCORE_SOURCE_LAYER}
|
||||
filter={filter} // This filter filters out all other features except the selected feature.
|
||||
type='line'
|
||||
paint={{
|
||||
'line-color': constants.SELECTED_FEATURE_BORDER_COLOR,
|
||||
'line-width': constants.SELECTED_FEATURE_BORDER_WIDTH,
|
||||
}}
|
||||
filter={filter}
|
||||
minzoom={constants.GLOBAL_MIN_ZOOM_HIGH}
|
||||
/>
|
||||
</Source>
|
||||
|
||||
{/* Enable fullscreen behind a feature flag */}
|
||||
{('fs' in flags && detailViewData && !transitionInProgress) && (
|
||||
<Popup
|
||||
className={styles.j40Popup}
|
||||
|
@ -316,19 +395,26 @@ const J40Map = ({location}: IJ40Interface) => {
|
|||
<AreaDetail properties={detailViewData.properties} />
|
||||
</Popup>
|
||||
)}
|
||||
|
||||
{/* This will add the navigation controls of the zoom in and zoom out buttons */}
|
||||
<NavigationControl
|
||||
showCompass={false}
|
||||
className={styles.navigationControl}
|
||||
/>
|
||||
|
||||
{/* This places Geolocation behind a feature flag */}
|
||||
{'gl' in flags ? <GeolocateControl
|
||||
className={styles.geolocateControl}
|
||||
positionOptions={{enableHighAccuracy: true}}
|
||||
onGeolocate={onGeolocate}
|
||||
// @ts-ignore // Types have not caught up yet, see https://github.com/visgl/react-map-gl/issues/1492
|
||||
// @ts-ignore
|
||||
onClick={onClickGeolocate}
|
||||
/> : ''}
|
||||
{geolocationInProgress ? <div>Geolocation in progress...</div> : ''}
|
||||
|
||||
{/* This will show shortcut buttons to pan/zoom to US territories */}
|
||||
<TerritoryFocusControl onClick={onClick}/>
|
||||
|
||||
{'fs' in flags ? <FullscreenControl className={styles.fullscreenControl}/> :'' }
|
||||
|
||||
</ReactMapGL>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, {useState} from 'react';
|
||||
import {LngLatBoundsLike} from 'mapbox-gl';
|
||||
import {LngLatBoundsLike} from 'maplibre-gl';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import {Search} from '@trussworks/react-uswds';
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
import {LngLatBoundsLike} from 'maplibre-gl';
|
||||
import {isMobile as isMobileReactDeviceDetect} from 'react-device-detect';
|
||||
|
||||
export const isMobile = isMobileReactDeviceDetect;
|
||||
|
||||
const XYZ_SUFFIX = '{z}/{x}/{y}.pbf';
|
||||
export const featureURLForTilesetName = (tilesetName: string): string => {
|
||||
// The feature tile base URL and path can either point locally or the CDN.
|
||||
|
@ -29,18 +31,13 @@ export const FEATURE_TILE_LOW_ZOOM_URL = featureURLForTilesetName('low');
|
|||
// Performance markers
|
||||
export const PERFORMANCE_MARKER_MAP_IDLE = 'MAP_IDLE';
|
||||
|
||||
// ******* PROPERTIES FROM TILE SERVER **************
|
||||
export type J40Properties = { [key: string]: any };
|
||||
|
||||
// Properties
|
||||
export const SCORE_PROPERTY_HIGH = 'SL_PFS';
|
||||
export const SCORE_PROPERTY_LOW = 'L_SCORE';
|
||||
export const GEOID_PROPERTY = 'GEOID10';
|
||||
export const HIGH_SCORE_SOURCE_NAME = 'score-high';
|
||||
export const HIGH_SCORE_LAYER_NAME = 'score-high-layer';
|
||||
export const LOW_SCORE_SOURCE_NAME = 'score-low';
|
||||
export const LOW_SCORE_LAYER_NAME = 'score-low-layer';
|
||||
export const SELECTED_PROPERTY = 'selected';
|
||||
export const CURRENTLY_SELECTED_FEATURE_HIGHLIGHT_LAYER_NAME = 'currently-selected-feature-highlight-layer';
|
||||
export const BLOCK_GROUP_BOUNDARY_LAYER_NAME = 'block-group-boundary-layer';
|
||||
|
||||
|
||||
// Indicator values:
|
||||
export const ASTHMA_PERCENTILE = 'AF_PFS';
|
||||
|
@ -113,20 +110,57 @@ export const TOTAL_THRESHOLD_CRITERIA = 'TC';
|
|||
export const IS_GTE_90_ISLAND_AREA_UNEMPLOYMENT_AND_IS_LOW_HS_EDU_2009 = 'IAULHSE';
|
||||
export const IS_GTE_90_ISLAND_AREA_BELOW_100_POVERTY_AND_IS_LOW_HS_EDU_2009 = 'ISPLHSE';
|
||||
export const IS_GTE_90_ISLAND_AREA_LOW_MEDIAN_INCOME_AND_IS_LOW_HS_EDU_2009 = 'IALMILHSE';
|
||||
export type J40Properties = { [key: string]: any };
|
||||
|
||||
// The name of the layer within the tiles that contains the score
|
||||
export const SCORE_SOURCE_LAYER = 'blocks';
|
||||
|
||||
|
||||
// ********** MAP CONSTANTS ***************
|
||||
|
||||
// Source name constants
|
||||
export const BASE_MAP_SOURCE_NAME = 'base-map-source-name';
|
||||
export const HIGH_ZOOM_SOURCE_NAME = 'high-zoom-source-name';
|
||||
export const LOW_ZOOM_SOURCE_NAME = 'low-zoom-source-name';
|
||||
|
||||
// Layer ID constants
|
||||
export const BASE_MAP_LAYER_ID = 'base-map-layer-id';
|
||||
export const HIGH_ZOOM_LAYER_ID = 'high-zoom-layer-id';
|
||||
export const PRIORITIZED_HIGH_ZOOM_LAYER_ID = 'prioritized-high-zoom-layer-id';
|
||||
export const LOW_ZOOM_LAYER_ID = 'low-zoom-layer-id';
|
||||
export const FEATURE_BORDER_LAYER_ID = 'feature-border-layer-id';
|
||||
export const SELECTED_FEATURE_BORDER_LAYER_ID = 'selected-feature-border-layer-id';
|
||||
|
||||
// Zoom
|
||||
export const GLOBAL_MIN_ZOOM = 3;
|
||||
export const GLOBAL_MAX_ZOOM = 22;
|
||||
export const GLOBAL_MIN_ZOOM_LOW = 3;
|
||||
export const GLOBAL_MAX_ZOOM_LOW = 7;
|
||||
export const GLOBAL_MIN_ZOOM_HIGHLIGHT = 8;
|
||||
export const GLOBAL_MAX_ZOOM_HIGHLIGHT = 22;
|
||||
export const GLOBAL_MIN_ZOOM_HIGH = 7;
|
||||
export const GLOBAL_MAX_ZOOM_HIGH = 11;
|
||||
export const GLOBAL_MIN_ZOOM_FEATURE_BORDER = 8;
|
||||
export const GLOBAL_MAX_ZOOM_FEATURE_BORDER = 22;
|
||||
|
||||
// Opacity
|
||||
export const FEATURE_BORDER_OPACITY = 0.5;
|
||||
export const HIGH_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY = 0.3;
|
||||
export const LOW_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY = 0.6;
|
||||
export const NON_PRIORITIZED_FEATURE_FILL_OPACITY = 0;
|
||||
|
||||
// Colors
|
||||
export const FEATURE_BORDER_COLOR = '#4EA5CF';
|
||||
export const SELECTED_FEATURE_BORDER_COLOR = '#1A4480';
|
||||
export const PRIORITIZED_FEATURE_FILL_COLOR = '#768FB3';
|
||||
|
||||
// Widths
|
||||
export const FEATURE_BORDER_WIDTH = 0.8;
|
||||
export const SELECTED_FEATURE_BORDER_WIDTH = 5.0;
|
||||
|
||||
/**
|
||||
* This threshold will determine if the feature is prioritized
|
||||
* or not. Currently all values are railed to 0 or 1 so this value
|
||||
* doesn't really matter.
|
||||
*/
|
||||
export const SCORE_BOUNDARY_THRESHOLD = 0.6;
|
||||
|
||||
// Bounds - these bounds can be obtained by using the getCurrentMapBoundingBox() function in the map
|
||||
export const GLOBAL_MAX_BOUNDS: LngLatBoundsLike = [
|
||||
|
@ -175,25 +209,3 @@ export const US_VIRGIN_ISLANDS_BOUNDS: LngLatBoundsLike = [
|
|||
];
|
||||
|
||||
export const DEFAULT_CENTER = [33.4687126, -97.502136];
|
||||
|
||||
// Opacity
|
||||
export const DEFAULT_LAYER_OPACITY = 0.6;
|
||||
|
||||
// Colors
|
||||
export const DEFAULT_OUTLINE_COLOR = '#4EA5CF';
|
||||
export const MIN_COLOR = '#FFFFFF';
|
||||
export const MED_COLOR = '#D1DAE6';
|
||||
export const MAX_COLOR = '#768FB3';
|
||||
export const BORDER_HIGHLIGHT_COLOR = '#1A4480';
|
||||
export const CURRENTLY_SELECTED_FEATURE_LAYER_OPACITY = 0.5;
|
||||
|
||||
// Widths
|
||||
export const HIGHLIGHT_BORDER_WIDTH = 5.0;
|
||||
export const CURRENTLY_SELECTED_FEATURE_LAYER_WIDTH = 0.8;
|
||||
|
||||
// Score boundaries
|
||||
export const SCORE_BOUNDARY_LOW = 0.0;
|
||||
export const SCORE_BOUNDARY_THRESHOLD = 0.6;
|
||||
export const SCORE_BOUNDARY_PRIORITIZED = 0.75;
|
||||
|
||||
export const isMobile = isMobileReactDeviceDetect;
|
||||
|
|
|
@ -1,67 +1,106 @@
|
|||
import {Style, FillPaint} from 'maplibre-gl';
|
||||
import chroma from 'chroma-js';
|
||||
import {Style} from 'maplibre-gl';
|
||||
import * as constants from '../data/constants';
|
||||
import {FlagContainer} from '../contexts/FlagContext';
|
||||
|
||||
// eslint-disable-next-line require-jsdoc
|
||||
function hexToHSLA(hex:string, alpha:number) {
|
||||
return chroma(hex).alpha(alpha).css('hsl');
|
||||
}
|
||||
|
||||
/**
|
||||
* `MakePaint` generates a zoom-faded Maplibre style formatted layer given a set of parameters.
|
||||
*
|
||||
* @param {string} field : the field within the data to consult
|
||||
* @param {number} minRamp : the minimum value this can assume
|
||||
* @param {number} medRamp : the medium value this can assume
|
||||
* @param {number} maxRamp : the maximum value this can assume
|
||||
* @return {FillPaint} a maplibregl fill layer
|
||||
**/
|
||||
function makePaint({
|
||||
field,
|
||||
minRamp,
|
||||
medRamp,
|
||||
maxRamp,
|
||||
}: {
|
||||
field: string;
|
||||
minRamp: number;
|
||||
medRamp: number;
|
||||
maxRamp: number;
|
||||
}): FillPaint {
|
||||
const paintDescriptor : FillPaint = {
|
||||
'fill-color': [
|
||||
'step',
|
||||
['get', field],
|
||||
hexToHSLA(constants.MIN_COLOR, constants.DEFAULT_LAYER_OPACITY ),
|
||||
minRamp,
|
||||
hexToHSLA(constants.MIN_COLOR, constants.DEFAULT_LAYER_OPACITY ),
|
||||
medRamp,
|
||||
hexToHSLA(constants.MED_COLOR, constants.DEFAULT_LAYER_OPACITY ),
|
||||
maxRamp,
|
||||
hexToHSLA(constants.MAX_COLOR, constants.DEFAULT_LAYER_OPACITY ),
|
||||
],
|
||||
};
|
||||
return paintDescriptor;
|
||||
}
|
||||
|
||||
// *********** BASE MAP SOURCES ***************
|
||||
const imageSuffix = constants.isMobile ? '' : '@2x';
|
||||
|
||||
export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
|
||||
return {
|
||||
'version': 8,
|
||||
'sources': {
|
||||
'carto': {
|
||||
'type': 'raster',
|
||||
'tiles':
|
||||
[
|
||||
// Original "light" Base layer
|
||||
// Additional layers found here: https://carto.com/help/building-maps/basemap-list/#carto-vector-basemaps
|
||||
const cartoLightBaseLayer = {
|
||||
noLabels: [
|
||||
`https://a.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://b.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://c.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://d.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
],
|
||||
labelsOnly: [
|
||||
`https://cartodb-basemaps-a.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://cartodb-basemaps-b.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://cartodb-basemaps-c.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://cartodb-basemaps-d.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
],
|
||||
};
|
||||
|
||||
// MapTiler base map source
|
||||
// Todo: move API key to .env
|
||||
const getMapTilerBaseLayer = (name:string, API_KEY='KMA4bawPDNtR6zNIAfUH') => {
|
||||
return [
|
||||
`https://api.maptiler.com/maps/${name}/{z}/{x}/{y}${imageSuffix}.png?key=${API_KEY}`,
|
||||
];
|
||||
};
|
||||
|
||||
// Utility function to make map styles according to JSON spec of MapBox
|
||||
// https://docs.mapbox.com/mapbox-gl-js/style-spec/
|
||||
export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
|
||||
// Add flags for various types of MapTiler base maps:
|
||||
const getBaseMapLayer = () => {
|
||||
if ('mt-streets' in flagContainer) {
|
||||
return getMapTilerBaseLayer('streets');
|
||||
} else if ('mt-bright' in flagContainer) {
|
||||
return getMapTilerBaseLayer('bright');
|
||||
} else if ('mt-voyager' in flagContainer) {
|
||||
return getMapTilerBaseLayer('voyager');
|
||||
} else if ('mt-osm' in flagContainer) {
|
||||
return getMapTilerBaseLayer('osm-standard');
|
||||
} else {
|
||||
return cartoLightBaseLayer.noLabels;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
'version': 8,
|
||||
|
||||
/**
|
||||
* Removing any sources, removes the map from rendering, since the layers key is depenedent on these
|
||||
* sources.
|
||||
*
|
||||
* - base map source: This source control the base map.
|
||||
* - geo: currently not being used
|
||||
* - high zoom source: comes from our tile server for high zoom tiles
|
||||
* - low zoom source: comes from our tile server for low zoom tiles
|
||||
* - labels source: currently using carto's label-only source
|
||||
* */
|
||||
'sources': {
|
||||
|
||||
/**
|
||||
* The base map source source allows us to define where the tiles can be fetched from.
|
||||
* Currently we are evaluating carto, MapTiler, Geoampify and MapBox for viable base maps.
|
||||
*/
|
||||
[constants.BASE_MAP_SOURCE_NAME]: {
|
||||
'type': 'raster',
|
||||
'tiles': getBaseMapLayer(),
|
||||
|
||||
/**
|
||||
* Attempting to place a direct call to mapbox URL:
|
||||
*/
|
||||
// 'type': 'raster',
|
||||
// 'tiles': [`mapbox://styles/mapbox/streets-v11`],
|
||||
|
||||
/**
|
||||
* This MapBox Raster seems to work, however the tileset curently available in MapBox
|
||||
* is the "satellite" tileset. Messaged Mikel on more options.
|
||||
*/
|
||||
// 'type': 'raster',
|
||||
// 'tiles': [
|
||||
// `https://api.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoianVzdGljZTQwIiwiYSI6ImNreGF1Z3loNjB0N3oybm9jdGpxeDZ4b3kifQ.76tMHU7C8wwn0HGsF6azjA`,
|
||||
// ],
|
||||
|
||||
/**
|
||||
* This MapBox Vector does not work, attempting to place this in the main component as
|
||||
* a <Source> and <Layer> component also did not work.
|
||||
*/
|
||||
// 'type': 'vector',
|
||||
// 'tiles': [
|
||||
// `https://api.mapbox.com/v4/mapbox.mapbox-streets-v8/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1IjoianVzdGljZTQwIiwiYSI6ImNreGF1Z3loNjB0N3oybm9jdGpxeDZ4b3kifQ.76tMHU7C8wwn0HGsF6azjA`,
|
||||
// ],
|
||||
|
||||
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||
},
|
||||
|
||||
// In the layer (below) where the geo source is used, the layer is invisible
|
||||
'geo': {
|
||||
'type': 'raster',
|
||||
'tiles': [
|
||||
|
@ -70,10 +109,10 @@ export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
|
|||
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||
},
|
||||
[constants.HIGH_SCORE_SOURCE_NAME]: {
|
||||
// "Score-high" represents the full set of data
|
||||
// at the census block group level. It is only shown
|
||||
// at high zoom levels to avoid performance issues at lower zooms
|
||||
|
||||
// The High zoom source:
|
||||
[constants.HIGH_ZOOM_SOURCE_NAME]: {
|
||||
// It is only shown at high zoom levels to avoid performance issues at lower zooms
|
||||
'type': 'vector',
|
||||
// Our current tippecanoe command does not set an id.
|
||||
// The below line promotes the GEOID10 property to the ID
|
||||
|
@ -83,13 +122,15 @@ export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
|
|||
constants.featureURLForTilesetName(flagContainer['high_tiles']) :
|
||||
constants.FEATURE_TILE_HIGH_ZOOM_URL,
|
||||
],
|
||||
// Seeting maxzoom here enables 'overzooming'
|
||||
// Setting maxzoom here enables 'overzooming'
|
||||
// e.g. continued zooming beyond the max bounds.
|
||||
// More here: https://docs.mapbox.com/help/glossary/overzoom/
|
||||
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
|
||||
'maxzoom': constants.GLOBAL_MAX_ZOOM_HIGH,
|
||||
},
|
||||
[constants.LOW_SCORE_SOURCE_NAME]: {
|
||||
|
||||
// The Low zoom source:
|
||||
[constants.LOW_ZOOM_SOURCE_NAME]: {
|
||||
// "Score-low" represents a tileset at the level of bucketed tracts.
|
||||
// census block group information is `dissolve`d into tracts, then
|
||||
// each tract is `dissolve`d into one of ten buckets. It is meant
|
||||
|
@ -106,70 +147,126 @@ export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
|
|||
'minzoom': constants.GLOBAL_MIN_ZOOM_LOW,
|
||||
'maxzoom': constants.GLOBAL_MAX_ZOOM_LOW,
|
||||
},
|
||||
|
||||
// The labels source:
|
||||
'labels': {
|
||||
'type': 'raster',
|
||||
'tiles': [
|
||||
`https://cartodb-basemaps-a.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://cartodb-basemaps-b.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://cartodb-basemaps-c.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
`https://cartodb-basemaps-d.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||
],
|
||||
'tiles': cartoLightBaseLayer.labelsOnly,
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Each object in the layers array references it's source via the source key.
|
||||
* Each layer stacks upon the previous layer in the array of layers.
|
||||
*
|
||||
* - baseMapLayer: the base layer without labels
|
||||
* - geo: a geographical layer that is not being used
|
||||
* - high zoom layer - non-prioritized features only
|
||||
* - high zoom layer - prioritized features only
|
||||
* - low zoom layer - prioritized features only
|
||||
* - labels only layer
|
||||
*/
|
||||
'layers': [
|
||||
// The baseMapLayer
|
||||
{
|
||||
'id': 'carto',
|
||||
'source': 'carto',
|
||||
'id': constants.BASE_MAP_LAYER_ID,
|
||||
'source': constants.BASE_MAP_SOURCE_NAME,
|
||||
'type': 'raster',
|
||||
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||
},
|
||||
|
||||
// The Geo layer adds a geographical layer like mountains and rivers
|
||||
{
|
||||
'id': 'geo',
|
||||
'source': 'geo',
|
||||
'type': 'raster',
|
||||
'layout': {
|
||||
// Make the layer invisible by default.
|
||||
'visibility': 'none',
|
||||
// Place visibility behind flag:
|
||||
'visibility': 'geo' in flagContainer ? 'visible' : 'none',
|
||||
},
|
||||
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||
},
|
||||
|
||||
/**
|
||||
* High zoom layer - non-prioritized features only
|
||||
*/
|
||||
{
|
||||
'id': constants.HIGH_SCORE_LAYER_NAME,
|
||||
'source': constants.HIGH_SCORE_SOURCE_NAME,
|
||||
'id': constants.HIGH_ZOOM_LAYER_ID,
|
||||
'source': constants.HIGH_ZOOM_SOURCE_NAME,
|
||||
'source-layer': constants.SCORE_SOURCE_LAYER,
|
||||
/**
|
||||
* This shows features where the high score < score boundary threshold.
|
||||
* In other words, this filter out prioritized features
|
||||
*/
|
||||
'filter': ['all',
|
||||
['<', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD],
|
||||
],
|
||||
|
||||
'type': 'fill',
|
||||
'paint': makePaint({
|
||||
field: constants.SCORE_PROPERTY_HIGH,
|
||||
minRamp: constants.SCORE_BOUNDARY_LOW,
|
||||
medRamp: constants.SCORE_BOUNDARY_THRESHOLD,
|
||||
maxRamp: constants.SCORE_BOUNDARY_PRIORITIZED,
|
||||
}),
|
||||
'paint': {
|
||||
'fill-opacity': constants.NON_PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
},
|
||||
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
|
||||
},
|
||||
|
||||
/**
|
||||
* High zoom layer - prioritized features only
|
||||
*/
|
||||
{
|
||||
'id': constants.LOW_SCORE_LAYER_NAME,
|
||||
'source': constants.LOW_SCORE_SOURCE_NAME,
|
||||
'id': constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID,
|
||||
'source': constants.HIGH_ZOOM_SOURCE_NAME,
|
||||
'source-layer': constants.SCORE_SOURCE_LAYER,
|
||||
/**
|
||||
* This shows features where the high score > score boundary threshold.
|
||||
* In other words, this filter out non-prioritized features
|
||||
*/
|
||||
'filter': ['all',
|
||||
['>', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD],
|
||||
],
|
||||
|
||||
'type': 'fill',
|
||||
'paint': {
|
||||
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
|
||||
'fill-opacity': constants.PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
},
|
||||
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Low zoom layer - prioritized features only
|
||||
*/
|
||||
{
|
||||
'id': constants.LOW_ZOOM_LAYER_ID,
|
||||
'source': constants.LOW_ZOOM_SOURCE_NAME,
|
||||
'source-layer': constants.SCORE_SOURCE_LAYER,
|
||||
/**
|
||||
* This shows features where the low score > score boundary threshold.
|
||||
* In other words, this filter out non-prioritized features
|
||||
*/
|
||||
'filter': ['all',
|
||||
['>', constants.SCORE_PROPERTY_LOW, constants.SCORE_BOUNDARY_THRESHOLD],
|
||||
],
|
||||
'paint': makePaint({
|
||||
field: constants.SCORE_PROPERTY_LOW,
|
||||
minRamp: constants.SCORE_BOUNDARY_LOW,
|
||||
medRamp: constants.SCORE_BOUNDARY_THRESHOLD,
|
||||
maxRamp: constants.SCORE_BOUNDARY_PRIORITIZED,
|
||||
}),
|
||||
|
||||
'type': 'fill',
|
||||
'paint': {
|
||||
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
|
||||
'fill-opacity': constants.PRIORITIZED_FEATURE_FILL_OPACITY,
|
||||
},
|
||||
'minzoom': constants.GLOBAL_MIN_ZOOM_LOW,
|
||||
'maxzoom': constants.GLOBAL_MAX_ZOOM_LOW,
|
||||
},
|
||||
|
||||
// A layer for labels only
|
||||
{
|
||||
// We put labels last to ensure prominence
|
||||
'id': 'labels-only-layer',
|
||||
'type': 'raster',
|
||||
'source': 'labels',
|
||||
'type': 'raster',
|
||||
'layout': {
|
||||
'visibility': 'remove-label-layer' in flagContainer ? 'none' : 'visible',
|
||||
},
|
||||
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||
},
|
||||
|
|
|
@ -193,24 +193,24 @@ This section will outline styles that are component specific
|
|||
// but it after 1.14.0 it optionally still allows for the mapbox-gl prefix
|
||||
|
||||
// Below properties override mb defaults
|
||||
.mapboxgl-ctrl-group:not(:empty) {
|
||||
box-shadow: none;
|
||||
}
|
||||
// .mapboxgl-ctrl-group:not(:empty) {
|
||||
// box-shadow: none;
|
||||
// }
|
||||
|
||||
@media (-ms-high-contrast: active) {
|
||||
.mapboxgl-ctrl-group:not(:empty) {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
// @media (-ms-high-contrast: active) {
|
||||
// .mapboxgl-ctrl-group:not(:empty) {
|
||||
// box-shadow: none;
|
||||
// }
|
||||
// }
|
||||
|
||||
.mapboxgl-ctrl-group {
|
||||
border-radius: 0;
|
||||
}
|
||||
// .mapboxgl-ctrl-group {
|
||||
// border-radius: 0;
|
||||
// }
|
||||
|
||||
.mapboxgl-ctrl {
|
||||
button + button {
|
||||
border-top: 1px;
|
||||
}
|
||||
// button + button {
|
||||
// border-top: 1px;
|
||||
// }
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
|
@ -316,7 +316,7 @@ This section will outline styles that are component specific
|
|||
******************************
|
||||
*/
|
||||
|
||||
/* about card - based on datasetCard... need to combine */
|
||||
/* about card - based on datasetCard... Todo: need to combine */
|
||||
.j40-aboutcard-container {
|
||||
|
||||
.j40-aboutcard-lg-card {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue