mirror of
https://github.com/DOI-DO/j40-cejst-2.git
synced 2025-07-29 20:21:17 -07:00
Adding low zoom level styling (#334)
* Fixes #201 - As an EVCM, I want the map to make sense at varying zoom levels so that I'm not confused . For now uses a usa_low tileset created as part of #209 for zoom levels 3-7. Will need further iteration * Adding comments
This commit is contained in:
parent
842312f69f
commit
68c345b950
4 changed files with 117 additions and 51 deletions
|
@ -39,7 +39,7 @@ describe('Tests for the Explore the Map page', () => {
|
||||||
return map.getFeatureState(
|
return map.getFeatureState(
|
||||||
{
|
{
|
||||||
'id': id,
|
'id': id,
|
||||||
'source': constants.SCORE_SOURCE_NAME,
|
'source': constants.HIGH_SCORE_SOURCE_NAME,
|
||||||
'sourceLayer': constants.SCORE_SOURCE_LAYER,
|
'sourceLayer': constants.SCORE_SOURCE_LAYER,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,7 +8,6 @@ import maplibregl, {LngLatBoundsLike,
|
||||||
LngLatLike,
|
LngLatLike,
|
||||||
MapboxGeoJSONFeature} from 'maplibre-gl';
|
MapboxGeoJSONFeature} from 'maplibre-gl';
|
||||||
import mapStyle from '../data/mapStyle';
|
import mapStyle from '../data/mapStyle';
|
||||||
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';
|
||||||
|
@ -76,7 +75,7 @@ const J40Map = () => {
|
||||||
const map = e.target;
|
const map = e.target;
|
||||||
const clickedCoord = e.point;
|
const clickedCoord = e.point;
|
||||||
const features = map.queryRenderedFeatures(clickedCoord, {
|
const features = map.queryRenderedFeatures(clickedCoord, {
|
||||||
layers: ['score'],
|
layers: [constants.HIGH_SCORE_LAYER_NAME],
|
||||||
});
|
});
|
||||||
const feature = features && features[0];
|
const feature = features && features[0];
|
||||||
if (feature) {
|
if (feature) {
|
||||||
|
@ -107,10 +106,10 @@ const J40Map = () => {
|
||||||
mapRef.current.on('move', () => {
|
mapRef.current.on('move', () => {
|
||||||
setZoom(mapRef.current.getZoom());
|
setZoom(mapRef.current.getZoom());
|
||||||
});
|
});
|
||||||
mapRef.current.on('mouseenter', 'score', () => {
|
mapRef.current.on('mouseenter', constants.HIGH_SCORE_LAYER_NAME, () => {
|
||||||
mapRef.current.getCanvas().style.cursor = 'pointer';
|
mapRef.current.getCanvas().style.cursor = 'pointer';
|
||||||
});
|
});
|
||||||
mapRef.current.on('mouseleave', 'score', () => {
|
mapRef.current.on('mouseleave', constants.HIGH_SCORE_LAYER_NAME, () => {
|
||||||
mapRef.current.getCanvas().style.cursor = '';
|
mapRef.current.getCanvas().style.cursor = '';
|
||||||
});
|
});
|
||||||
}, [mapRef]);
|
}, [mapRef]);
|
||||||
|
@ -177,7 +176,6 @@ const J40Map = () => {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div ref={mapContainer} className={styles.mapContainer}/>
|
<div ref={mapContainer} className={styles.mapContainer}/>
|
||||||
<ZoomWarning zoomLevel={zoom} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
// URLS
|
// URLS
|
||||||
export const FEATURE_TILE_BASE_URL = 'https://d2zjid6n5ja2pt.cloudfront.net/0629_demo';
|
export const FEATURE_TILE_BASE_URL = 'https://d2zjid6n5ja2pt.cloudfront.net';
|
||||||
|
const XYZ_SUFFIX = '{z}/{x}/{y}.pbf';
|
||||||
|
export const FEATURE_TILE_HIGH_ZOOM_URL = `${FEATURE_TILE_BASE_URL}/0629_demo/${XYZ_SUFFIX}`;
|
||||||
|
export const FEATURE_TILE_LOW_ZOOM_URL = `${FEATURE_TILE_BASE_URL}/tiles_low/${XYZ_SUFFIX}`;
|
||||||
|
|
||||||
|
|
||||||
// Performance markers
|
// Performance markers
|
||||||
export const PERFORMANCE_MARKER_MAP_IDLE = 'MAP_IDLE';
|
export const PERFORMANCE_MARKER_MAP_IDLE = 'MAP_IDLE';
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
export const SCORE_PROPERTY = 'Score D (percentile)';
|
export const SCORE_PROPERTY_HIGH = 'Score D (percentile)';
|
||||||
|
export const SCORE_PROPERTY_LOW = 'D_SCORE';
|
||||||
export const GEOID_PROPERTY = 'GEOID10';
|
export const GEOID_PROPERTY = 'GEOID10';
|
||||||
export const SCORE_SOURCE_NAME = 'score';
|
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';
|
||||||
|
|
||||||
// The name of the layer within the tiles that contains the score
|
// The name of the layer within the tiles that contains the score
|
||||||
export const SCORE_SOURCE_LAYER = 'blocks';
|
export const SCORE_SOURCE_LAYER = 'blocks';
|
||||||
|
|
||||||
|
@ -18,8 +27,10 @@ export type J40Properties = { [key: string]: any };
|
||||||
export const GLOBAL_MIN_ZOOM = 3;
|
export const GLOBAL_MIN_ZOOM = 3;
|
||||||
export const GLOBAL_MAX_ZOOM = 22;
|
export const GLOBAL_MAX_ZOOM = 22;
|
||||||
export const GLOBAL_MIN_ZOOM_LOW = 3;
|
export const GLOBAL_MIN_ZOOM_LOW = 3;
|
||||||
export const GLOBAL_MAX_ZOOM_LOW = 9;
|
export const GLOBAL_MAX_ZOOM_LOW = 7;
|
||||||
export const GLOBAL_MIN_ZOOM_HIGH = 9;
|
export const GLOBAL_MIN_ZOOM_HIGHLIGHT = 9;
|
||||||
|
export const GLOBAL_MAX_ZOOM_HIGHLIGHT = 22;
|
||||||
|
export const GLOBAL_MIN_ZOOM_HIGH = 7;
|
||||||
export const GLOBAL_MAX_ZOOM_HIGH = 11;
|
export const GLOBAL_MAX_ZOOM_HIGH = 11;
|
||||||
|
|
||||||
// Bounds
|
// Bounds
|
||||||
|
@ -74,3 +85,13 @@ export const MIN_COLOR = '#FFFFFF';
|
||||||
export const MED_COLOR = '#D1DAE6';
|
export const MED_COLOR = '#D1DAE6';
|
||||||
export const MAX_COLOR = '#768FB3';
|
export const MAX_COLOR = '#768FB3';
|
||||||
export const BORDER_HIGHLIGHT_COLOR = '#00BDE3';
|
export const BORDER_HIGHLIGHT_COLOR = '#00BDE3';
|
||||||
|
|
||||||
|
// Widths
|
||||||
|
export const HIGHLIGHT_BORDER_WIDTH = 5.0;
|
||||||
|
|
||||||
|
// 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 = typeof window !== 'undefined' && (window.innerWidth < 400);
|
||||||
|
|
|
@ -43,47 +43,70 @@ function makePaint({
|
||||||
return paintDescriptor;
|
return paintDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const imageSuffix = constants.isMobile ? '' : '@2x';
|
||||||
|
|
||||||
const mapStyle : Style = {
|
const mapStyle : Style = {
|
||||||
'version': 8,
|
'version': 8,
|
||||||
'sources': {
|
'sources': {
|
||||||
'carto': {
|
'carto': {
|
||||||
'type': 'raster',
|
'type': 'raster',
|
||||||
'tiles': [
|
'tiles':
|
||||||
'https://a.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png',
|
[
|
||||||
'https://b.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png',
|
`https://a.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||||
'https://c.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png',
|
`https://b.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||||
'https://d.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.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`,
|
||||||
],
|
],
|
||||||
|
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||||
|
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||||
},
|
},
|
||||||
'geo': {
|
'geo': {
|
||||||
'type': 'raster',
|
'type': 'raster',
|
||||||
'tiles': [
|
'tiles': [
|
||||||
'https://mt0.google.com/vt/lyrs=p&hl=en&x={x}&y={y}&z={z}',
|
'https://mt0.google.com/vt/lyrs=p&hl=en&x={x}&y={y}&z={z}',
|
||||||
],
|
],
|
||||||
|
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||||
|
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||||
},
|
},
|
||||||
'score': {
|
'score-high': {
|
||||||
|
// "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
|
||||||
'type': 'vector',
|
'type': 'vector',
|
||||||
// Our current tippecanoe command does not set an id.
|
// Our current tippecanoe command does not set an id.
|
||||||
// The below line promotes the GEOID10 property to the ID
|
// The below line promotes the GEOID10 property to the ID
|
||||||
'promoteId': 'GEOID10',
|
'promoteId': constants.GEOID_PROPERTY,
|
||||||
'tiles': [
|
'tiles': [
|
||||||
`${constants.FEATURE_TILE_BASE_URL}/{z}/{x}/{y}.pbf`,
|
constants.FEATURE_TILE_HIGH_ZOOM_URL,
|
||||||
// For local development, use:
|
|
||||||
// 'http://localhost:8080/data/tl_2010_bg_with_data/{z}/{x}/{y}.pbf',
|
|
||||||
],
|
],
|
||||||
|
|
||||||
// Seeting maxzoom here enables 'overzooming'
|
// Seeting maxzoom here enables 'overzooming'
|
||||||
// e.g. continued zooming beyond the max bounds.
|
// e.g. continued zooming beyond the max bounds.
|
||||||
// More here: https://docs.mapbox.com/help/glossary/overzoom/
|
// More here: https://docs.mapbox.com/help/glossary/overzoom/
|
||||||
|
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
|
||||||
'maxzoom': constants.GLOBAL_MAX_ZOOM_HIGH,
|
'maxzoom': constants.GLOBAL_MAX_ZOOM_HIGH,
|
||||||
},
|
},
|
||||||
|
'score-low': {
|
||||||
|
// "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
|
||||||
|
// to give us a favorable tradeoff between performance and fidelity.
|
||||||
|
'type': 'vector',
|
||||||
|
'promoteId': constants.GEOID_PROPERTY,
|
||||||
|
'tiles': [
|
||||||
|
constants.FEATURE_TILE_LOW_ZOOM_URL,
|
||||||
|
// For local development, use:
|
||||||
|
// 'http://localhost:8080/data/tl_2010_bg_with_data/{z}/{x}/{y}.pbf',
|
||||||
|
],
|
||||||
|
'minzoom': constants.GLOBAL_MIN_ZOOM_LOW,
|
||||||
|
'maxzoom': constants.GLOBAL_MAX_ZOOM_LOW,
|
||||||
|
},
|
||||||
'labels': {
|
'labels': {
|
||||||
'type': 'raster',
|
'type': 'raster',
|
||||||
'tiles': [
|
'tiles': [
|
||||||
'https://cartodb-basemaps-a.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}@2x.png',
|
`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}@2x.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}@2x.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}@2x.png',
|
`https://cartodb-basemaps-d.global.ssl.fastly.net/light_only_labels/{z}/{x}/{y}${imageSuffix}.png`,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -92,42 +115,60 @@ const mapStyle : Style = {
|
||||||
'id': 'carto',
|
'id': 'carto',
|
||||||
'source': 'carto',
|
'source': 'carto',
|
||||||
'type': 'raster',
|
'type': 'raster',
|
||||||
'minzoom': constants.GLOBAL_MIN_ZOOM - 1,
|
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||||
|
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'geo',
|
'id': 'geo',
|
||||||
'source': 'geo',
|
'source': 'geo',
|
||||||
'type': 'raster',
|
'type': 'raster',
|
||||||
'minzoom': constants.GLOBAL_MIN_ZOOM - 1,
|
|
||||||
'layout': {
|
'layout': {
|
||||||
// Make the layer visible by default.
|
// Make the layer invisible by default.
|
||||||
'visibility': 'none',
|
'visibility': 'none',
|
||||||
},
|
},
|
||||||
},
|
|
||||||
{
|
|
||||||
'id': 'score',
|
|
||||||
'source': constants.SCORE_SOURCE_NAME,
|
|
||||||
'source-layer': constants.SCORE_SOURCE_LAYER,
|
|
||||||
'type': 'fill',
|
|
||||||
'filter': ['all',
|
|
||||||
['>', constants.SCORE_PROPERTY, 0.6],
|
|
||||||
// ['in', 'STATEFP10', '01', '30', '34', '35', '36'],
|
|
||||||
],
|
|
||||||
'paint': makePaint({
|
|
||||||
field: constants.SCORE_PROPERTY,
|
|
||||||
minRamp: 0,
|
|
||||||
medRamp: 0.6,
|
|
||||||
maxRamp: 0.75,
|
|
||||||
}),
|
|
||||||
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||||
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
'id': constants.HIGH_SCORE_LAYER_NAME,
|
||||||
|
'source': constants.HIGH_SCORE_SOURCE_NAME,
|
||||||
|
'source-layer': constants.SCORE_SOURCE_LAYER,
|
||||||
|
'type': 'fill',
|
||||||
|
'filter': ['all',
|
||||||
|
['>', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD],
|
||||||
|
],
|
||||||
|
'paint': makePaint({
|
||||||
|
field: constants.SCORE_PROPERTY_HIGH,
|
||||||
|
minRamp: constants.SCORE_BOUNDARY_LOW,
|
||||||
|
medRamp: constants.SCORE_BOUNDARY_THRESHOLD,
|
||||||
|
maxRamp: constants.SCORE_BOUNDARY_PRIORITIZED,
|
||||||
|
}),
|
||||||
|
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': constants.LOW_SCORE_LAYER_NAME,
|
||||||
|
'source': constants.LOW_SCORE_SOURCE_NAME,
|
||||||
|
'source-layer': constants.SCORE_SOURCE_LAYER,
|
||||||
|
'type': 'fill',
|
||||||
|
'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,
|
||||||
|
}),
|
||||||
|
'minzoom': constants.GLOBAL_MIN_ZOOM_LOW,
|
||||||
|
'maxzoom': constants.GLOBAL_MAX_ZOOM_LOW,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// "Score-highlights" represents the border
|
||||||
|
// around given tiles that appears at higher zooms
|
||||||
'id': 'score-highlights',
|
'id': 'score-highlights',
|
||||||
'source': 'score',
|
'source': constants.HIGH_SCORE_SOURCE_NAME,
|
||||||
'source-layer': constants.SCORE_SOURCE_LAYER,
|
'source-layer': constants.SCORE_SOURCE_LAYER,
|
||||||
'type': 'line',
|
'type': 'line',
|
||||||
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
|
|
||||||
'layout': {
|
'layout': {
|
||||||
'visibility': 'visible',
|
'visibility': 'visible',
|
||||||
'line-join': 'round',
|
'line-join': 'round',
|
||||||
|
@ -138,13 +179,15 @@ const mapStyle : Style = {
|
||||||
'line-width': 0.8,
|
'line-width': 0.8,
|
||||||
'line-opacity': 0.5,
|
'line-opacity': 0.5,
|
||||||
},
|
},
|
||||||
|
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGHLIGHT,
|
||||||
|
'maxzoom': constants.GLOBAL_MAX_ZOOM_HIGHLIGHT,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// This layer queries the feature-state property "selected" and
|
// "score-border-highlight" is used to highlight
|
||||||
// highlights the border of the selected region if true
|
// the currently-selected feature
|
||||||
'id': 'score-border-highlight',
|
'id': 'score-border-highlight',
|
||||||
'type': 'line',
|
'type': 'line',
|
||||||
'source': 'score',
|
'source': constants.HIGH_SCORE_SOURCE_NAME,
|
||||||
'source-layer': constants.SCORE_SOURCE_LAYER,
|
'source-layer': constants.SCORE_SOURCE_LAYER,
|
||||||
'layout': {},
|
'layout': {},
|
||||||
'paint': {
|
'paint': {
|
||||||
|
@ -152,16 +195,20 @@ const mapStyle : Style = {
|
||||||
'line-width': [
|
'line-width': [
|
||||||
'case',
|
'case',
|
||||||
['boolean', ['feature-state', 'selected'], false],
|
['boolean', ['feature-state', 'selected'], false],
|
||||||
5.0,
|
constants.HIGHLIGHT_BORDER_WIDTH,
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
|
||||||
|
'maxzoom': constants.GLOBAL_MAX_ZOOM_HIGH,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// We put labels last to ensure prominence
|
||||||
'id': 'labels-only',
|
'id': 'labels-only',
|
||||||
'type': 'raster',
|
'type': 'raster',
|
||||||
'source': 'labels',
|
'source': 'labels',
|
||||||
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
'minzoom': constants.GLOBAL_MIN_ZOOM,
|
||||||
|
'maxzoom': constants.GLOBAL_MAX_ZOOM,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue