Allow open source map with new API key (#1155)

* Allow open source map

- create new getOSBaseMap function
- set secret on GitHub actions
- read secret into J40Map.tsx
- add secret to gatsby-config
- remove secret from .env.*

* Fix typo on yml file

* Add placeholder for API TOKEN

- add placeholder in docker compose
- add placeholder in .env.dev
- remove console.log

* Add Mapbox API Token to main deploy
This commit is contained in:
Vim 2022-01-18 15:16:33 -05:00 committed by GitHub
parent 18f299c5f8
commit f4926376fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 214 additions and 145 deletions

View file

@ -39,6 +39,7 @@ jobs:
DATA_SOURCE: cdn DATA_SOURCE: cdn
# TODO: Update main URL when either is back up # TODO: Update main URL when either is back up
SITE_URL: https://d29zfl8cj7y1zf.cloudfront.net/ SITE_URL: https://d29zfl8cj7y1zf.cloudfront.net/
MAPBOX_STYLES_READ_TOKEN: "${{ secrets.MAPBOX_STYLES_READ_TOKEN }}"
- name: Get directory contents - name: Get directory contents
run: ls -la public run: ls -la public
- name: Lint - name: Lint

View file

@ -38,6 +38,7 @@ jobs:
DATA_SOURCE: cdn DATA_SOURCE: cdn
SITE_URL: "http://usds-geoplatform-justice40-website.s3-website-us-east-1.amazonaws.com/" SITE_URL: "http://usds-geoplatform-justice40-website.s3-website-us-east-1.amazonaws.com/"
PATH_PREFIX: "/justice40-tool/${{env.DESTINATION_FOLDER}}" PATH_PREFIX: "/justice40-tool/${{env.DESTINATION_FOLDER}}"
MAPBOX_STYLES_READ_TOKEN: "${{ secrets.MAPBOX_STYLES_READ_TOKEN }}"
- name: Get directory contents - name: Get directory contents
run: ls -la public run: ls -la public
- name: Lint - name: Lint

View file

@ -12,4 +12,7 @@ GATSBY_DATA_PIPELINE_SCORE_PATH=data-pipeline/data/score
GATSBY_SCORE_DOWNLOAD_FILE_PATH=downloadable/Screening_Tool_Data.zip GATSBY_SCORE_DOWNLOAD_FILE_PATH=downloadable/Screening_Tool_Data.zip
GATSBY_MAP_TILES_PATH=tiles GATSBY_MAP_TILES_PATH=tiles
GATSBY_MAPBOX_STYLES_READ_TOKEN=pk.eyJ1IjoianVzdGljZTQwIiwiYSI6ImNreHRub2QxdTV6dnUzMHBmZDdzZXQ4YWMifQ.Fc-my99OtAwP5zEXCgrx_g # If you want the map to render a MapBox base map (as opposed to the
# open source one from CartoDB), please create your own API TOKEN from
# your MapBox account and add the token here:
# MAPBOX_STYLES_READ_TOKEN=''

View file

@ -8,5 +8,3 @@ GATSBY_CDN_TILES_BASE_URL=https://d3jqyw10j8e7p9.cloudfront.net
GATSBY_DATA_PIPELINE_SCORE_PATH=data-pipeline/data/score GATSBY_DATA_PIPELINE_SCORE_PATH=data-pipeline/data/score
GATSBY_SCORE_DOWNLOAD_FILE_PATH=downloadable/Screening_Tool_Data.zip GATSBY_SCORE_DOWNLOAD_FILE_PATH=downloadable/Screening_Tool_Data.zip
GATSBY_MAP_TILES_PATH=tiles GATSBY_MAP_TILES_PATH=tiles
GATSBY_MAPBOX_STYLES_READ_TOKEN=pk.eyJ1IjoianVzdGljZTQwIiwiYSI6ImNreHRub2QxdTV6dnUzMHBmZDdzZXQ4YWMifQ.Fc-my99OtAwP5zEXCgrx_g

4
client/.gitignore vendored
View file

@ -5,6 +5,4 @@ public
cypress/screenshots/ cypress/screenshots/
cypress/videos/ cypress/videos/
.DS_Store .DS_Store
coverage coverage
.env.development
.env.production

View file

@ -93,7 +93,7 @@ module.exports = {
{ {
resolve: `gatsby-plugin-env-variables`, resolve: `gatsby-plugin-env-variables`,
options: { options: {
allowList: ['DATA_SOURCE'], allowList: ['DATA_SOURCE', 'MAPBOX_STYLES_READ_TOKEN'],
}, },
}, },
{ {

View file

@ -29,7 +29,7 @@ import MapSearch from './MapSearch';
import TerritoryFocusControl from './territoryFocusControl'; import TerritoryFocusControl from './territoryFocusControl';
// Styles and constants // Styles and constants
// import {makeMapStyle} from '../data/mapStyle'; import {getOSBaseMap} from '../data/getOSBaseMap';
import 'maplibre-gl/dist/maplibre-gl.css'; import 'maplibre-gl/dist/maplibre-gl.css';
import * as constants from '../data/constants'; import * as constants from '../data/constants';
import * as styles from './J40Map.module.scss'; import * as styles from './J40Map.module.scss';
@ -258,14 +258,18 @@ const J40Map = ({location}: IJ40Interface) => {
<ReactMapGL <ReactMapGL
// Initialization props: // Initialization props:
// access token is j40StylesReadToken // access token is j40StylesReadToken
mapboxApiAccessToken={process.env.GATSBY_MAPBOX_STYLES_READ_TOKEN} mapboxApiAccessToken={
process.env.MAPBOX_STYLES_READ_TOKEN ?
process.env.MAPBOX_STYLES_READ_TOKEN : ''}
// Map state props: // Map state props:
// http://visgl.github.io/react-map-gl/docs/api-reference/interactive-map#map-state // http://visgl.github.io/react-map-gl/docs/api-reference/interactive-map#map-state
{...viewport} {...viewport}
mapStyle={`mapbox://styles/mapbox/streets-v11`} mapStyle={
process.env.MAPBOX_STYLES_READ_TOKEN ? `mapbox://styles/mapbox/streets-v11` :
getOSBaseMap()
}
// This styles will need to be enabled in some way when adding back the free map - #1133 // This styles will need to be enabled in some way when adding back the free map - #1133
// mapStyle={makeMapStyle(flags)}
width="100%" width="100%"
height={windowWidth < 1024 ? '44vh' : '100%'} height={windowWidth < 1024 ? '44vh' : '100%'}
mapOptions={{hash: true}} mapOptions={{hash: true}}

View file

@ -0,0 +1,80 @@
import {Style} from 'maplibre-gl';
import * as constants from '../data/constants';
// *********** BASE MAP SOURCES ***************
const imageSuffix = constants.isMobile ? '' : '@2x';
// 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`,
],
};
// Utility function to get OpenSource base maps that are in accordance to JSON spec of MapBox
// https://docs.mapbox.com/mapbox-gl-js/style-spec/
export const getOSBaseMap = () : Style => {
return {
'version': 8,
/**
* Map Sources
* */
'sources': {
/**
* The base map source source allows us to define where the tiles can be fetched from.
*/
[constants.BASE_MAP_SOURCE_NAME]: {
'type': 'raster',
'tiles': cartoLightBaseLayer.noLabels,
'minzoom': constants.GLOBAL_MIN_ZOOM,
'maxzoom': constants.GLOBAL_MAX_ZOOM,
},
// The labels source:
'labels': {
'type': 'raster',
'tiles': cartoLightBaseLayer.labelsOnly,
},
},
/**
* Each object in the layers array references it's source via the source key.
*/
'layers': [
// The baseMapLayer
{
'id': constants.BASE_MAP_LAYER_ID,
'source': constants.BASE_MAP_SOURCE_NAME,
'type': 'raster',
'minzoom': constants.GLOBAL_MIN_ZOOM,
'maxzoom': constants.GLOBAL_MAX_ZOOM,
},
// A layer for labels only
{
'id': 'labels-only-layer',
'source': 'labels',
'type': 'raster',
'layout': {
'visibility': 'visible',
},
'minzoom': constants.GLOBAL_MIN_ZOOM,
'maxzoom': constants.GLOBAL_MAX_ZOOM,
},
],
};
};

View file

@ -1,6 +1,8 @@
import {Style} from 'maplibre-gl'; import {Style} from 'maplibre-gl';
import * as constants from '../data/constants'; import * as constants from '../data/constants';
import {FlagContainer} from '../contexts/FlagContext';
// This file is no longer used, however keeping in case we have to revert to explicit styling. There was a
// gradient function that in this file's commit history which could prove useful in the future.
// *********** BASE MAP SOURCES *************** // *********** BASE MAP SOURCES ***************
const imageSuffix = constants.isMobile ? '' : '@2x'; const imageSuffix = constants.isMobile ? '' : '@2x';
@ -22,33 +24,10 @@ const cartoLightBaseLayer = {
], ],
}; };
// 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 // Utility function to make map styles according to JSON spec of MapBox
// https://docs.mapbox.com/mapbox-gl-js/style-spec/ // https://docs.mapbox.com/mapbox-gl-js/style-spec/
export const makeMapStyle = (flagContainer: FlagContainer) : Style => { export const makeMapStyle = () : 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 { return {
'version': 8, 'version': 8,
@ -70,7 +49,7 @@ export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
*/ */
[constants.BASE_MAP_SOURCE_NAME]: { [constants.BASE_MAP_SOURCE_NAME]: {
'type': 'raster', 'type': 'raster',
'tiles': getBaseMapLayer(), 'tiles': cartoLightBaseLayer.noLabels,
/** /**
* Attempting to place a direct call to mapbox URL: * Attempting to place a direct call to mapbox URL:
@ -101,52 +80,52 @@ export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
}, },
// In the layer (below) where the geo source is used, the layer is invisible // In the layer (below) where the geo source is used, the layer is invisible
'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, // 'minzoom': constants.GLOBAL_MIN_ZOOM,
'maxzoom': constants.GLOBAL_MAX_ZOOM, // 'maxzoom': constants.GLOBAL_MAX_ZOOM,
}, // },
// The High zoom source: // The High zoom source:
[constants.HIGH_ZOOM_SOURCE_NAME]: { // [constants.HIGH_ZOOM_SOURCE_NAME]: {
// It is only shown at high zoom levels to avoid performance issues at lower zooms // // 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': constants.GEOID_PROPERTY, // 'promoteId': constants.GEOID_PROPERTY,
'tiles': [ // 'tiles': [
'high_tiles' in flagContainer ? // 'high_tiles' in flagContainer ?
constants.featureURLForTilesetName(flagContainer['high_tiles']) : // constants.featureURLForTilesetName(flagContainer['high_tiles']) :
constants.FEATURE_TILE_HIGH_ZOOM_URL, // constants.FEATURE_TILE_HIGH_ZOOM_URL,
], // ],
// Setting maxzoom here enables 'overzooming' // // Setting 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, // 'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
'maxzoom': constants.GLOBAL_MAX_ZOOM_HIGH, // 'maxzoom': constants.GLOBAL_MAX_ZOOM_HIGH,
}, // },
// The Low zoom source: // The Low zoom source:
[constants.LOW_ZOOM_SOURCE_NAME]: { // [constants.LOW_ZOOM_SOURCE_NAME]: {
// "Score-low" represents a tileset at the level of bucketed tracts. // // "Score-low" represents a tileset at the level of bucketed tracts.
// census block group information is `dissolve`d into tracts, then // // census block group information is `dissolve`d into tracts, then
// each tract is `dissolve`d into one of ten buckets. It is meant // // each tract is `dissolve`d into one of ten buckets. It is meant
// to give us a favorable tradeoff between performance and fidelity. // // to give us a favorable tradeoff between performance and fidelity.
'type': 'vector', // 'type': 'vector',
'promoteId': constants.GEOID_PROPERTY, // 'promoteId': constants.GEOID_PROPERTY,
'tiles': [ // 'tiles': [
'low_tiles' in flagContainer ? // 'low_tiles' in flagContainer ?
constants.featureURLForTilesetName(flagContainer['low_tiles']) : // constants.featureURLForTilesetName(flagContainer['low_tiles']) :
constants.FEATURE_TILE_LOW_ZOOM_URL, // constants.FEATURE_TILE_LOW_ZOOM_URL,
// For local development, use: // // For local development, use:
// 'http://localhost:8080/data/tl_2010_bg_with_data/{z}/{x}/{y}.pbf', // // 'http://localhost:8080/data/tl_2010_bg_with_data/{z}/{x}/{y}.pbf',
], // ],
'minzoom': constants.GLOBAL_MIN_ZOOM_LOW, // 'minzoom': constants.GLOBAL_MIN_ZOOM_LOW,
'maxzoom': constants.GLOBAL_MAX_ZOOM_LOW, // 'maxzoom': constants.GLOBAL_MAX_ZOOM_LOW,
}, // },
// The labels source: // The labels source:
'labels': { 'labels': {
@ -177,87 +156,87 @@ export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
}, },
// The Geo layer adds a geographical layer like mountains and rivers // The Geo layer adds a geographical layer like mountains and rivers
{ // {
'id': 'geo', // 'id': 'geo',
'source': 'geo', // 'source': 'geo',
'type': 'raster', // 'type': 'raster',
'layout': { // 'layout': {
// Place visibility behind flag: // // Place visibility behind flag:
'visibility': 'geo' in flagContainer ? 'visible' : 'none', // 'visibility': 'geo' in flagContainer ? 'visible' : 'none',
}, // },
'minzoom': constants.GLOBAL_MIN_ZOOM, // 'minzoom': constants.GLOBAL_MIN_ZOOM,
'maxzoom': constants.GLOBAL_MAX_ZOOM, // 'maxzoom': constants.GLOBAL_MAX_ZOOM,
}, // },
/** /**
* High zoom layer - non-prioritized features only * High zoom layer - non-prioritized features only
*/ */
{ // {
'id': constants.HIGH_ZOOM_LAYER_ID, // 'id': constants.HIGH_ZOOM_LAYER_ID,
'source': constants.HIGH_ZOOM_SOURCE_NAME, // 'source': constants.HIGH_ZOOM_SOURCE_NAME,
'source-layer': constants.SCORE_SOURCE_LAYER, // 'source-layer': constants.SCORE_SOURCE_LAYER,
/** // /**
* This shows features where the high score < score boundary threshold. // * This shows features where the high score < score boundary threshold.
* In other words, this filter out prioritized features // * In other words, this filter out prioritized features
*/ // */
'filter': ['all', // 'filter': ['all',
['<', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD], // ['<', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD],
], // ],
'type': 'fill', // 'type': 'fill',
'paint': { // 'paint': {
'fill-opacity': constants.NON_PRIORITIZED_FEATURE_FILL_OPACITY, // 'fill-opacity': constants.NON_PRIORITIZED_FEATURE_FILL_OPACITY,
}, // },
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH, // 'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
}, // },
/** /**
* High zoom layer - prioritized features only * High zoom layer - prioritized features only
*/ */
{ // {
'id': constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID, // 'id': constants.PRIORITIZED_HIGH_ZOOM_LAYER_ID,
'source': constants.HIGH_ZOOM_SOURCE_NAME, // 'source': constants.HIGH_ZOOM_SOURCE_NAME,
'source-layer': constants.SCORE_SOURCE_LAYER, // 'source-layer': constants.SCORE_SOURCE_LAYER,
/** // /**
* This shows features where the high score > score boundary threshold. // * This shows features where the high score > score boundary threshold.
* In other words, this filter out non-prioritized features // * In other words, this filter out non-prioritized features
*/ // */
'filter': ['all', // 'filter': ['all',
['>', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD], // ['>', constants.SCORE_PROPERTY_HIGH, constants.SCORE_BOUNDARY_THRESHOLD],
], // ],
'type': 'fill', // 'type': 'fill',
'paint': { // 'paint': {
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR, // 'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
'fill-opacity': constants.PRIORITIZED_FEATURE_FILL_OPACITY, // 'fill-opacity': constants.HIGH_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY,
}, // },
'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH, // 'minzoom': constants.GLOBAL_MIN_ZOOM_HIGH,
}, // },
/** /**
* Low zoom layer - prioritized features only * Low zoom layer - prioritized features only
*/ */
{ // {
'id': constants.LOW_ZOOM_LAYER_ID, // 'id': constants.LOW_ZOOM_LAYER_ID,
'source': constants.LOW_ZOOM_SOURCE_NAME, // 'source': constants.LOW_ZOOM_SOURCE_NAME,
'source-layer': constants.SCORE_SOURCE_LAYER, // 'source-layer': constants.SCORE_SOURCE_LAYER,
/** // /**
* This shows features where the low score > score boundary threshold. // * This shows features where the low score > score boundary threshold.
* In other words, this filter out non-prioritized features // * In other words, this filter out non-prioritized features
*/ // */
'filter': ['all', // 'filter': ['all',
['>', constants.SCORE_PROPERTY_LOW, constants.SCORE_BOUNDARY_THRESHOLD], // ['>', constants.SCORE_PROPERTY_LOW, constants.SCORE_BOUNDARY_THRESHOLD],
], // ],
'type': 'fill', // 'type': 'fill',
'paint': { // 'paint': {
'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR, // 'fill-color': constants.PRIORITIZED_FEATURE_FILL_COLOR,
'fill-opacity': constants.PRIORITIZED_FEATURE_FILL_OPACITY, // 'fill-opacity': constants.LOW_ZOOM_PRIORITIZED_FEATURE_FILL_OPACITY,
}, // },
'minzoom': constants.GLOBAL_MIN_ZOOM_LOW, // 'minzoom': constants.GLOBAL_MIN_ZOOM_LOW,
'maxzoom': constants.GLOBAL_MAX_ZOOM_LOW, // 'maxzoom': constants.GLOBAL_MAX_ZOOM_LOW,
}, // },
// A layer for labels only // A layer for labels only
{ {
@ -265,7 +244,7 @@ export const makeMapStyle = (flagContainer: FlagContainer) : Style => {
'source': 'labels', 'source': 'labels',
'type': 'raster', 'type': 'raster',
'layout': { 'layout': {
'visibility': 'remove-label-layer' in flagContainer ? 'none' : 'visible', 'visibility': 'visible',
}, },
'minzoom': constants.GLOBAL_MIN_ZOOM, 'minzoom': constants.GLOBAL_MIN_ZOOM,
'maxzoom': constants.GLOBAL_MAX_ZOOM, 'maxzoom': constants.GLOBAL_MAX_ZOOM,

View file

@ -34,6 +34,11 @@ services:
# See the client readme for more info on environment variables: # See the client readme for more info on environment variables:
# https://github.com/usds/justice40-tool/blob/main/client/README.md # https://github.com/usds/justice40-tool/blob/main/client/README.md
DATA_SOURCE: local DATA_SOURCE: local
# If you want the map to render a MapBox base map (as opposed to the
# open source one from CartoDB), please create your own API TOKEN from
# your MapBox account and add the token here:
MAPBOX_STYLES_READ_TOKEN: ""
volumes: volumes:
- ./client/src:/client/src - ./client/src:/client/src
ports: ports: