diff --git a/src/visualizations/custom/maps/map_minimal.js b/src/visualizations/custom/maps/map_minimal.js
deleted file mode 100644
index ce6df7f..0000000
--- a/src/visualizations/custom/maps/map_minimal.js
+++ /dev/null
@@ -1,650 +0,0 @@
-import mapboxgl from 'mapbox-gl';
-import stateData from './mapbox-boundaries-adm1-v3_4.json';
-import cbsaData from './mapbox-boundaries-sta2-v3_4.json';
-import zipData from './mapbox-boundaries-pos4-v3_4.json';
-import regeneratorRuntime from "regenerator-runtime";
-import "core-js/stable";
-
-if (mapboxgl.version.indexOf('2.9.') === 0) Object.defineProperty(window, 'caches', { value: undefined });
-
-function numberWithCommas(x) {
- if(!x) {
- return undefined;
- }
- x = x.toFixed(0);
- var parts = x.toString().split(".");
- parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
- return parts.join(".");
-};
-
-looker.plugins.visualizations.add({
- id: "thrive_custom_special_granularity_map",
- label: "Custom Layered Mapbox Map",
- // Set up the initial state of the visualization
- create: function (element, config) {
-
- // Insert a `;
-
- // Create the top layer selector bar
- //###################################################################################//
-
- this.__mapStatesButton = document.createElement('button');
- this.__mapStatesButton.innerHTML = "States";
- this.__mapStatesButton.className = "map-paginator active";
- this.__mapStatesButton.id = "states-join";
-
- this.__mapCBSAsButton = document.createElement('button');
- this.__mapCBSAsButton.innerHTML = "CBSAs";
- this.__mapCBSAsButton.className = "map-paginator";
- this.__mapCBSAsButton.id = "cbsas-join";
-
- this.__mapZipCodesButton = document.createElement('button');
- this.__mapZipCodesButton.innerHTML = "Zip Codes";
- this.__mapZipCodesButton.className = "map-paginator";
- this.__mapZipCodesButton.id = "zips-join";
-
- this.__mapBEsButton = document.createElement('button');
- this.__mapBEsButton.innerHTML = "Business Entities";
- this.__mapBEsButton.className = "map-paginator";
- this.__mapBEsButton.id = "business-entities-join";
-
- this.__mapPaginatorWrapper = document.createElement('div');
- this.__mapPaginatorWrapper.className = "map-paginator__wrapper";
-
- this.__mapPaginatorWrapper.appendChild(this.__mapStatesButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapCBSAsButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapZipCodesButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapBEsButton);
-
- element.appendChild(this.__mapPaginatorWrapper);
-
- this.__selectedLocalesWrapper = document.createElement('div');
- this.__selectedLocalesWrapper.className = "selected-locales__wrapper";
- element.appendChild(this.__selectedLocalesWrapper);
-
- //###################################################################################//
-
- this.__mapBox = document.createElement('div');
- this.__mapBox.style.height = '100%';
- this.__mapBox.style.width = '100%';
- this.__mapBox.id = "map";
-
- element.appendChild(this.__mapBox);
-
- mapboxgl.accessToken = 'pk.eyJ1IjoiZHVuY2FuY2ZyYXNlciIsImEiOiJjbDRvbDlmZWQwMGdzM2ZxazZybTVkdDQ0In0.xL5_LBkos5tYRbLxR0tQRQ';
- this.__map = new mapboxgl.Map({
- container: 'map',
- style: 'mapbox://styles/mapbox/light-v10',
- center: [-98.5795, 39.8283],
- zoom: 4,
- projection: 'globe'
- });
-
- this.__map.addControl(new mapboxgl.NavigationControl());
- this.__map.addControl(new mapboxgl.FullscreenControl());
-
- var link = document.createElement('link');
- link.href = 'https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css';
- link.rel = 'stylesheet';
-
- var script = document.createElement('script');
- script.src = 'https://kit.fontawesome.com/f2060bf509.js';
- script.crossOrigin = "anonymous";
-
- document.head.appendChild(link);
- document.head.appendChild(script);
- },
- // Render in response to the data or settings changing
- updateAsync: function (data, element, config, queryResponse, details, done) {
-
- // Reload Handler to accomodate the on load event only running once
- console.log("Running Entire Visualization Update")
-
- function throwMessage(locales) {
- console.log("A1")
- window.parent.parent.postMessage({ message: "crossFilterLocale", value: locales }, "*")
- }
-
- function changeGranularity(g) {
- console.log("A2")
- window.parent.parent.postMessage({ message: "changeGranularity", value: g }, "*")
- }
-
- let mapgl = this.__map
-
- const measureName = queryResponse.fields.measures[0].name;
- const measureLabel = queryResponse.fields.measures[0].label_short;
- const localesWrapper = this.__selectedLocalesWrapper
-
- let hoveredStateId = null; // Tracks hovered state and updates with popup
- let filteredStateNames = []
-
- async function runSelectionUpdate(element) {
- console.log("A3")
- const prevParent = document.getElementById("selectedLocaleContainer");
- if(prevParent) {
- console.log("B3")
- element.removeChild(prevParent)
- };
-
- const parent = document.createElement("div");
- parent.id = "selectedLocaleContainer";
-
- const values = (Object.values(filteredStateNames)).map(element => element[0])
- console.log("values", values)
-
- for(let i = 0; i < values.length; i++) {
- if(!values[i]) {
- continue;
- }
- if(i > 1) {
- const moreWrapper = document.createElement("div")
- moreWrapper.className = "selected-locale__more"
- const moreText = document.createElement("span")
- moreText.innerHTML = `+${values.length - 2} more locales`;
- moreWrapper.appendChild(moreText)
- parent.appendChild(moreWrapper)
- break;
- }
- const selectedLocale = document.createElement("div")
- const selectedLocaleText = document.createElement("span")
- const removeButton = document.createElement('div')
- removeButton.innerHTML = '';
-
- removeButton.addEventListener("click", () => {
- values.splice(i, 1)
- runSelectionUpdate(element)
- })
-
- selectedLocaleText.innerHTML = values[i]
- selectedLocale.className = "selected-locale"
-
- selectedLocale.appendChild(selectedLocaleText)
- selectedLocale.appendChild(removeButton)
- parent.appendChild(selectedLocale)
- }
-
- throwMessage(values)
-
- element.appendChild(parent)
- };
-
- mapgl.on('load', () => {
- console.log("A4")
- createStatesViz();
- });
-
- mapgl.on('idle', () => {
- console.log("A5")
- this.__mapStatesButton.addEventListener("click", changeActive);
- this.__mapCBSAsButton.addEventListener("click", changeActive);
- this.__mapZipCodesButton.addEventListener("click", changeActive);
- this.__mapBEsButton.addEventListener("click", changeActive);
- })
-
- const changeActive = (e) => {
- console.log("A6")
- /* For reference, e.target is one of the buttons on top of the map.
- The event listeners are added in a map.on('idle', () => {}) but have
- previously been added in map.on('load', () => {}) to the same effect*/
-
- //e.preventDefault();
- //e.stopPropagation();
-
- if(!e.target.classList.contains("active")) {
- console.log("B6")
- // Updates the nav-bar active status
- const els = document.getElementsByClassName("map-paginator");
- for (let i = 0; i < els.length; i++) {
- if(els[i].classList.contains("active")) {
- els[i].classList.remove("active");
- };
- };
-
- e.target.classList.add("active");
-
- // Updates the layers' active status
- for (let j = 0; j < this.__LAYERNAMES.length; j++) {
- if(this.__LAYERNAMES[j].name !== e.target.id) {
- mapgl.setLayoutProperty(this.__LAYERNAMES[j].name, 'visibility', 'none');
- };
- };
-
- const filteredDown = this.__LAYERNAMES.filter(item => item.name === e.target.id)
- console.log(e.target.id)
-
- if(filteredDown.length > 0) {
- console.log("B6A")
- mapgl.setLayoutProperty(e.target.id, 'visibility', 'visible');
- changeGranularity(filteredDown[0].groupingName)
- }
-
- console.log("DEBUG: GETTING LAYER VISIBILITY")
- console.log(mapgl.getStyle().layers)
- }
- }
-
- function getMaxState(arr) {
- console.log("A7")
- const set = data.filter(row => arr.hasOwnProperty(row["dim_zi_map_vis.state"].value));
- try {
- console.log("B7")
- let max = set.reduce((max, item) => max[measureName].value > item[measureName].value ? max : item);
- return max[measureName].value
- } catch {
- return 2
- }
- }
-
- function createStatesViz() {
- console.log("A8")
- const lookupData = filterLookupTable();
-
- function filterLookupTable(lookupTable) {
- const lookupData = {};
-
- const searchData = stateData.adm1.data.all
-
- Object.keys(searchData).forEach(function(key) {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['name']] = featureData
- }
- })
- return lookupData;
- }
-
- mapgl.addSource('statesData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-adm1-v3'
- });
-
- const maxValue = getMaxState(lookupData)
-
- mapgl.addLayer({
- id: 'states-join',
- type: 'fill',
- source: 'statesData',
- /*'layout': {
- // Make the layer visible by default.
- 'visibility': 'visible'
- },*/
- 'source-layer': 'boundaries_admin_1',
- paint: {
- 'fill-color': [
- // In the case that 'feature-state': 'requestedKPI' is not null, interpolate the colors between the min and max, if it is null make the layer white.
- 'case',
- ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],
- 'rgba(255, 255, 255, 0)'
- ]
- }
- }, 'waterway-label');
-
- const popup = new mapboxgl.Popup({
- closeButton: false,
- closeOnClick: false,
- className: 'gtm-map-popup',
- maxWidth: '300px'
- });
-
-
- mapgl.on('mousemove', 'states-join', (e) => {
- console.log("A9")
- if (e.features.length > 0) {
-
- const realCoords = [e.lngLat.lng, e.lngLat.lat]
- const reqKPI = e.features[0].state.requestedKPI;
- const state = e.features[0].state.name
-
- const description = `
-
`
-
- if(e.features[0].state.requestedKPI) {
- popup.setLngLat(realCoords).setHTML(description).addTo(mapgl);
- } else {
- popup.remove;
- }
-
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: false }
- );
- }
- hoveredStateId = e.features[0].id;
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: true }
- );
- }
- });
-
- // When the mouse leaves the state-fill layer, update the feature state of the
- // previously hovered feature.
- mapgl.on('mouseleave', 'states-join', () => {
- console.log("A10")
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: false }
- );
- popup.remove()
- }
- hoveredStateId = null;
- });
-
- mapgl.on('click', (e) => {
- console.log("A11")
- // Set `bbox` as 5px reactangle area around clicked point.
- const bbox = [
- [e.point.x, e.point.y],
- [e.point.x, e.point.y]
- ];
-
- const selectedFeatures = mapgl.queryRenderedFeatures(bbox, {
- layers: ['states-join']
- });
-
- const name = selectedFeatures.map(
- (feature) => feature.state.name
- );
-
- const selectedFeatureName = name[0]
-
- if(!lookupData.hasOwnProperty(selectedFeatureName) || filteredStateNames[activeLayer].includes(selectedFeatureName)) {
- return;
- }
-
-
- filteredStateNames[activeLayer].push(selectedFeatureName)
- console.dir(filteredStateNames)
- runSelectionUpdate(localesWrapper);
- });
-
- function setStates() {
- console.log("A12")
- console.log("%c Setting States for States", 'color: #009900')
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.state"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "statesData",
- sourceLayer: 'boundaries_admin_1',
- id: lookupData[row["dim_zi_map_vis.state"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- fipsCode: lookupData[row["dim_zi_map_vis.state"].value].unit_code,
- name: lookupData[row["dim_zi_map_vis.state"].value].name,
- hovered: false
- }
- )
- }
- }
-
- function createLegend() {
- console.log("A13")
- try {
- const oldLegendBox = document.getElementById("mapboxLegend")
- oldLegendBox.parentNode.removeChild(oldLegendBox)
- } catch {
- console.log("Unable to remove old legend because there is no old legend.")
- }
-
- const legendBox = document.createElement("div")
- const legendLeft = document.createElement("div")
- const legendRight = document.createElement("div")
- const legendBar = document.createElement("div")
- const legendRightTop = document.createElement("div")
- const legendRightBottom = document.createElement("div")
-
- legendBox.className = "legend-box"
- legendLeft.className = "legend-left"
- legendRight.className = "legend-right"
- legendBar.className = "legend-bar"
-
- legendRightTop.innerHTML = numberWithCommas(maxValue)
- legendRightBottom.innerHTML = 1
-
- legendLeft.appendChild(legendBar)
-
- legendRight.appendChild(legendRightTop)
- legendRight.appendChild(legendRightBottom)
-
- legendBox.appendChild(legendLeft)
- legendBox.appendChild(legendRight)
-
- legendBox.id = "mapboxLegend"
-
- element.appendChild(legendBox)
- }
-
- createLegend()
-
- // Check if `statesData` source is loaded.
- function setAfterLoadStates(event) {
- console.log("A14")
- console.log("sourceEvent", event)
- if (event.sourceID !== 'statesData' && !event.isSourceLoaded) return;
- setStates();
- console.log("%c Turning off Sourcedata event listener for states", 'color: #ff0000')
- mapgl.off('sourcedata', setAfterLoadStates);
- }
-
- // If `statesData` source is loaded, call `setStates()`.
- if (mapgl.isSourceLoaded('statesData')) {
- console.log("A15")
- console.log("%c States Data Source loaded, setting states", 'color: #009900')
- setStates();
- } else {
- console.log("%c States Data Source is not loaded, adding event listener sourcedata", 'color: #009900')
- console.log("A16")
- mapgl.on('sourcedata', setAfterLoadStates);
- }
- }
-
- mapgl.on('style.load', () => {
- console.log("A17")
- mapgl.setFog({
- color: 'rgb(186, 210, 235)', // Lower atmosphere
- 'high-color': 'rgb(36, 92, 223)', // Upper atmosphere
- 'horizon-blend': 0.02, // Atmosphere thickness (default 0.2 at low zooms)
- 'space-color': 'rgb(11, 11, 25)', // Background color
- 'star-intensity': 0.6 // Background star brightness (default 0.35 at low zoooms )
- }); // Set the default atmosphere style
- });
-
- // Clear any errors from previous updates
- this.clearErrors(queryResponse.fields);
-
- if (queryResponse.fields.measures.length == 0 || queryResponse.fields.dimensions.length == 0) {
- this.addError({ title: "No Measures or Dimensions", message: "This chart requires a measure and a dimension." });
- return;
- }
-
- console.log("query response")
- console.log(queryResponse)
-
- done()
- }
-});
\ No newline at end of file
diff --git a/src/visualizations/custom/maps/map_test copy.js b/src/visualizations/custom/maps/map_test copy.js
deleted file mode 100644
index a310d8a..0000000
--- a/src/visualizations/custom/maps/map_test copy.js
+++ /dev/null
@@ -1,1431 +0,0 @@
-import mapboxgl from 'mapbox-gl';
-import stateData from './mapbox-boundaries-adm1-v3_4.json';
-import cbsaData from './mapbox-boundaries-sta2-v3_4.json';
-import zipData from './mapbox-boundaries-pos4-v3_4.json';
-import regeneratorRuntime from "regenerator-runtime";
-import bbox from '@turf/bbox';
-import "core-js/stable";
-
-if (mapboxgl.version.indexOf('2.9.') === 0) Object.defineProperty(window, 'caches', { value: undefined });
-
-function numberWithCommas(x) {
- if(!x) return undefined;
- x = x.toFixed(0);
- var parts = x.toString().split(".");
- parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
- return parts.join(".");
-};
-
-looker.plugins.visualizations.add({
- id: "thrive_custom_special_granularity_map",
- label: "Custom Layered Mapbox Map",
- // Set up the initial state of the visualization
- create: function (element, config) {
- // Insert a `;
-
- this.__currentLayer = "states-join";
- this.__LAYERNAMES = [
- {
- name: "states-join",
- groupingName: "State"
- },
- {
- name: "cbsas-join",
- groupingName: "CBSA"
- },
- {
- name: "zips-join",
- groupingName: "Zipcode"
- }
- ];
-
- // Create the top layer selector bar
- //###################################################################################//
-
- this.__mapStatesButton = document.createElement('button');
- this.__mapStatesButton.innerHTML = "States";
- this.__mapStatesButton.className = "map-paginator active";
- this.__mapStatesButton.id = "states-join";
-
- this.__mapCBSAsButton = document.createElement('button');
- this.__mapCBSAsButton.innerHTML = "CBSAs";
- this.__mapCBSAsButton.className = "map-paginator";
- this.__mapCBSAsButton.id = "cbsas-join";
-
- this.__mapZipCodesButton = document.createElement('button');
- this.__mapZipCodesButton.innerHTML = "Zip Codes";
- this.__mapZipCodesButton.className = "map-paginator";
- this.__mapZipCodesButton.id = "zips-join";
-
- this.__mapPaginatorWrapper = document.createElement('div');
- this.__mapPaginatorWrapper.className = "map-paginator__wrapper";
-
- this.__mapPaginatorWrapper.appendChild(this.__mapStatesButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapCBSAsButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapZipCodesButton);
-
- element.appendChild(this.__mapPaginatorWrapper);
-
- this.__selectedLocalesWrapper = document.createElement('div');
- this.__selectedLocalesWrapper.className = "selected-locales__wrapper";
- element.appendChild(this.__selectedLocalesWrapper);
-
- //###################################################################################//
-
- this.__mapBox = document.createElement('div');
- this.__mapBox.style.height = '100%';
- this.__mapBox.style.width = '100%';
- this.__mapBox.id = "map";
-
- element.appendChild(this.__mapBox);
-
- mapboxgl.accessToken = 'pk.eyJ1IjoiZHVuY2FuY2ZyYXNlciIsImEiOiJjbDRvbDlmZWQwMGdzM2ZxazZybTVkdDQ0In0.xL5_LBkos5tYRbLxR0tQRQ';
- this.__map = new mapboxgl.Map({
- container: 'map',
- style: 'mapbox://styles/mapbox/light-v10',
- center: [-98.5795, 39.8283],
- zoom: 4,
- projection: 'globe'
- });
-
- this.__map.addControl(new mapboxgl.NavigationControl());
- this.__map.addControl(new mapboxgl.FullscreenControl());
-
- this.__map.scrollZoom.disable();
-
- this.__map.on('load', () => {
- this.__map.addSource('statesData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-adm1-v3'
- }).addSource('cbsaData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-sta2-v3'
- }).addSource('zipData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-pos4-v3'
- });
- });
-
-
- var link = document.createElement('link');
- link.href = 'https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css';
- link.rel = 'stylesheet';
-
- var script = document.createElement('script');
- script.src = 'https://kit.fontawesome.com/f2060bf509.js';
- script.crossOrigin = "anonymous";
-
- document.head.appendChild(link);
- document.head.appendChild(script);
- },
-
- /* Render in response to the data or settings changing
- Params:
- @param data: array of returned data with fields
- @param element: HTML DOM element where the vis is stored
- @param config: Settings object on the tile where the vis is located
- @param queryResponse: Entire response to query, includes data object and config object
- @param details: ?
- @param done: function to call to tell Looker you've finished rendering
- */
- updateAsync: function (data, element, config, queryResponse, details, done) {
- // Clear any errors from previous updates
- this.clearErrors(queryResponse.fields);
-
- //When no dimensions and/or no measures are present the viz stops updating and displays an error
- if (queryResponse.fields.measures.length < 1 || queryResponse.fields.dimensions.length < 1) {
- this.addError({ title: "No Measures or Dimensions", message: "This chart requires a measure and a dimension." });
- return;
- }
-
- /* Pass a message to the GTM Frontend to send a locale filter to looker
- Params:
- @param locales: object containing all filtered locales at different levels of granularity
- */
- const throwMessage = (locales) => window.parent.parent.postMessage({ message: "crossFilterLocale", value: locales }, "*");
- /* Pass a message to the GTM Frontend to send a granularity grouping filter to looker
- Params:
- @param g: string representing new grouping to filter to
- */
- const changeGranularity = (g) => window.parent.parent.postMessage({ message: "changeGranularity", value: g }, "*");
-
- // Because `this` does not work properly in functions (`this` goes local), move the map to a more usable variable
- let mapgl = this.__map;
- // Find name of measure, as measure is requested KPI, which is dynamic, returns String
- const measureName = queryResponse.fields.measures[0].name;
- // Find label of measure, as measure is requested KPI, which is dynamic. This prints to UI, returns String
- const measureLabel = queryResponse.fields.measures[0].label_short;
- // Move HTML DOM element from `this` to permanent variable, returns HTML DOM element
- const localesWrapper = this.__selectedLocalesWrapper;
- // Move Object from `this` to permanent variable, returns Object
- const thisLayerNames = this.__LAYERNAMES;
- // Tracks feature currently being hovered, DEV NOTE: To increase conciseness this could be altered to `hoveredFeatureId`, set to null
- let hoveredStateId = null; // Tracks hovered state and updates with popup
- // The object responsible for capturing selected features, DEV NOTE: To increase conciseness this could be altered to `selectedFeatureNames`, set to object of empty arrays
- let filteredStateNames = {
- "states-join": [],
- "cbsas-join": [],
- "zips-join": []
- };
-
- /* Creates legend for the map
- Params:
- @param data: contains current data object at runtime
- @param fieldName: holds the current grouping
- @param max: the maximum value currently represented on the map
- */
- const createLegend = (data, fieldName, max) => {
- // If the grouping is null, return. This keeps the legend in line with the active layer
- if(determineNull(data, fieldName)) return;
- // If there is an old legend, remove it before creating the new one.
- const oldLegendBox = document.getElementById("mapboxLegend");
- if(oldLegendBox) oldLegendBox.parentNode.removeChild(oldLegendBox);
- // Create the elements necessary to construct the legend, all below elements should return HTML DOM nodes
- const legendBox = document.createElement("div");
- const legendLeft = document.createElement("div");
- const legendRight = document.createElement("div");
- const legendBar = document.createElement("div");
- const legendRightTop = document.createElement("div");
- const legendRightBottom = document.createElement("div");
- // Add the proper classes to the legend elements consistent with the CSS styling in `create()`
- legendBox.className = "legend-box";
- legendLeft.className = "legend-left";
- legendRight.className = "legend-right";
- legendBar.className = "legend-bar";
- // Display the maximum value with the proper number of commas for a number it's length
- legendRightTop.innerHTML = numberWithCommas(max);
- // The lower bound is 1, since 0 is never displayed
- legendRightBottom.innerHTML = 1;
- // Append all the elements in order to create the legend from the CSS styling in `create()`
- legendLeft.appendChild(legendBar);
- legendRight.appendChild(legendRightTop);
- legendRight.appendChild(legendRightBottom);
- legendBox.appendChild(legendLeft);
- legendBox.appendChild(legendRight);
- // Give the entire legend an id so it can be deleted on refresh.
- legendBox.id = "mapboxLegend";
- // Append the new legend to the entire visualization
- element.appendChild(legendBox);
- }
-
- const showHideMultiTooltip = () => document.getElementById("mainTooltip").classList.toggle("active")
-
- const createMultiTooltip = () => {
- const mapboxbox = document.getElementById("map")
- const tooltipOpener = mapboxbox.appendChild(document.createElement('div'))
- const tooltipBackground = mapboxbox.appendChild(document.createElement("div"))
- const tooltipOuter = tooltipBackground.appendChild(document.createElement("div"))
- const tooltipInner = tooltipOuter.appendChild(document.createElement("div"))
- const tooltipTop = tooltipOuter.appendChild(document.createElement("div"))
- const tooltipBottom = tooltipOuter.appendChild(document.createElement("div"))
- const tooltipTitle = tooltipTop.appendChild(document.createElement("h2"))
- const tooltipDescription = tooltipTop.appendChild(document.createElement("p"))
- const tooltipButton = tooltipBottom.appendChild(document.createElement("button"))
- tooltipBackground.className = "ctrl-tooltip__background"
- tooltipBackground.id = "mainTooltip"
- tooltipOuter.className = "ctrl-tooltip"
- tooltipInner.className = "ctrl-tooltip__inner"
- tooltipTop.className = "ctrl-tooltip__top"
- tooltipBottom.className = "ctrl-tooltip__bottom"
- tooltipTitle.innerHTML = "Keyboard Shortcut"
- tooltipDescription.innerHTML = "Press and hold the Ctrl key (or Cmd key on Macs) while clicking on different locations to select multiple at once."
- tooltipButton.innerHTML = "Got It"
- tooltipButton.addEventListener("click", showHideMultiTooltip)
- tooltipOpener.className = "tooltip-opener"
- tooltipOpener.innerHTML = ''
- tooltipOpener.addEventListener("click", showHideMultiTooltip)
- }
-
- /* Runs an update function when a user removes or adds a feature to the selection list.
- Params:
- @param element: The element that holds the feature pucks.
- @param selectedLayer: The layer where the click originated or where the feature should be removed from.
- */
- async function runSelectionUpdate(element, selectedLayer) {
- // Holds the DOM element that is the lowest single parent, returns HTML DOM Element.
- const prevParent = document.getElementById("selectedLocaleContainer");
-
- const oldMoreBox = document.getElementById("moreBoxWrapper")
- // If the lowest parent element exists, delete it so it can be replaced.
- if(prevParent) element.removeChild(prevParent);
-
- if(oldMoreBox) element.removeChild(oldMoreBox)
- // Create a new div to replace the last and give it an id for deletion later.
- const parent = document.createElement("div");
- parent.id = "selectedLocaleContainer";
- // Use advanced filtering logic to determine all the values present and get a count
- const prevalues = (Object.values(filteredStateNames)).map(element => element);
- const values = [].concat.apply([], prevalues);
- const count = values.length;
- // Create a "See More" puck which users can click to display the hidden selected features.
- const moreWrapper = document.createElement("div");
- // When the total number of objects is greater than 3, simply change the text of the puck to display the number of hidden features
- const moreBoxWrapper = document.createElement("div");
- const moreBox = document.createElement("div");
- moreBox.className = "selected-locale__more-box";
- moreBox.id = "moreBox";
- moreBoxWrapper.appendChild(moreBox);
- moreBoxWrapper.id = "moreBoxWrapper";
- moreBoxWrapper.className = "selected-locale__more-box__wrapper";
- element.appendChild(moreBoxWrapper);
-
- if(count > 3) {
- moreWrapper.className = "selected-locale__more";
- const moreText = document.createElement("span");
- moreText.innerHTML = `+${count - 2} more locales`;
- moreWrapper.appendChild(moreText);
- };
- // Total Count will keep a live count of number of features, returns Integer
- let totalCount = 0;
- // Rotate through each layer using Object.keys to get the layer names
- Object.keys(filteredStateNames).forEach((layer) => {
- // Rotate Through each selected value on a given layer, also keep the index to determine from which position to splice on removal.
- filteredStateNames[layer].forEach((feature, index) => {
- // Increment total count to keep track of which elements should be hidden
- totalCount++;
- // Create each element in order to make a puck. In the else statement the pucks are not hidden.
- const selectedLocale = document.createElement("div");
- const selectedLocaleText = document.createElement("span");
- const removeButton = document.createElement('div');
- removeButton.innerHTML = '';
- // Add an event listener that will remove a value from the list when the `x` is clicked
- removeButton.addEventListener("click", () => {
- // Remove a single element at the index supplied
- filteredStateNames[layer].splice(index, 1);
- // Update the selected locales on the GTM Dashboard
- throwMessage(filteredStateNames);
- // Rerun this function so that the pucks show the item is removed
- runSelectionUpdate(element, selectedLayer);
- })
- // Finish creating the puck and append it to the parent element.
- selectedLocaleText.innerHTML = feature;
- selectedLocale.appendChild(selectedLocaleText);
- selectedLocale.appendChild(removeButton);
-
- if(totalCount > 2 && count > 3) {
- selectedLocale.className = "selected-locale__hidden";
- moreBox.appendChild(selectedLocale)
- } else {
- selectedLocale.className = "selected-locale";
- parent.appendChild(selectedLocale);
- }
- })
- })
- // When the total number of features is empty, revert to the states dashboard, zoom back to center and reset zoom.
- if(totalCount === 0) {
- autoChangeActive("states-join");
- changeGranularity("State");
- mapgl.easeTo({ center: [-98.5795, 39.8283], zoom: 4, duration: 1000 })
- }
- moreWrapper.addEventListener("click", function() {
- if(moreWrapper.classList.contains("active")) {
- runSelectionUpdate(element, selectedLayer)
- } else {
- moreWrapper.classList.toggle("active")
- moreWrapper.innerHTML = "Close"
- const elements = document.querySelectorAll(".selected-locale");
- const mbw = document.getElementById("moreBoxWrapper")
- const mb = document.getElementById("moreBox")
- //elements.forEach((puck) => puck.remove())
- elements.forEach((puck) => mb.appendChild(puck))
- mbw.classList.toggle("active")
- }
- })
- // Add the hidden puck to the selected features
- parent.appendChild(moreWrapper);
- // Append the whole selected locale box to the visualization
- element.appendChild(parent);
- };
-
- /* Params:
- @param e: mapBox click event
- @param layerName: map layer from which mapBox click event originated
- @param lookupData: object containing feature data
- @param localesWrapper: HTML DOM element where pucks are located
- @param replaceCommas: *optional* flag to replace commas in selected features Name
- */
- function hostClickEvent(e, layerName, lookupData, localesWrapper, replaceCommas) {
- // bbox represents the point on the map that was just clicked, returned in the form of longLat
- const bbox = [[e.point.x, e.point.y], [e.point.x, e.point.y]];
- // selectedFeatures represents the features available at the point `bbox`, returns [featureA, featureB, etc...]
- const selectedFeatures = mapgl.queryRenderedFeatures(bbox, {layers: [layerName]});
- // line below maps `name` properties from selectedFeatures above, returns [nameA, nameB, etc...]
- const names = selectedFeatures.map((feature) => feature.state.name);
- // Line below gets the first name (name of closest feature to bbox), returns string or undefined
- var selectedFeatureName = names[0];
- // When selectedFeatureName is undefined, does not execute
- if(selectedFeatureName) {
- // If optional parameter `replaceCommas` is true, attempts to replace commas, upon failing executes console.warn
- if(replaceCommas && selectedFeatureName) selectedFeatureName = selectedFeatureName.replace(",", "")
- /* When the selectedFeatureName is not a property of lookupData or the
- selectedFeatureName is already included in `filteredStateNames[layerName]` then early return */
- if(!lookupData.hasOwnProperty(selectedFeatureName) || filteredStateNames[layerName].includes(selectedFeatureName)) return;
- /* Push the selectedFeatureName into the proper category of `filteredStateNames[layerName]`,
- inline and returns {layerNameA: [featureA, featureB, etc...], layerNameB: [featureA, featureB, etc...]} , etc... */
- filteredStateNames[layerName].push(selectedFeatureName)
- // Updates the pucks that show feature selection bottom-right of the map, returns null
- runSelectionUpdate(localesWrapper, layerName);
- // If the ctrl key is not selected, send data for filter update
- if(!e.originalEvent.ctrlKey) {
- // Send data to GTM Frontend for a looker data refresh, returns null
- throwMessage(filteredStateNames)
- // Get layer names from filteredStateNames with Object.keys(), Returns array: ["layerX", "layerY", "layerZ"]
- const layers = Object.keys(filteredStateNames)
- // Check what the next layer in the list is after the layer currently in use, returns String or undefined
- const nextLayerName = layers[layers.findIndex((element) => element === layerName) + 1]
- // If nextLayerName is not undefined get the grouping name and change granularity to next lowest setting
- if(nextLayerName) {
- // Get the grouping name of the next layer, returns String no undefined
- const nextLayerGrouping = thisLayerNames[thisLayerNames.findIndex((element) => element.name === nextLayerName)].groupingName
- // Update the selected grouping in the GTM Frontend to swap granularities
- changeGranularity(nextLayerGrouping)
- // Automatically change the active layer to the specific layer supplied
- autoChangeActive(nextLayerName)
- }
- }
- }
- }
-
- // When the map loads, create each initial visualization regardless of the existence of data
- mapgl.on('load', () => {
- createStatesViz();
- createCBSAsViz();
- createZipsViz();
- //createMultiTooltip();
- //showHideMultiTooltip();
- });
-
- // When the map goes idle, attach an event listener to the granularity buttons to change to that granularity
- mapgl.on('idle', () => {
- this.__mapStatesButton.addEventListener("click", changeActive);
- this.__mapCBSAsButton.addEventListener("click", changeActive);
- this.__mapZipCodesButton.addEventListener("click", changeActive);
- })
-
- /* As Compared to the next function, this function automatically changes which layer is active rather than determining
- What was clicked.
- Params:
- @param layer: The name of the layer that the visualization will swap to.
- */
- const autoChangeActive = (layer) => {
- // Get all elements with the given class, this will return a collection of DOM elements that are the buttons
- const els = document.getElementsByClassName("map-paginator");
- // Loop through the
- for (let i = 0; i < els.length; i++) {
- if(els[i].classList.contains("active")) els[i].classList.remove("active");
- if(els[i].id === layer) els[i].classList.add("active")
- };
-
- for (let j = 0; j < this.__LAYERNAMES.length; j++) {
- if(this.__LAYERNAMES[j].name !== layer) mapgl.setLayoutProperty(this.__LAYERNAMES[j].name, 'visibility', 'none');
- };
-
- const filteredDown = this.__LAYERNAMES.filter(item => item.name === layer)
- if(filteredDown.length > 0) mapgl.setLayoutProperty(layer, 'visibility', 'visible');
- }
-
- const changeActive = (e) => {
- if(!e.target.classList.contains("active")) {
- // Updates the nav-bar active status
- const els = document.getElementsByClassName("map-paginator");
- for (let i = 0; i < els.length; i++) {
- if(els[i].classList.contains("active")) {
- els[i].classList.remove("active");
- };
- };
-
- e.target.classList.add("active");
-
- // Updates the layers' active status
- for (let j = 0; j < this.__LAYERNAMES.length; j++) {
- if(this.__LAYERNAMES[j].name !== e.target.id)mapgl.setLayoutProperty(this.__LAYERNAMES[j].name, 'visibility', 'none');
- };
-
- const filteredDown = this.__LAYERNAMES.filter(item => item.name === e.target.id)
-
- if(filteredDown.length > 0) {
- mapgl.setLayoutProperty(e.target.id, 'visibility', 'visible');
- changeGranularity(filteredDown[0].groupingName)
- }
-
- }
- }
-
- function getMaxState(arr) {
- const set = data.filter(row => arr.hasOwnProperty(row["dim_zi_map_vis.state"].value));
- try {
- let max = set.reduce((max, item) => max[measureName].value > item[measureName].value ? max : item);
- return max[measureName].value
- } catch {
- return 2
- }
- }
-
- function getMaxCBSA(arr) {
- const set = data.filter(row => arr.hasOwnProperty(row["dim_zi_map_vis.cbsa"].value));
- try {
- let max = set.reduce((max, item) => max[measureName].value > item[measureName].value ? max : item);
- return max[measureName].value
- } catch {
- return 2
- }
- }
-
- function getMaxZip(arr) {
- const set = data.filter(row => arr.hasOwnProperty(row["dim_zi_map_vis.zip"].value));
- try {
- let max = set.reduce((max, item) => max[measureName].value > item[measureName].value ? max : item);
- return max[measureName].value
- } catch {
- return 2
- }
- }
-
- function determineNull(arr, prop) {
- return arr.every(row => row[prop].value === null);
- }
-
- function createStatesViz() {
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
-
- const searchData = stateData.adm1.data.all
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['name']] = featureData
- }
- })
- return lookupData;
- }
- const maxValue = getMaxState(lookupData)
-
- mapgl.addLayer({
- id: 'states-join',
- type: 'fill',
- source: 'statesData',
- 'layout': {
- // Make the layer visible by default.
- 'visibility': 'visible'
- },
- 'source-layer': 'boundaries_admin_1',
- paint: {
- 'fill-color': [
- // In the case that 'feature-state': 'requestedKPI' is not null, interpolate the colors between the min and max, if it is null make the layer white.
- 'case',
- ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],
- 'rgba(255, 255, 255, 0)'
- ]
- }
- }, 'waterway-label');
-
- const popup = new mapboxgl.Popup({
- closeButton: false,
- closeOnClick: false,
- className: 'gtm-map-popup',
- maxWidth: '300px'
- });
-
- mapgl.on('mousemove', 'states-join', (e) => {
- if (e.features.length > 0) {
-
- const realCoords = [e.lngLat.lng, e.lngLat.lat]
- const reqKPI = e.features[0].state.requestedKPI;
- const state = e.features[0].state.name
-
- const description = `
- `
-
- if(e.features[0].state.requestedKPI) {
- popup.setLngLat(realCoords).setHTML(description).addTo(mapgl);
- } else {
- popup.remove;
- return;
- }
-
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: false }
- );
- }
- hoveredStateId = e.features[0].id;
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: true }
- );
- }
- });
-
- // When the mouse leaves the state-fill layer, update the feature state of the
- // previously hovered feature.
- mapgl.on('mouseleave', 'states-join', () => {
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: false }
- );
- popup.remove();
- }
- hoveredStateId = null;
- });
-
- mapgl.on('click', 'states-join', (e) => hostClickEvent(e, 'states-join', lookupData, localesWrapper));
-
- function setStates() {
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.state"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "statesData",
- sourceLayer: 'boundaries_admin_1',
- id: lookupData[row["dim_zi_map_vis.state"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- fipsCode: lookupData[row["dim_zi_map_vis.state"].value].unit_code,
- name: lookupData[row["dim_zi_map_vis.state"].value].name,
- hovered: false
- }
- )
- }
- }
-
- createLegend(data, "dim_zi_map_vis.state", maxValue)
-
- // Check if `statesData` source is loaded.
- function setAfterLoadStates(event) {
- if (event.sourceID !== 'statesData' && !event.isSourceLoaded) return;
- setStates();
- mapgl.off('sourcedata', setAfterLoadStates);
- }
-
- // If `statesData` source is loaded, call `setStates()`.
- if (mapgl.isSourceLoaded('statesData')) {
- setStates();
- } else {
- mapgl.on('sourcedata', setAfterLoadStates);
- }
- }
-
-
- function createCBSAsViz() {
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
-
- const searchData = cbsaData.sta2.data.all
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['name'].replace(",", "")] = featureData
- }
- })
- return lookupData;
- }
-
-
-
- const maxValue = getMaxCBSA(lookupData)
-
- mapgl.addLayer({
- id: 'cbsas-join',
- type: 'fill',
- source: 'cbsaData',
- 'layout': {
- // Make the layer visible by default.
- 'visibility': 'visible'
- },
- 'source-layer': 'boundaries_stats_2',
- paint: {
- 'fill-color': [
- // In the case that 'feature-state': 'requestedKPI' is not null, interpolate the colors between the min and max, if it is null make the layer white.
- 'case',
- ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],
- 'rgba(255, 255, 255, 0)'
- ]
- }
- }, 'waterway-label');
-
- const popup = new mapboxgl.Popup({
- closeButton: false,
- closeOnClick: false,
- className: 'gtm-map-popup',
- maxWidth: '300px'
- });
-
-
- mapgl.on('mousemove', 'cbsas-join', (e) => {
- if (e.features.length > 0) {
-
- const realCoords = [e.lngLat.lng, e.lngLat.lat]
- const reqKPI = e.features[0].state.requestedKPI;
- const cbsa = e.features[0].state.name
-
- const description = `
- `
-
- if(e.features[0].state.requestedKPI) {
- popup.setLngLat(realCoords).setHTML(description).addTo(mapgl);
- } else {
- popup.remove
- }
-
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'cbsaData', id: hoveredStateId, sourceLayer: 'boundaries_stats_2' },
- { hover: false }
- );
- }
- hoveredStateId = e.features[0].id;
- mapgl.setFeatureState(
- { source: 'cbsaData', id: hoveredStateId, sourceLayer: 'boundaries_stats_2' },
- { hover: true }
- );
- }
- });
-
- // When the mouse leaves the state-fill layer, update the feature state of the
- // previously hovered feature.
- mapgl.on('mouseleave', 'cbsas-join', () => {
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'cbsaData', id: hoveredStateId, sourceLayer: 'boundaries_stats_2' },
- { hover: false }
- );
- popup.remove();
- }
- hoveredStateId = null;
- });
-
- mapgl.on('click', 'cbsas-join', (e) => hostClickEvent(e, 'cbsas-join', lookupData, localesWrapper, true));
-
- function setStates() {
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.cbsa"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "cbsaData",
- sourceLayer: 'boundaries_stats_2',
- id: lookupData[row["dim_zi_map_vis.cbsa"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- name: lookupData[row["dim_zi_map_vis.cbsa"].value].name,
- hovered: false
- }
- )
- }
- }
-
- createLegend(data, "dim_zi_map_vis.cbsa", maxValue)
-
- // Check if `statesData` source is loaded.
- function setAfterLoadCBSAs(event) {
- if (event.sourceID !== 'cbsaData' && !event.isSourceLoaded) return;
- setStates();
- mapgl.off('sourcedata', setAfterLoadCBSAs);
- }
-
- // If `statesData` source is loaded, call `setStates()`.
- if (mapgl.isSourceLoaded('cbsaData')) {
- setStates();
- } else {
- mapgl.on('sourcedata', setAfterLoadCBSAs);
- }
- }
-
- function createZipsViz() {
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
-
- const searchData = zipData.pos4.data.all
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['unit_code']] = featureData
- }
- })
- return lookupData;
- }
-
- const maxValue = getMaxZip(lookupData)
-
- mapgl.addLayer({
- id: 'zips-join',
- type: 'fill',
- source: 'zipData',
- 'layout': {
- // Make the layer visible by default.
- 'visibility': 'visible'
- },
- 'source-layer': 'boundaries_postal_4',
- paint: {
- 'fill-color': [
- // In the case that 'feature-state': 'requestedKPI' is not null, interpolate the colors between the min and max, if it is null make the layer white.
- 'case',
- ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],
- 'rgba(255, 255, 255, 0)'
- ]
- }
- }, 'waterway-label');
-
- const popup = new mapboxgl.Popup({
- closeButton: false,
- closeOnClick: false,
- className: 'gtm-map-popup',
- maxWidth: '300px'
- });
-
-
- mapgl.on('mousemove', 'zips-join', (e) => {
- if (e.features.length > 0) {
-
- const realCoords = [e.lngLat.lng, e.lngLat.lat]
- const reqKPI = e.features[0].state.requestedKPI;
- const zip = e.features[0].state.name
-
- const description = `
- `
-
- if(e.features[0].state.requestedKPI) {
- popup.setLngLat(realCoords).setHTML(description).addTo(mapgl);
- } else {
- popup.remove
- }
-
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'zipData', id: hoveredStateId, sourceLayer: 'boundaries_postal_4' },
- { hover: false }
- );
- }
- hoveredStateId = e.features[0].id;
- mapgl.setFeatureState(
- { source: 'zipData', id: hoveredStateId, sourceLayer: 'boundaries_postal_4' },
- { hover: true }
- );
- }
- });
-
- // When the mouse leaves the state-fill layer, update the feature state of the
- // previously hovered feature.
- mapgl.on('mouseleave', 'zips-join', () => {
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'zipData', id: hoveredStateId, sourceLayer: 'boundaries_postal_4' },
- { hover: false }
- );
- popup.remove();
- }
- hoveredStateId = null;
- });
-
- mapgl.on('click', 'zips-join', (e) => hostClickEvent(e, 'zips-join', lookupData, localesWrapper));
-
- function setStates() {
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.zip"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "zipData",
- sourceLayer: 'boundaries_postal_4',
- id: lookupData[row["dim_zi_map_vis.zip"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- name: lookupData[row["dim_zi_map_vis.zip"].value].unit_code,
- hovered: false
- }
- )
- }
- }
-
- createLegend(data, "dim_zi_map_vis.zip", maxValue)
-
- // Check if `statesData` source is loaded.
- function setAfterLoadZips(event) {
- if (event.sourceID !== 'zipData' && !event.isSourceLoaded) return;
- setStates();
- mapgl.off('sourcedata', setAfterLoadZips);
- }
-
- // If `statesData` source is loaded, call `setStates()`.
- if (mapgl.isSourceLoaded('zipData')) {
- setStates();
- } else {
- mapgl.on('sourcedata', setAfterLoadZips);
- }
- }
-
- mapgl.on('style.load', () => {
- mapgl.setFog({
- 'color': 'rgb(186, 210, 235)', // Lower atmosphere
- 'high-color': 'rgb(36, 92, 223)', // Upper atmosphere
- 'horizon-blend': 0.02, // Atmosphere thickness (default 0.2 at low zooms)
- 'space-color': 'rgb(11, 11, 25)', // Background color
- 'star-intensity': 0.6 // Background star brightness (default 0.35 at low zoooms )
- }); // Set the default atmosphere style
- });
-
- function autozoomCBSA() {
- if(mapgl.getSource('cbsaData') && mapgl.isSourceLoaded('cbsaData')) {
- const fu = mapgl.queryRenderedFeatures({ layers: ['cbsas-join'] })
- //const fu = mapgl.querySourceFeatures('cbsaData', { sourceLayer: 'boundaries_stats_2' })
- const f = fu.filter((feature) => feature.state && feature.state.requestedKPI)
- if (f.length > 0) {
- var bb = bbox({ type: 'FeatureCollection', features: f });
- mapgl.fitBounds(bb, {padding: 50});
- mapgl.off("idle", autozoomCBSA)
- }
- }
- }
-
- function autozoomZip() {
- if(mapgl.getSource('zipData') && mapgl.isSourceLoaded('zipData')) {
- const fu = mapgl.queryRenderedFeatures({ layers: ['zips-join'] })
- //const fu = mapgl.querySourceFeatures('cbsaData', { sourceLayer: 'boundaries_stats_2' })
- const f = fu.filter((feature) => feature.state && feature.state.requestedKPI)
- if (f.length > 0) {
- var bb = bbox({ type: 'FeatureCollection', features: f });
- mapgl.fitBounds(bb, {padding: 50});
- mapgl.off("idle", autozoomZip)
- }
- }
- }
-
- runVisUpdate()
-
- function runVisUpdate() {
- mapgl.on("idle", autozoomCBSA)
- mapgl.on("idle", autozoomZip)
-
- const updateStates = () => {
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
- const searchData = stateData.adm1.data.all;
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') lookupData[featureData['name']] = featureData
- })
- return lookupData;
- }
-
- mapgl.removeFeatureState({source: "statesData", sourceLayer: 'boundaries_admin_1'})
-
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.state"].value)) continue;
- mapgl.setFeatureState(
- {
- source: "statesData",
- sourceLayer: 'boundaries_admin_1',
- id: lookupData[row["dim_zi_map_vis.state"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- fipsCode: lookupData[row["dim_zi_map_vis.state"].value].unit_code,
- name: lookupData[row["dim_zi_map_vis.state"].value].name,
- hovered: false
- }
- )
- }
-
- const maxValue = getMaxState(lookupData)
- createLegend(data, "dim_zi_map_vis.state", maxValue)
-
- mapgl.setPaintProperty(
- 'states-join',
- 'fill-color',
- ['case', ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],'rgba(255, 255, 255, 0)']
- )
- }
-
- const updateCBSAs = () => {
- console.log("Updating CBSA's", data)
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
- const searchData = cbsaData.sta2.data.all
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') lookupData[featureData['name'].replace(",", "")] = featureData
- })
- return lookupData;
- }
-
- mapgl.removeFeatureState({source: "cbsaData", sourceLayer: 'boundaries_stats_2'})
-
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.cbsa"].value)) continue;
- mapgl.setFeatureState(
- {
- source: "cbsaData",
- sourceLayer: 'boundaries_stats_2',
- id: lookupData[row["dim_zi_map_vis.cbsa"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- name: lookupData[row["dim_zi_map_vis.cbsa"].value].name,
- hovered: false
- }
- )
- }
-
- const maxValue = getMaxCBSA(lookupData)
- createLegend(data, "dim_zi_map_vis.cbsa", maxValue)
-
- mapgl.setPaintProperty(
- 'cbsas-join',
- 'fill-color',
- ['case', ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],'rgba(255, 255, 255, 0)']
- )
- }
-
- const updateZips = () => {
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
- const searchData = zipData.pos4.data.all;
-
- Object.keys(searchData).forEach(function (key) {
- const featureData = searchData[key];
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['unit_code']] = featureData;
- }
- })
- return lookupData;
- }
-
- mapgl.removeFeatureState({source: "zipData", sourceLayer: 'boundaries_postal_4'});
-
- for (let i = 0; i < data.length; i++) {
- const row = data[i];
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.zip"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "zipData",
- sourceLayer: 'boundaries_postal_4',
- id: lookupData[row["dim_zi_map_vis.zip"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- name: lookupData[row["dim_zi_map_vis.zip"].value].unit_code,
- hovered: false
- }
- )
- }
-
- const maxValue = getMaxZip(lookupData);
-
- createLegend(data, "dim_zi_map_vis.zip", maxValue);
-
- mapgl.setPaintProperty(
- 'zips-join',
- 'fill-color',
- ['case', ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],'rgba(255, 255, 255, 0)']
- );
- }
-
- if(mapgl.getSource('statesData') && mapgl.isSourceLoaded('statesData')) updateStates();
- if(mapgl.getSource('cbsaData') && mapgl.isSourceLoaded('cbsaData')) updateCBSAs();
- if(mapgl.getSource('zipData') && mapgl.isSourceLoaded('zipData')) updateZips();
- }
-
- done()
- }
-});
\ No newline at end of file
diff --git a/src/visualizations/custom/maps/map_test.js b/src/visualizations/custom/maps/map_test.js
index cfea6b8..d9b1cef 100644
--- a/src/visualizations/custom/maps/map_test.js
+++ b/src/visualizations/custom/maps/map_test.js
@@ -6,22 +6,27 @@ import regeneratorRuntime from "regenerator-runtime";
import bbox from '@turf/bbox';
import "core-js/stable";
+// DEV NOTE: Mikel from mapbox asked me to add this to destroy a non-blocking recurring console error
if (mapboxgl.version.indexOf('2.9.') === 0) Object.defineProperty(window, 'caches', { value: undefined });
-function numberWithCommas(x) {
- if(!x) return undefined;
- x = x.toFixed(0);
- var parts = x.toString().split(".");
- parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
- return parts.join(".");
-};
+/* DEV NOTE: In an attempt to make this function run as fast as possible, I switch from using `.toString()` to using '' + x which is 8% faster ,
+This function is used to convert long integers into strings with commas between every three numbers in reverse.
+Params:
+ @param x: a number, specifically an integer
+*/
+const numberWithCommas = (x) => x ? (('' + x.toFixed(0)).split(".")[0]).replace(/\B(?=(\d{3})+(?!\d))/g, ",") : undefined;
+// Add the visualization to the looker plugins, self-explanatory. This object is required for all custom visualizations and should follow this top level layout
looker.plugins.visualizations.add({
id: "thrive_custom_special_granularity_map",
label: "Custom Layered Mapbox Map",
// Set up the initial state of the visualization
create: function (element, config) {
- // Insert a `;
-
- this.__currentLayer = "states-join";
+
+ // This is an object containing the information to refer to for groupingNames and layerNames
this.__LAYERNAMES = [
- {
- name: "states-join",
- groupingName: "State"
- },
- {
- name: "cbsas-join",
- groupingName: "CBSA"
- },
- {
- name: "zips-join",
- groupingName: "Zipcode"
- }
+ { name: "states-join", groupingName: "State" },
+ { name: "cbsas-join", groupingName: "CBSA" },
+ { name: "zips-join", groupingName: "Zipcode" }
];
-
- // Create the top layer selector bar
- //###################################################################################//
-
- this.__mapStatesButton = document.createElement('button');
+ // Create and style all the elements that make up the major components of the map and surrounding UI.
+ this.__mapPaginatorWrapper = element.appendChild(document.createElement('div'));
+ this.__selectedLocalesWrapper = element.appendChild(document.createElement('div'));
+ this.__mapBox = element.appendChild(document.createElement('div'));
+ this.__mapStatesButton = this.__mapPaginatorWrapper.appendChild(document.createElement('button'));
+ this.__mapCBSAsButton = this.__mapPaginatorWrapper.appendChild(document.createElement('button'));
+ this.__mapZipCodesButton = this.__mapPaginatorWrapper.appendChild(document.createElement('button'));
+ this.__mapPaginatorWrapper.className = "map-paginator__wrapper";
+ this.__selectedLocalesWrapper.className = "selected-locales__wrapper";
this.__mapStatesButton.innerHTML = "States";
this.__mapStatesButton.className = "map-paginator active";
this.__mapStatesButton.id = "states-join";
-
- this.__mapCBSAsButton = document.createElement('button');
this.__mapCBSAsButton.innerHTML = "CBSAs";
this.__mapCBSAsButton.className = "map-paginator";
this.__mapCBSAsButton.id = "cbsas-join";
-
- this.__mapZipCodesButton = document.createElement('button');
this.__mapZipCodesButton.innerHTML = "Zip Codes";
this.__mapZipCodesButton.className = "map-paginator";
this.__mapZipCodesButton.id = "zips-join";
-
- this.__mapPaginatorWrapper = document.createElement('div');
- this.__mapPaginatorWrapper.className = "map-paginator__wrapper";
-
- this.__mapPaginatorWrapper.appendChild(this.__mapStatesButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapCBSAsButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapZipCodesButton);
-
- element.appendChild(this.__mapPaginatorWrapper);
-
- this.__selectedLocalesWrapper = document.createElement('div');
- this.__selectedLocalesWrapper.className = "selected-locales__wrapper";
- element.appendChild(this.__selectedLocalesWrapper);
-
- //###################################################################################//
-
- this.__mapBox = document.createElement('div');
this.__mapBox.style.height = '100%';
this.__mapBox.style.width = '100%';
this.__mapBox.id = "map";
- element.appendChild(this.__mapBox);
-
+ // Set the access Token to access the Mapbox GL API
mapboxgl.accessToken = 'pk.eyJ1IjoiZHVuY2FuY2ZyYXNlciIsImEiOiJjbDRvbDlmZWQwMGdzM2ZxazZybTVkdDQ0In0.xL5_LBkos5tYRbLxR0tQRQ';
+ // Initialize the map with the light style, center it on the USA, set a minumum zoom level and turn off scroll interaction.
this.__map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v10',
@@ -365,35 +344,18 @@ looker.plugins.visualizations.add({
zoom: 3.6,
minZoom: 2,
scrollZoom: false,
- //projection: 'globe'
+ dragRotate: false,
+ keyboard: false,
+ maxPitch: 0,
+ touchPitch: false
});
-
+ // Add the +/- Map zoom controls. This also adds a rotation control though it's not super useful
this.__map.addControl(new mapboxgl.NavigationControl());
-
- this.__map.on('load', () => {
- this.__map.addSource('statesData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-adm1-v3'
- }).addSource('cbsaData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-sta2-v3'
- }).addSource('zipData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-pos4-v3'
- });
- });
-
-
- var link = document.createElement('link');
- link.href = 'https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css';
- link.rel = 'stylesheet';
-
- var script = document.createElement('script');
+ // When the map first loads, add all the sources which dictate the behavior of data added to the map
+ this.__map.on('load', () => this.__map.addSource('statesData', { type: 'vector', url: 'mapbox://mapbox.boundaries-adm1-v3'}).addSource('cbsaData', { type: 'vector', url: 'mapbox://mapbox.boundaries-sta2-v3' }).addSource('zipData', { type: 'vector', url: 'mapbox://mapbox.boundaries-pos4-v3' }));
+ var script = document.head.appendChild(document.createElement('script'));
script.src = 'https://kit.fontawesome.com/f2060bf509.js';
script.crossOrigin = "anonymous";
-
- document.head.appendChild(link);
- document.head.appendChild(script);
},
/* Render in response to the data or settings changing
@@ -406,7 +368,6 @@ looker.plugins.visualizations.add({
@param done: function to call to tell Looker you've finished rendering
*/
updateAsync: function (data, element, config, queryResponse, details, done) {
- console.log("Updating in async", queryResponse)
// Clear any errors from previous updates
this.clearErrors(queryResponse.fields);
@@ -674,11 +635,7 @@ looker.plugins.visualizations.add({
});
// When the map goes idle, attach an event listener to the granularity buttons to change to that granularity
- mapgl.on('idle', () => {
- this.__mapStatesButton.addEventListener("click", changeActive);
- this.__mapCBSAsButton.addEventListener("click", changeActive);
- this.__mapZipCodesButton.addEventListener("click", changeActive);
- })
+ mapgl.on('idle', () => document.querySelectorAll('.map-paginator').forEach(button => button.addEventListener("click", changeActive)))
/* As Compared to the next function, this function automatically changes which layer is active rather than determining
What was clicked.
diff --git a/src/visualizations/custom/maps/map_test_old.js b/src/visualizations/custom/maps/map_test_old.js
deleted file mode 100644
index d802b40..0000000
--- a/src/visualizations/custom/maps/map_test_old.js
+++ /dev/null
@@ -1,1223 +0,0 @@
-import mapboxgl from 'mapbox-gl';
-import stateData from './mapbox-boundaries-adm1-v3_4.json';
-import cbsaData from './mapbox-boundaries-sta2-v3_4.json';
-import zipData from './mapbox-boundaries-pos4-v3_4.json';
-import regeneratorRuntime from "regenerator-runtime";
-import bbox from '@turf/bbox';
-import "core-js/stable";
-
-if (mapboxgl.version.indexOf('2.9.') === 0) Object.defineProperty(window, 'caches', { value: undefined });
-
-function numberWithCommas(x) {
- if(!x) return undefined;
- x = x.toFixed(0);
- var parts = x.toString().split(".");
- parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
- return parts.join(".");
-};
-
-looker.plugins.visualizations.add({
- id: "thrive_custom_special_granularity_map",
- label: "Custom Layered Mapbox Map",
- // Set up the initial state of the visualization
- create: function (element, config) {
- // Insert a `;
-
- this.__currentLayer = "states-join";
- this.__LAYERNAMES = [
- {
- name: "states-join",
- groupingName: "State"
- },
- {
- name: "cbsas-join",
- groupingName: "CBSA"
- },
- {
- name: "zips-join",
- groupingName: "Zipcode"
- }
- ];
-
- // Create the top layer selector bar
- //###################################################################################//
-
- this.__mapStatesButton = document.createElement('button');
- this.__mapStatesButton.innerHTML = "States";
- this.__mapStatesButton.className = "map-paginator active";
- this.__mapStatesButton.id = "states-join";
-
- this.__mapCBSAsButton = document.createElement('button');
- this.__mapCBSAsButton.innerHTML = "CBSAs";
- this.__mapCBSAsButton.className = "map-paginator";
- this.__mapCBSAsButton.id = "cbsas-join";
-
- this.__mapZipCodesButton = document.createElement('button');
- this.__mapZipCodesButton.innerHTML = "Zip Codes";
- this.__mapZipCodesButton.className = "map-paginator";
- this.__mapZipCodesButton.id = "zips-join";
-
- this.__mapPaginatorWrapper = document.createElement('div');
- this.__mapPaginatorWrapper.className = "map-paginator__wrapper";
-
- this.__mapPaginatorWrapper.appendChild(this.__mapStatesButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapCBSAsButton);
- this.__mapPaginatorWrapper.appendChild(this.__mapZipCodesButton);
-
- element.appendChild(this.__mapPaginatorWrapper);
-
- this.__selectedLocalesWrapper = document.createElement('div');
- this.__selectedLocalesWrapper.className = "selected-locales__wrapper";
- element.appendChild(this.__selectedLocalesWrapper);
-
- //###################################################################################//
-
- this.__mapBox = document.createElement('div');
- this.__mapBox.style.height = '100%';
- this.__mapBox.style.width = '100%';
- this.__mapBox.id = "map";
-
- element.appendChild(this.__mapBox);
-
- mapboxgl.accessToken = 'pk.eyJ1IjoiZHVuY2FuY2ZyYXNlciIsImEiOiJjbDRvbDlmZWQwMGdzM2ZxazZybTVkdDQ0In0.xL5_LBkos5tYRbLxR0tQRQ';
- this.__map = new mapboxgl.Map({
- container: 'map',
- style: 'mapbox://styles/mapbox/light-v10',
- center: [-98.5795, 39.8283],
- zoom: 4,
- projection: 'globe'
- });
-
- this.__map.addControl(new mapboxgl.NavigationControl());
- this.__map.addControl(new mapboxgl.FullscreenControl());
-
- this.__map.on('load', () => {
- this.__map.addSource('statesData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-adm1-v3'
- }).addSource('cbsaData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-sta2-v3'
- }).addSource('zipData', {
- type: 'vector',
- url: 'mapbox://mapbox.boundaries-pos4-v3'
- });
- });
-
-
- var link = document.createElement('link');
- link.href = 'https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css';
- link.rel = 'stylesheet';
-
- var script = document.createElement('script');
- script.src = 'https://kit.fontawesome.com/f2060bf509.js';
- script.crossOrigin = "anonymous";
-
- document.head.appendChild(link);
- document.head.appendChild(script);
-
- console.log("Create function complete");
- },
-
- /* Render in response to the data or settings changing
- Params:
- @param data: array of returned data with fields
- @param element: HTML DOM element where the vis is stored
- @param config: Settings object on the tile where the vis is located
- @param queryResponse: Entire response to query, includes data object and config object
- @param details: ?
- @param done: function to call to tell Looker you've finished rendering
- */
- updateAsync: function (data, element, config, queryResponse, details, done) {
- // Clear any errors from previous updates
- this.clearErrors(queryResponse.fields);
-
- //When no dimensions and/or no measures are present the viz stops updating and displays an error
- if (queryResponse.fields.measures.length < 1 || queryResponse.fields.dimensions.length < 1) {
- this.addError({ title: "No Measures or Dimensions", message: "This chart requires a measure and a dimension." });
- return;
- }
-
- /* Pass a message to the GTM Frontend to send a locale filter to looker
- Params:
- @param locales: object containing all filtered locales at different levels of granularity
- */
- const throwMessage = (locales) => window.parent.parent.postMessage({ message: "crossFilterLocale", value: locales }, "*");
- /* Pass a message to the GTM Frontend to send a granularity grouping filter to looker
- Params:
- @param g: string representing new grouping to filter to
- */
- const changeGranularity = (g) => window.parent.parent.postMessage({ message: "changeGranularity", value: g }, "*");
-
- // Because `this` does not work properly in functions (`this` goes local), move the map to a more usable variable
- let mapgl = this.__map;
- // Find name of measure, as measure is requested KPI, which is dynamic, returns String
- const measureName = queryResponse.fields.measures[0].name;
- // Find label of measure, as measure is requested KPI, which is dynamic. This prints to UI, returns String
- const measureLabel = queryResponse.fields.measures[0].label_short;
- // Move HTML DOM element from `this` to permanent variable, returns HTML DOM element
- const localesWrapper = this.__selectedLocalesWrapper;
- // Move Object from `this` to permanent variable, returns Object
- const thisLayerNames = this.__LAYERNAMES;
- // Tracks feature currently being hovered, DEV NOTE: To increase conciseness this could be altered to `hoveredFeatureId`, set to null
- let hoveredStateId = null; // Tracks hovered state and updates with popup
- // The object responsible for capturing selected features, DEV NOTE: To increase conciseness this could be altered to `selectedFeatureNames`, set to object of empty arrays
- let filteredStateNames = {
- "states-join": [],
- "cbsas-join": [],
- "zips-join": []
- };
-
- /* Creates legend for the map
- Params:
- @param data: contains current data object at runtime
- @param fieldName: holds the current grouping
- @param max: the maximum value currently represented on the map
- */
- const createLegend = (data, fieldName, max) => {
- // If the grouping is null, return. This keeps the legend in line with the active layer
- if(determineNull(data, fieldName)) return;
- // If there is an old legend, remove it before creating the new one.
- const oldLegendBox = document.getElementById("mapboxLegend");
- if(oldLegendBox) oldLegendBox.parentNode.removeChild(oldLegendBox);
- // Create the elements necessary to construct the legend, all below elements should return HTML DOM nodes
- const legendBox = document.createElement("div");
- const legendLeft = document.createElement("div");
- const legendRight = document.createElement("div");
- const legendBar = document.createElement("div");
- const legendRightTop = document.createElement("div");
- const legendRightBottom = document.createElement("div");
- // Add the proper classes to the legend elements consistent with the CSS styling in `create()`
- legendBox.className = "legend-box";
- legendLeft.className = "legend-left";
- legendRight.className = "legend-right";
- legendBar.className = "legend-bar";
- // Display the maximum value with the proper number of commas for a number it's length
- legendRightTop.innerHTML = numberWithCommas(max);
- // The lower bound is 1, since 0 is never displayed
- legendRightBottom.innerHTML = 1;
- // Append all the elements in order to create the legend from the CSS styling in `create()`
- legendLeft.appendChild(legendBar);
- legendRight.appendChild(legendRightTop);
- legendRight.appendChild(legendRightBottom);
- legendBox.appendChild(legendLeft);
- legendBox.appendChild(legendRight);
- // Give the entire legend an id so it can be deleted on refresh.
- legendBox.id = "mapboxLegend";
- // Append the new legend to the entire visualization
- element.appendChild(legendBox);
- }
-
- /* Runs an update function when a user removes or adds a feature to the selection list.
- Params:
- @param element: The element that holds the feature pucks.
- @param selectedLayer: The layer where the click originated or where the feature should be removed from.
- */
- async function runSelectionUpdate(element, selectedLayer) {
- // Holds the DOM element that is the lowest single parent, returns HTML DOM Element.
- const prevParent = document.getElementById("selectedLocaleContainer");
- // If the lowest parent element exists, delete it so it can be replaced.
- if(prevParent) element.removeChild(prevParent);
- // Create a new div to replace the last and give it an id for deletion later.
- const parent = document.createElement("div");
- parent.id = "selectedLocaleContainer";
- // Use advanced filtering logic to determine all the values present and get a count
- const prevalues = (Object.values(filteredStateNames)).map(element => element);
- const values = [].concat.apply([], prevalues);
- const count = values.length;
- // Create a "See More" puck which users can click to display the hidden selected features.
- const moreWrapper = document.createElement("div");
- // When the total number of objects is greater than 3, simply change the text of the puck to display the number of hidden features
- if(count > 3) {
- moreWrapper.className = "selected-locale__more";
- const moreText = document.createElement("span");
- moreText.innerHTML = `+${count - 2} more locales`;
- moreWrapper.appendChild(moreText);
- };
-
- // Total Count will keep a live count of number of features, returns Integer
- let totalCount = 0;
- Object.keys(filteredStateNames).forEach((layer) => {
- filteredStateNames[layer].forEach((feature, index) => {
- totalCount++;
- if(totalCount > 2 && count > 3) {
- // Here is where we'll create new hidden pucks and append them to a hidden box, for now do nothing
- console.debug("Nothing");
- } else {
- const selectedLocale = document.createElement("div");
- const selectedLocaleText = document.createElement("span");
- const removeButton = document.createElement('div');
- removeButton.innerHTML = '';
-
- removeButton.addEventListener("click", () => {
- filteredStateNames[layer].splice(index, 1);
- throwMessage(filteredStateNames);
- runSelectionUpdate(element, selectedLayer);
- })
-
- selectedLocaleText.innerHTML = feature;
- selectedLocale.className = "selected-locale";
-
- selectedLocale.appendChild(selectedLocaleText);
- selectedLocale.appendChild(removeButton);
- parent.appendChild(selectedLocale);
- }
- })
- })
-
- if(totalCount === 0) {
- autoChangeActive("states-join");
- changeGranularity("State");
- mapgl.zoomTo(4, { duration: 1000, offset: [100, 50] });
- mapgl.panTo([-98.5795, 39.8283], { duration: 1000 });
- }
-
- parent.appendChild(moreWrapper);
- element.appendChild(parent);
- };
-
- /* Params:
- @param e: mapBox click event
- @param layerName: map layer from which mapBox click event originated
- @param lookupData: object containing feature data
- @param localesWrapper: HTML DOM element where pucks are located
- @param replaceCommas: *optional* flag to replace commas in selected features Name
- */
- function hostClickEvent(e, layerName, lookupData, localesWrapper, replaceCommas) {
- // bbox represents the point on the map that was just clicked, returned in the form of longLat
- const bbox = [[e.point.x, e.point.y], [e.point.x, e.point.y]];
- // selectedFeatures represents the features available at the point `bbox`, returns [featureA, featureB, etc...]
- const selectedFeatures = mapgl.queryRenderedFeatures(bbox, {layers: [layerName]});
- // line below maps `name` properties from selectedFeatures above, returns [nameA, nameB, etc...]
- const names = selectedFeatures.map((feature) => feature.state.name);
- // Line below gets the first name (name of closest feature to bbox), returns string or undefined
- var selectedFeatureName = names[0];
-
- // When selectedFeatureName is undefined, does not execute
- if(selectedFeatureName) {
- // If optional parameter `replaceCommas` is true, attempts to replace commas, upon failing executes console.warn
- if(replaceCommas) {
- try {
- // Replace Commas (particularly in CBSAs for comparison), returns string [no undefined]
- selectedFeatureName = selectedFeatureName.replace(",", "")
- } catch (error) {
- // Warns when replace fails, NOTE: may be able to remove
- console.warn("Could not replace null selection: " + selectedFeatureName)
- }
- }
-
- /* When the selectedFeatureName is not a property of lookupData or the
- selectedFeatureName is already included in `filteredStateNames[layerName]` then early return */
- if(!lookupData.hasOwnProperty(selectedFeatureName) || filteredStateNames[layerName].includes(selectedFeatureName)) return;
-
- /* Push the selectedFeatureName into the proper category of `filteredStateNames[layerName]`,
- inline and returns {layerNameA: [featureA, featureB, etc...], layerNameB: [featureA, featureB, etc...]} , etc... */
- filteredStateNames[layerName].push(selectedFeatureName)
- // Updates the pucks that show feature selection bottom-right of the map, returns null
- runSelectionUpdate(localesWrapper, layerName);
-
- // If the ctrl key is not selected, send data for filter update
- if(!e.originalEvent.ctrlKey) {
- // Send data to GTM Frontend for a looker data refresh, returns null
- throwMessage(filteredStateNames)
- const layers = Object.keys(filteredStateNames)
- const nextLayerName = layers[layers.findIndex((element) => element === layerName) + 1]
- if(nextLayerName) {
- const nextLayerGrouping = thisLayerNames[thisLayerNames.findIndex((element) => {console.log("nln", nextLayerName); console.log("element", element.name); return element.name === nextLayerName})].groupingName
- autoChangeActive(nextLayerName)
- changeGranularity(nextLayerGrouping)
- }
- }
- }
- }
-
- mapgl.on('load', () => {
- createStatesViz();
- createCBSAsViz();
- createZipsViz();
- });
-
- mapgl.on('idle', () => {
- this.__mapStatesButton.addEventListener("click", changeActive);
- this.__mapCBSAsButton.addEventListener("click", changeActive);
- this.__mapZipCodesButton.addEventListener("click", changeActive);
- })
-
- const autoChangeActive = (layer) => {
- /* For reference, e.target is one of the buttons on top of the map.
- The event listeners are added in a map.on('idle', () => {}) but have
- previously been added in map.on('load', () => {}) to the same effect*/
- const els = document.getElementsByClassName("map-paginator");
- for (let i = 0; i < els.length; i++) {
- if(els[i].classList.contains("active")) {
- els[i].classList.remove("active");
- };
-
- if(els[i].id === layer) els[i].classList.add("active")
- };
-
- for (let j = 0; j < this.__LAYERNAMES.length; j++) {
- if(this.__LAYERNAMES[j].name !== layer) {
- mapgl.setLayoutProperty(this.__LAYERNAMES[j].name, 'visibility', 'none');
- };
- };
-
- const filteredDown = this.__LAYERNAMES.filter(item => item.name === layer)
- if(filteredDown.length > 0) mapgl.setLayoutProperty(layer, 'visibility', 'visible');
- }
-
- const changeActive = (e) => {
- /* For reference, e.target is one of the buttons on top of the map.
- The event listeners are added in a map.on('idle', () => {}) but have
- previously been added in map.on('load', () => {}) to the same effect*/
-
- //e.preventDefault();
- //e.stopPropagation();
-
- if(!e.target.classList.contains("active")) {
- // Updates the nav-bar active status
- const els = document.getElementsByClassName("map-paginator");
- for (let i = 0; i < els.length; i++) {
- if(els[i].classList.contains("active")) {
- els[i].classList.remove("active");
- };
- };
-
- e.target.classList.add("active");
-
- // Updates the layers' active status
- for (let j = 0; j < this.__LAYERNAMES.length; j++) {
- if(this.__LAYERNAMES[j].name !== e.target.id) {
- mapgl.setLayoutProperty(this.__LAYERNAMES[j].name, 'visibility', 'none');
- };
- };
-
- const filteredDown = this.__LAYERNAMES.filter(item => item.name === e.target.id)
-
- if(filteredDown.length > 0) {
- mapgl.setLayoutProperty(e.target.id, 'visibility', 'visible');
- changeGranularity(filteredDown[0].groupingName)
- }
-
- }
- }
-
- function getMaxState(arr) {
- const set = data.filter(row => arr.hasOwnProperty(row["dim_zi_map_vis.state"].value));
- try {
- let max = set.reduce((max, item) => max[measureName].value > item[measureName].value ? max : item);
- return max[measureName].value
- } catch {
- return 2
- }
- }
-
- function getMaxCBSA(arr) {
- const set = data.filter(row => arr.hasOwnProperty(row["dim_zi_map_vis.cbsa"].value));
- try {
- let max = set.reduce((max, item) => max[measureName].value > item[measureName].value ? max : item);
- return max[measureName].value
- } catch {
- return 2
- }
- }
-
- function getMaxZip(arr) {
- const set = data.filter(row => arr.hasOwnProperty(row["dim_zi_map_vis.zip"].value));
- try {
- let max = set.reduce((max, item) => max[measureName].value > item[measureName].value ? max : item);
- return max[measureName].value
- } catch {
- return 2
- }
- }
-
- function determineNull(arr, prop) {
- return arr.every(row => row[prop].value === null);
- }
-
- function createStatesViz() {
- console.log("CREATING STATES VIZ")
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
-
- const searchData = stateData.adm1.data.all
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['name']] = featureData
- }
- })
- return lookupData;
- }
-
- console.log("GETTING MAX STATE")
- const maxValue = getMaxState(lookupData)
-
- console.log("adding layer")
- mapgl.addLayer({
- id: 'states-join',
- type: 'fill',
- source: 'statesData',
- 'layout': {
- // Make the layer visible by default.
- 'visibility': 'visible'
- },
- 'source-layer': 'boundaries_admin_1',
- paint: {
- 'fill-color': [
- // In the case that 'feature-state': 'requestedKPI' is not null, interpolate the colors between the min and max, if it is null make the layer white.
- 'case',
- ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],
- 'rgba(255, 255, 255, 0)'
- ]
- }
- }, 'waterway-label');
-
- console.log("CREATING POPUP")
-
- const popup = new mapboxgl.Popup({
- closeButton: false,
- closeOnClick: false,
- className: 'gtm-map-popup',
- maxWidth: '300px'
- });
-
- console.log("ADDING EVENT HANDLERS")
-
- mapgl.on('mousemove', 'states-join', (e) => {
- if (e.features.length > 0) {
-
- const realCoords = [e.lngLat.lng, e.lngLat.lat]
- const reqKPI = e.features[0].state.requestedKPI;
- const state = e.features[0].state.name
-
- const description = `
- `
-
- if(e.features[0].state.requestedKPI) {
- popup.setLngLat(realCoords).setHTML(description).addTo(mapgl);
- } else {
- popup.remove;
- return;
- }
-
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: false }
- );
- }
- hoveredStateId = e.features[0].id;
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: true }
- );
- }
- });
-
- // When the mouse leaves the state-fill layer, update the feature state of the
- // previously hovered feature.
- mapgl.on('mouseleave', 'states-join', () => {
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'statesData', id: hoveredStateId, sourceLayer: 'boundaries_admin_1' },
- { hover: false }
- );
- popup.remove();
- }
- hoveredStateId = null;
- });
-
- mapgl.on('click', 'states-join', (e) => hostClickEvent(e, 'states-join', lookupData, localesWrapper));
-
- function setStates() {
- console.log("SETTING STATES")
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.state"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "statesData",
- sourceLayer: 'boundaries_admin_1',
- id: lookupData[row["dim_zi_map_vis.state"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- fipsCode: lookupData[row["dim_zi_map_vis.state"].value].unit_code,
- name: lookupData[row["dim_zi_map_vis.state"].value].name,
- hovered: false
- }
- )
- }
- }
-
- createLegend(data, "dim_zi_map_vis.state", maxValue)
-
- // Check if `statesData` source is loaded.
- function setAfterLoadStates(event) {
- if (event.sourceID !== 'statesData' && !event.isSourceLoaded) return;
- setStates();
- mapgl.off('sourcedata', setAfterLoadStates);
- }
-
- // If `statesData` source is loaded, call `setStates()`.
- if (mapgl.isSourceLoaded('statesData')) {
- setStates();
- } else {
- mapgl.on('sourcedata', setAfterLoadStates);
- }
- }
-
-
- function createCBSAsViz() {
- console.log("CREATING CBSA's VIZ")
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
-
- const searchData = cbsaData.sta2.data.all
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['name'].replace(",", "")] = featureData
- }
- })
- return lookupData;
- }
-
-
-
- const maxValue = getMaxCBSA(lookupData)
-
- mapgl.addLayer({
- id: 'cbsas-join',
- type: 'fill',
- source: 'cbsaData',
- 'layout': {
- // Make the layer visible by default.
- 'visibility': 'visible'
- },
- 'source-layer': 'boundaries_stats_2',
- paint: {
- 'fill-color': [
- // In the case that 'feature-state': 'requestedKPI' is not null, interpolate the colors between the min and max, if it is null make the layer white.
- 'case',
- ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],
- 'rgba(255, 255, 255, 0)'
- ]
- }
- }, 'waterway-label');
-
- const popup = new mapboxgl.Popup({
- closeButton: false,
- closeOnClick: false,
- className: 'gtm-map-popup',
- maxWidth: '300px'
- });
-
-
- mapgl.on('mousemove', 'cbsas-join', (e) => {
- if (e.features.length > 0) {
-
- const realCoords = [e.lngLat.lng, e.lngLat.lat]
- const reqKPI = e.features[0].state.requestedKPI;
- const cbsa = e.features[0].state.name
-
- const description = `
- `
-
- if(e.features[0].state.requestedKPI) {
- popup.setLngLat(realCoords).setHTML(description).addTo(mapgl);
- } else {
- popup.remove
- }
-
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'cbsaData', id: hoveredStateId, sourceLayer: 'boundaries_stats_2' },
- { hover: false }
- );
- }
- hoveredStateId = e.features[0].id;
- mapgl.setFeatureState(
- { source: 'cbsaData', id: hoveredStateId, sourceLayer: 'boundaries_stats_2' },
- { hover: true }
- );
- }
- });
-
- // When the mouse leaves the state-fill layer, update the feature state of the
- // previously hovered feature.
- mapgl.on('mouseleave', 'cbsas-join', () => {
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'cbsaData', id: hoveredStateId, sourceLayer: 'boundaries_stats_2' },
- { hover: false }
- );
- popup.remove();
- }
- hoveredStateId = null;
- });
-
- mapgl.on('click', 'cbsas-join', (e) => hostClickEvent(e, 'cbsas-join', lookupData, localesWrapper, true));
-
- function setStates() {
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.cbsa"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "cbsaData",
- sourceLayer: 'boundaries_stats_2',
- id: lookupData[row["dim_zi_map_vis.cbsa"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- name: lookupData[row["dim_zi_map_vis.cbsa"].value].name,
- hovered: false
- }
- )
- }
- }
-
- createLegend(data, "dim_zi_map_vis.cbsa", maxValue)
-
- // Check if `statesData` source is loaded.
- function setAfterLoadCBSAs(event) {
- if (event.sourceID !== 'cbsaData' && !event.isSourceLoaded) return;
- setStates();
- mapgl.off('sourcedata', setAfterLoadCBSAs);
- }
-
- // If `statesData` source is loaded, call `setStates()`.
- if (mapgl.isSourceLoaded('cbsaData')) {
- setStates();
- } else {
- mapgl.on('sourcedata', setAfterLoadCBSAs);
- }
- }
-
- function createZipsViz() {
- console.log("CREATING zip's VIZ")
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
-
- const searchData = zipData.pos4.data.all
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['unit_code']] = featureData
- }
- })
- return lookupData;
- }
-
- const maxValue = getMaxZip(lookupData)
-
- mapgl.addLayer({
- id: 'zips-join',
- type: 'fill',
- source: 'zipData',
- 'layout': {
- // Make the layer visible by default.
- 'visibility': 'visible'
- },
- 'source-layer': 'boundaries_postal_4',
- paint: {
- 'fill-color': [
- // In the case that 'feature-state': 'requestedKPI' is not null, interpolate the colors between the min and max, if it is null make the layer white.
- 'case',
- ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],
- 'rgba(255, 255, 255, 0)'
- ]
- }
- }, 'waterway-label');
-
- const popup = new mapboxgl.Popup({
- closeButton: false,
- closeOnClick: false,
- className: 'gtm-map-popup',
- maxWidth: '300px'
- });
-
-
- mapgl.on('mousemove', 'zips-join', (e) => {
- if (e.features.length > 0) {
-
- const realCoords = [e.lngLat.lng, e.lngLat.lat]
- const reqKPI = e.features[0].state.requestedKPI;
- const zip = e.features[0].state.name
-
- const description = `
- `
-
- if(e.features[0].state.requestedKPI) {
- popup.setLngLat(realCoords).setHTML(description).addTo(mapgl);
- } else {
- popup.remove
- }
-
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'zipData', id: hoveredStateId, sourceLayer: 'boundaries_postal_4' },
- { hover: false }
- );
- }
- hoveredStateId = e.features[0].id;
- mapgl.setFeatureState(
- { source: 'zipData', id: hoveredStateId, sourceLayer: 'boundaries_postal_4' },
- { hover: true }
- );
- }
- });
-
- // When the mouse leaves the state-fill layer, update the feature state of the
- // previously hovered feature.
- mapgl.on('mouseleave', 'zips-join', () => {
- if (hoveredStateId !== null) {
- mapgl.setFeatureState(
- { source: 'zipData', id: hoveredStateId, sourceLayer: 'boundaries_postal_4' },
- { hover: false }
- );
- popup.remove();
- }
- hoveredStateId = null;
- });
-
- mapgl.on('click', 'zips-join', (e) => hostClickEvent(e, 'zips-join', lookupData, localesWrapper));
-
- function setStates() {
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.zip"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "zipData",
- sourceLayer: 'boundaries_postal_4',
- id: lookupData[row["dim_zi_map_vis.zip"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- name: lookupData[row["dim_zi_map_vis.zip"].value].unit_code,
- hovered: false
- }
- )
- }
- }
-
- createLegend(data, "dim_zi_map_vis.zip", maxValue)
-
- // Check if `statesData` source is loaded.
- function setAfterLoadZips(event) {
- if (event.sourceID !== 'zipData' && !event.isSourceLoaded) return;
- setStates();
- mapgl.off('sourcedata', setAfterLoadZips);
- }
-
- // If `statesData` source is loaded, call `setStates()`.
- if (mapgl.isSourceLoaded('zipData')) {
- setStates();
- } else {
- mapgl.on('sourcedata', setAfterLoadZips);
- }
- }
-
- mapgl.on('style.load', () => {
- mapgl.setFog({
- 'color': 'rgb(186, 210, 235)', // Lower atmosphere
- 'high-color': 'rgb(36, 92, 223)', // Upper atmosphere
- 'horizon-blend': 0.02, // Atmosphere thickness (default 0.2 at low zooms)
- 'space-color': 'rgb(11, 11, 25)', // Background color
- 'star-intensity': 0.6 // Background star brightness (default 0.35 at low zoooms )
- }); // Set the default atmosphere style
- });
-
- const autozoomCBSA = () => {
- console.log("AUTOZOOM CBSA")
- if(mapgl.getSource('cbsaData') && mapgl.isSourceLoaded('cbsaData')) {
- const fu = mapgl.queryRenderedFeatures({ layers: ['cbsas-join'] })
- //const fu = mapgl.querySourceFeatures('cbsaData', { sourceLayer: 'boundaries_stats_2' })
- const f = fu.filter((feature) => feature.state && feature.state.requestedKPI)
- if (f.length > 0) {
- var bb = bbox({ type: 'FeatureCollection', features: f });
- mapgl.fitBounds(bb, {padding: 20});
- mapgl.off("idle", autozoomCBSA)
- }
- }
- }
-
- runVisUpdate()
-
- const runVisUpdate = () => {
- //mapgl.on("idle", autozoomCBSA)
- //mapgl.on("idle", autozoomZip)
-
- const updateStates = () => {
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
- const searchData = stateData.adm1.data.all;
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') lookupData[featureData['name']] = featureData
- })
- return lookupData;
- }
-
- mapgl.removeFeatureState({source: "statesData", sourceLayer: 'boundaries_admin_1'})
-
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.state"].value)) continue;
- mapgl.setFeatureState(
- {
- source: "statesData",
- sourceLayer: 'boundaries_admin_1',
- id: lookupData[row["dim_zi_map_vis.state"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- fipsCode: lookupData[row["dim_zi_map_vis.state"].value].unit_code,
- name: lookupData[row["dim_zi_map_vis.state"].value].name,
- hovered: false
- }
- )
- }
-
- const maxValue = getMaxState(lookupData)
- createLegend(data, "dim_zi_map_vis.state", maxValue)
-
- mapgl.setPaintProperty(
- 'states-join',
- 'fill-color',
- ['case', ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],'rgba(255, 255, 255, 0)']
- )
- }
-
- const updateCBSAs = () => {
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
- const searchData = cbsaData.sta2.data.all
-
- Object.keys(searchData).forEach((key) => {
- const featureData = searchData[key]
- if(featureData.iso_3166_1 === 'US') lookupData[featureData['name'].replace(",", "")] = featureData
- })
- return lookupData;
- }
-
- mapgl.removeFeatureState({source: "cbsaData", sourceLayer: 'boundaries_stats_2'})
-
- for (let i = 0; i < data.length; i++) {
- const row = data[i]
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.cbsa"].value)) continue;
- mapgl.setFeatureState(
- {
- source: "cbsaData",
- sourceLayer: 'boundaries_stats_2',
- id: lookupData[row["dim_zi_map_vis.cbsa"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- name: lookupData[row["dim_zi_map_vis.cbsa"].value].name,
- hovered: false
- }
- )
- }
-
- const maxValue = getMaxCBSA(lookupData)
- createLegend(data, "dim_zi_map_vis.cbsa", maxValue)
-
- mapgl.setPaintProperty(
- 'cbsas-join',
- 'fill-color',
- ['case', ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],'rgba(255, 255, 255, 0)']
- )
- }
-
- const updateZips = () => {
- console.log("Updating Zips")
- const lookupData = filterLookupTable();
-
- function filterLookupTable() {
- const lookupData = {};
- const searchData = zipData.pos4.data.all;
-
- Object.keys(searchData).forEach(function (key) {
- const featureData = searchData[key];
- if(featureData.iso_3166_1 === 'US') {
- lookupData[featureData['unit_code']] = featureData;
- }
- })
- return lookupData;
- }
-
- mapgl.removeFeatureState({source: "zipData", sourceLayer: 'boundaries_postal_4'});
-
- for (let i = 0; i < data.length; i++) {
- const row = data[i];
- if(!lookupData.hasOwnProperty(row["dim_zi_map_vis.zip"].value)) {
- continue;
- }
- mapgl.setFeatureState(
- {
- source: "zipData",
- sourceLayer: 'boundaries_postal_4',
- id: lookupData[row["dim_zi_map_vis.zip"].value].feature_id
- },
- {
- requestedKPI: row[measureName].value,
- name: lookupData[row["dim_zi_map_vis.zip"].value].unit_code,
- hovered: false
- }
- )
- }
-
- const maxValue = getMaxZip(lookupData);
-
- createLegend(data, "dim_zi_map_vis.zip", maxValue);
-
- mapgl.setPaintProperty(
- 'zips-join',
- 'fill-color',
- ['case', ['!=', ['feature-state', 'requestedKPI'], null], ['interpolate', ['linear'], ['feature-state', 'requestedKPI'], 1, 'rgba(255,237,234,0.6)', maxValue, 'rgba(179,18,31,0.6)'],'rgba(255, 255, 255, 0)']
- );
- }
-
- //if(mapgl.getSource('statesData') && mapgl.isSourceLoaded('statesData')) updateStates();
- //if(mapgl.getSource('cbsaData') && mapgl.isSourceLoaded('cbsaData')) updateCBSAs();
- //if(mapgl.getSource('zipData') && mapgl.isSourceLoaded('zipData')) updateZips();
- }
-
- console.log("Update Async complete")
- done()
- }
-});
\ No newline at end of file
diff --git a/src/visualizations/custom/maps/mapbox-boundaries-sta1-v3_4.json b/src/visualizations/custom/maps/mapbox-boundaries-sta1-v3_4.json
deleted file mode 100644
index b139a2b..0000000
--- a/src/visualizations/custom/maps/mapbox-boundaries-sta1-v3_4.json
+++ /dev/null
@@ -1,192 +0,0 @@
-{"sta1": {"type": "stats","level": 1,"PolyTilesetName": "mapbox.boundaries-sta1-v3","PolyLayerName": "boundaries_stats_1","PointTilesetName": "mapbox.boundaries-staPoints-v3","PointLayerName": "points_stats_1","data": {
-"AR":{
-},
-"CN":{
-},
-"IN":{
-},
-"JP":{
-},
-"MA":{
-},
-"RU":{
-},
-"TR":{
-},
-"US":{
-},
-"all":{
-"USS100":{"feature_id":13033,"worldview":"all","unit_code":"000","name":"remainder","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-110.6813,38.885],"bounds":[-187.6522,18.8655,-66.8854,71.4398],"area_sqkm":14549637},
-"USS101":{"feature_id":8729321,"worldview":"all","unit_code":"444","name":"Pueblo-CaƱon City, CO","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-104.5535,38.2185],"bounds":[-106.0128,37.7347,-104.0539,38.6976],"area_sqkm":13007},
-"USS102":{"feature_id":8794857,"worldview":"all","unit_code":"446","name":"Pullman-Moscow, WA-ID","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-117.1668,46.8403],"bounds":[-118.2494,46.4168,-116.3294,47.2607],"area_sqkm":12333},
-"USS104":{"feature_id":8860393,"worldview":"all","unit_code":"448","name":"Quincy-Hannibal, IL-MO","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-91.3802,39.7896],"bounds":[-91.9527,39.3187,-90.912,40.2572],"area_sqkm":7817},
-"USS105":{"feature_id":8925929,"worldview":"all","unit_code":"450","name":"Raleigh-Durham-Cary, NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-78.7309,35.9018],"bounds":[-79.5558,35.2547,-78.0066,36.5438],"area_sqkm":15287},
-"USS106":{"feature_id":8336105,"worldview":"all","unit_code":"428","name":"Philadelphia-Reading-Camden, PA-NJ-DE-MD","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-75.2459,39.7394],"bounds":[-76.4402,38.7887,-74.2321,40.6773],"area_sqkm":28681},
-"USS107":{"feature_id":8991465,"worldview":"all","unit_code":"452","name":"Rapid City-Spearfish, SD","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-103.0283,44.3668],"bounds":[-104.056,43.6851,-102,45.0397],"area_sqkm":25573},
-"USS108":{"feature_id":9057001,"worldview":"all","unit_code":"454","name":"Redding-Red Bluff, CA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-122.0867,40.4945],"bounds":[-123.0688,39.7974,-121.32,41.185],"area_sqkm":23213},
-"USS109":{"feature_id":8467177,"worldview":"all","unit_code":"430","name":"Pittsburgh-New Castle-Weirton, PA-OH-WV","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-79.9413,40.4507],"bounds":[-80.9419,39.7207,-78.799,41.1731],"area_sqkm":24325},
-"USS10A":{"feature_id":8598249,"worldview":"all","unit_code":"438","name":"Portland-Lewiston-South Portland, ME","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-70.3256,43.7073],"bounds":[-70.9891,42.9171,-69.6647,44.4872],"area_sqkm":12031},
-"USS10B":{"feature_id":8663785,"worldview":"all","unit_code":"440","name":"Portland-Vancouver-Salem, OR-WA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-122.5753,45.3049],"bounds":[-123.8168,44.1999,-121.5144,46.3886],"area_sqkm":47536},
-"USS10C":{"feature_id":9122537,"worldview":"all","unit_code":"456","name":"Reno-Carson City-Fernley, NV","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-119.6676,40.2245],"bounds":[-120.0065,38.414,-118.7537,41.9975],"area_sqkm":32962},
-"USS10D":{"feature_id":9188073,"worldview":"all","unit_code":"458","name":"Richmond-Connersville, IN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-85.0579,39.7665],"bounds":[-85.3016,39.5255,-84.8108,40.0064],"area_sqkm":2091},
-"USS10E":{"feature_id":9253609,"worldview":"all","unit_code":"462","name":"Rochester-Austin, MN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-92.5623,43.9793],"bounds":[-93.0496,43.4995,-91.7302,44.4553],"area_sqkm":11551},
-"USS10F":{"feature_id":9319145,"worldview":"all","unit_code":"464","name":"Rochester-Batavia-Seneca Falls, NY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-77.5843,43.0748],"bounds":[-78.4687,42.4592,-76.586,43.6843],"area_sqkm":21779},
-"USS10G":{"feature_id":9384681,"worldview":"all","unit_code":"466","name":"Rockford-Freeport-Rochelle, IL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.197,42.196],"bounds":[-89.9265,41.8855,-88.7054,42.5058],"area_sqkm":7458},
-"USS10H":{"feature_id":9450217,"worldview":"all","unit_code":"468","name":"Rocky Mount-Wilson-Roanoke Rapids, NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-77.7181,36.0665],"bounds":[-78.2572,35.5834,-77.0662,36.5473],"area_sqkm":8686},
-"USS10K":{"feature_id":9515753,"worldview":"all","unit_code":"472","name":"Sacramento-Roseville, CA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-121.0975,38.8337],"bounds":[-122.422,38.0184,-119.8772,39.6395],"area_sqkm":25136},
-"USS10M":{"feature_id":9581289,"worldview":"all","unit_code":"474","name":"Saginaw-Midland-Bay City, MI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-84.1536,43.563],"bounds":[-84.6081,43.1285,-83.6952,43.9971],"area_sqkm":7056},
-"USS10N":{"feature_id":9646825,"worldview":"all","unit_code":"476","name":"St. Louis-St. Charles-Farmington, MO-IL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-90.0333,38.5887],"bounds":[-91.4186,37.641,-88.6952,39.5233],"area_sqkm":30323},
-"USS10P":{"feature_id":9777897,"worldview":"all","unit_code":"482","name":"Salt Lake City-Provo-Orem, UT","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-112.473,40.6703],"bounds":[-114.0479,39.3145,-110.0007,42.0015],"area_sqkm":86785},
-"USS10Q":{"feature_id":9908969,"worldview":"all","unit_code":"488","name":"San Jose-San Francisco-Oakland, CA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-121.4559,37.5428],"bounds":[-123.6325,36.1968,-120.0521,38.8642],"area_sqkm":49614},
-"USS10R":{"feature_id":10040041,"worldview":"all","unit_code":"496","name":"Savannah-Hinesville-Statesboro, GA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-81.3151,31.9927],"bounds":[-82.1479,31.3271,-80.783,32.6534],"area_sqkm":11977},
-"USS10S":{"feature_id":10171113,"worldview":"all","unit_code":"500","name":"Seattle-Tacoma, WA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-122.3811,47.5326],"bounds":[-123.5061,46.3835,-120.6861,48.657],"area_sqkm":51963},
-"USS10V":{"feature_id":10302185,"worldview":"all","unit_code":"515","name":"South Bend-Elkhart-Mishawaka, IN-MI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.0723,41.6448],"bounds":[-87.2078,41.0419,-85.6512,42.2435],"area_sqkm":13987},
-"USS10W":{"feature_id":10433257,"worldview":"all","unit_code":"518","name":"Spokane-Spokane Valley-Coeur d'Alene, WA-ID","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-117.8636,48.1374],"bounds":[-118.4024,47.2593,-116.3294,49.0007],"area_sqkm":21711},
-"USS10Z":{"feature_id":10498793,"worldview":"all","unit_code":"522","name":"Springfield-Jacksonville-Lincoln, IL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.8938,39.8375],"bounds":[-90.6461,39.3458,-89.024,40.3253],"area_sqkm":11305},
-"USS110":{"feature_id":10564329,"worldview":"all","unit_code":"524","name":"State College-DuBois, PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-78.1607,40.9731],"bounds":[-78.8066,40.6916,-77.1438,41.2538],"area_sqkm":7781},
-"USS111":{"feature_id":10629865,"worldview":"all","unit_code":"525","name":"Steamboat Springs-Craig, CO","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-107.8544,40.4637],"bounds":[-109.0512,39.9187,-106.6261,41.0034],"area_sqkm":24340},
-"USS112":{"feature_id":10695401,"worldview":"all","unit_code":"532","name":"Syracuse-Auburn, NY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-76.2954,43.1657],"bounds":[-76.7535,42.6186,-75.2395,43.7081],"area_sqkm":12937},
-"USS114":{"feature_id":10760937,"worldview":"all","unit_code":"534","name":"Toledo-Findlay-Tiffin, OH","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-83.3646,41.3905],"bounds":[-84.3996,40.8181,-82.6161,41.9594],"area_sqkm":12828},
-"USS115":{"feature_id":10826473,"worldview":"all","unit_code":"536","name":"Tucson-Nogales, AZ","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-111.7087,31.9254],"bounds":[-113.3341,31.3323,-110.4476,32.5142],"area_sqkm":31990},
-"USS116":{"feature_id":10892009,"worldview":"all","unit_code":"538","name":"Tulsa-Muskogee-Bartlesville, OK","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-96.0311,36.136],"bounds":[-97.0645,35.2616,-95.0499,36.9995],"area_sqkm":24869},
-"USS117":{"feature_id":11023081,"worldview":"all","unit_code":"540","name":"Tyler-Jacksonville, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-95.2095,32.0586],"bounds":[-95.5945,31.4257,-94.8659,32.687],"area_sqkm":6171},
-"USS118":{"feature_id":11088617,"worldview":"all","unit_code":"544","name":"Victoria-Port Lavaca, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-97.0221,28.5648],"bounds":[-97.7785,28.0228,-96.3227,29.104],"area_sqkm":8239},
-"USS119":{"feature_id":11154153,"worldview":"all","unit_code":"545","name":"Virginia Beach-Norfolk, VA-NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-76.313,36.3817],"bounds":[-77.5019,35.1406,-75.4001,37.6032],"area_sqkm":22685},
-"USS11B":{"feature_id":11219689,"worldview":"all","unit_code":"548","name":"Washington-Baltimore-Arlington, DC-MD-VA-WV-PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-77.344,39.0994],"bounds":[-78.9799,37.8885,-75.7478,40.2899],"area_sqkm":47402},
-"USS11C":{"feature_id":11285225,"worldview":"all","unit_code":"554","name":"Wausau-Stevens Point-Wisconsin Rapids, WI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.7695,44.9035],"bounds":[-90.318,44.2434,-89.223,45.5559],"area_sqkm":15008},
-"USS11D":{"feature_id":11350761,"worldview":"all","unit_code":"556","name":"Wichita-Winfield, KS","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-97.1667,37.5889],"bounds":[-97.8084,36.9985,-96.5228,38.1751],"area_sqkm":17382},
-"USS11E":{"feature_id":11416297,"worldview":"all","unit_code":"558","name":"Williamsport-Lock Haven, PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-77.2608,41.2803],"bounds":[-78.0934,40.9629,-76.4476,41.5969],"area_sqkm":7388},
-"USS11F":{"feature_id":11481833,"worldview":"all","unit_code":"566","name":"Youngstown-Warren, OH-PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-80.7607,41.0441],"bounds":[-81.0874,40.5825,-79.9992,41.5017],"area_sqkm":7853},
-"USS11G":{"feature_id":2306793,"worldview":"all","unit_code":"200","name":"Columbus-West Point, MS","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.4723,33.5467],"bounds":[-89.0361,33.2869,-88.2489,33.8124],"area_sqkm":2905},
-"USS11H":{"feature_id":4666089,"worldview":"all","unit_code":"297","name":"Jackson-Brownsville, TN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.0202,35.7366],"bounds":[-89.5021,35.2473,-88.3518,36.2228],"area_sqkm":7183},
-"USS11J":{"feature_id":5649129,"worldview":"all","unit_code":"324","name":"Lake Charles-Jennings, LA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-93.1885,30.0098],"bounds":[-93.9292,29.5271,-92.5831,30.4905],"area_sqkm":11078},
-"USS11M":{"feature_id":8270569,"worldview":"all","unit_code":"426","name":"Pensacola-Ferry Pass, FL-AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-87.1624,30.7472],"bounds":[-87.6349,30.2295,-86.6881,31.262],"area_sqkm":9086},
-"USS11N":{"feature_id":78569,"worldview":"all","unit_code":"104","name":"Albany-Schenectady, NY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-74.0161,42.8994],"bounds":[-74.7743,41.978,-73.2414,43.8085],"area_sqkm":22141},
-"USS11P":{"feature_id":144105,"worldview":"all","unit_code":"106","name":"Albuquerque-Santa Fe-Las Vegas, NM","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-105.5889,35.6401],"bounds":[-107.6265,34.2598,-103.637,37.0002],"area_sqkm":76303},
-"USS11Q":{"feature_id":275177,"worldview":"all","unit_code":"108","name":"Amarillo-Pampa-Borger, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-101.7904,35.4054],"bounds":[-103.0425,34.7474,-100.5381,36.058],"area_sqkm":25261},
-"USS11R":{"feature_id":799465,"worldview":"all","unit_code":"146","name":"Bloomsburg-Berwick-Sunbury, PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-76.7226,40.9582],"bounds":[-77.3642,40.6035,-76.2078,41.3102],"area_sqkm":5999},
-"USS11S":{"feature_id":865001,"worldview":"all","unit_code":"147","name":"Boise City-Mountain Home-Ontario, ID-OR","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-116.6572,43.267],"bounds":[-118.2339,41.9961,-114.9673,44.5108],"area_sqkm":89596},
-"USS11T":{"feature_id":930537,"worldview":"all","unit_code":"148","name":"Boston-Worcester-Providence, MA-RI-NH-CT","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-71.4529,42.4851],"bounds":[-72.3159,41.0958,-69.8589,43.761],"area_sqkm":43665},
-"USS11V":{"feature_id":340713,"worldview":"all","unit_code":"118","name":"Appleton-Oshkosh-Neenah, WI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.5397,44.2422],"bounds":[-88.8868,43.8915,-88.0417,44.5906],"area_sqkm":5852},
-"USS11W":{"feature_id":406249,"worldview":"all","unit_code":"120","name":"Asheville-Marion-Brevard, NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-82.5866,35.5483],"bounds":[-83.2574,35.0274,-81.8241,36.0659],"area_sqkm":9148},
-"USS11X":{"feature_id":471785,"worldview":"all","unit_code":"122","name":"Atlanta--Athens-Clarke County--Sandy Springs, GA-AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-84.1662,33.7649],"bounds":[-85.5937,32.69,-82.7795,34.8277],"area_sqkm":41553},
-"USS11Y":{"feature_id":537321,"worldview":"all","unit_code":"140","name":"Bend-Prineville, OR","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-120.7157,44.0895],"bounds":[-122.0024,43.6111,-119.655,44.564],"area_sqkm":21744},
-"USS11Z":{"feature_id":602857,"worldview":"all","unit_code":"142","name":"Birmingham-Hoover-Talladega, AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.5961,33.4912],"bounds":[-87.6361,32.6601,-85.7946,34.3138],"area_sqkm":21458},
-"USS120":{"feature_id":668393,"worldview":"all","unit_code":"144","name":"Bloomington-Bedford, IN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.5259,39.081],"bounds":[-87.0549,38.6866,-86.2753,39.4733],"area_sqkm":4181},
-"USS121":{"feature_id":733929,"worldview":"all","unit_code":"145","name":"Bloomington-Pontiac, IL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.6117,40.6992],"bounds":[-89.2694,40.2809,-88.235,41.1142],"area_sqkm":7629},
-"USS122":{"feature_id":996073,"worldview":"all","unit_code":"150","name":"Bowling Green-Glasgow, KY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.1104,37.0133],"bounds":[-86.9449,36.6285,-85.4418,37.3951],"area_sqkm":7897},
-"USS123":{"feature_id":1061609,"worldview":"all","unit_code":"154","name":"Brownsville-Harlingen-Raymondville, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-97.4915,26.2238],"bounds":[-98.0042,25.8372,-97.0893,26.6118],"area_sqkm":5980},
-"USS124":{"feature_id":1127145,"worldview":"all","unit_code":"160","name":"Buffalo-Cheektowaga-Olean, NY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-78.7332,42.8179],"bounds":[-79.3121,41.9976,-78.3081,43.6348],"area_sqkm":13008},
-"USS126":{"feature_id":1389289,"worldview":"all","unit_code":"164","name":"Cape Girardeau-Sikeston, MO-IL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.7373,37.2341],"bounds":[-90.2232,36.8595,-89.1329,37.6065],"area_sqkm":6151},
-"USS127":{"feature_id":1454825,"worldview":"all","unit_code":"168","name":"Cedar Rapids-Iowa City, IA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-91.5995,41.7334],"bounds":[-92.2993,41.1615,-90.898,42.2991],"area_sqkm":11214},
-"USS128":{"feature_id":1520361,"worldview":"all","unit_code":"170","name":"Charleston-Huntington-Ashland, WV-OH-KY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-82.117,38.3715],"bounds":[-83.3415,37.6406,-80.8174,39.0954],"area_sqkm":23840},
-"USS129":{"feature_id":1585897,"worldview":"all","unit_code":"172","name":"Charlotte-Concord, NC-SC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-80.9196,35.2628],"bounds":[-81.7681,34.4578,-79.8485,36.0588],"area_sqkm":20903},
-"USS12A":{"feature_id":1651433,"worldview":"all","unit_code":"174","name":"Chattanooga-Cleveland-Dalton, TN-GA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-85.0881,35.0594],"bounds":[-85.873,34.2861,-84.2924,35.8252],"area_sqkm":15813},
-"USS12B":{"feature_id":1716969,"worldview":"all","unit_code":"176","name":"Chicago-Naperville, IL-IN-WI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-87.7326,41.7103],"bounds":[-89.8624,40.7365,-86.4863,42.6699],"area_sqkm":45358},
-"USS12C":{"feature_id":1782505,"worldview":"all","unit_code":"178","name":"Cincinnati-Wilmington-Maysville, OH-KY-IN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-84.4869,39.0955],"bounds":[-85.2986,38.4563,-83.5763,39.7293],"area_sqkm":17680},
-"USS12D":{"feature_id":1848041,"worldview":"all","unit_code":"184","name":"Cleveland-Akron-Canton, OH","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-81.922,41.2792],"bounds":[-82.9529,40.2143,-80.5192,42.3271],"area_sqkm":32854},
-"USS12E":{"feature_id":1913577,"worldview":"all","unit_code":"185","name":"Cleveland-Indianola, MS","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-90.7452,33.6963],"bounds":[-91.2326,33.27,-90.4503,34.1208],"area_sqkm":5035},
-"USS12F":{"feature_id":1979113,"worldview":"all","unit_code":"188","name":"Clovis-Portales, NM","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-103.4964,34.2651],"bounds":[-103.9492,33.5701,-103.0427,34.9542],"area_sqkm":12121},
-"USS12G":{"feature_id":2044649,"worldview":"all","unit_code":"190","name":"Columbia-Moberly-Mexico, MO","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-92.2829,39.1281],"bounds":[-93.06,38.6432,-91.409,39.6104],"area_sqkm":9747},
-"USS12H":{"feature_id":2110185,"worldview":"all","unit_code":"192","name":"Columbia-Orangeburg-Newberry, SC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-81.2491,33.8989],"bounds":[-82.0103,33.1769,-80.2215,34.6148],"area_sqkm":17583},
-"USS12J":{"feature_id":2175721,"worldview":"all","unit_code":"194","name":"Columbus-Auburn-Opelika, GA-AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-84.913,32.4033],"bounds":[-85.697,31.9203,-84.2862,32.8836],"area_sqkm":10575},
-"USS12K":{"feature_id":2241257,"worldview":"all","unit_code":"198","name":"Columbus-Marion-Zanesville, OH","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-82.4586,39.9452],"bounds":[-84.0148,39.1678,-81.2259,40.7127],"area_sqkm":28958},
-"USS12M":{"feature_id":2372329,"worldview":"all","unit_code":"204","name":"Corpus Christi-Kingsville-Alice, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-98.0088,27.4599],"bounds":[-98.8033,26.5979,-96.7904,28.3192],"area_sqkm":23772},
-"USS12N":{"feature_id":2437865,"worldview":"all","unit_code":"206","name":"Dallas-Fort Worth, TX-OK","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-97.1449,32.9868],"bounds":[-98.5763,31.7962,-95.4281,34.1574],"area_sqkm":50064},
-"USS12P":{"feature_id":2503401,"worldview":"all","unit_code":"209","name":"Davenport-Moline, IA-IL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-90.6138,41.5506],"bounds":[-91.3693,41.0636,-89.8566,42.0336],"area_sqkm":12016},
-"USS12Q":{"feature_id":2568937,"worldview":"all","unit_code":"212","name":"Dayton-Springfield-Kettering, OH","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-84.1629,40.0167],"bounds":[-84.8124,39.5503,-83.4945,40.4832],"area_sqkm":10605},
-"USS12R":{"feature_id":2634473,"worldview":"all","unit_code":"216","name":"Denver-Aurora, CO","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-104.6999,39.857],"bounds":[-106.2102,38.6931,-103.5732,41.0019],"area_sqkm":44411},
-"USS12S":{"feature_id":2700009,"worldview":"all","unit_code":"217","name":"DeRidder-Fort Polk South, LA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-93.199,30.8848],"bounds":[-93.7417,30.4021,-92.8236,31.3648],"area_sqkm":7592},
-"USS12T":{"feature_id":2765545,"worldview":"all","unit_code":"218","name":"Des Moines-Ames-West Des Moines, IA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-93.7553,41.6856],"bounds":[-94.7449,41.1565,-92.4101,42.21],"area_sqkm":20560},
-"USS12V":{"feature_id":2831081,"worldview":"all","unit_code":"220","name":"Detroit-Warren-Ann Arbor, MI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-83.4104,42.5215],"bounds":[-84.3633,41.7066,-82.3341,43.327],"area_sqkm":24797},
-"USS12W":{"feature_id":2896617,"worldview":"all","unit_code":"221","name":"Dixon-Sterling, IL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.5932,41.7572],"bounds":[-90.2479,41.5837,-88.9387,41.9313],"area_sqkm":4950},
-"USS12X":{"feature_id":2962153,"worldview":"all","unit_code":"222","name":"Dothan-Ozark, AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-85.4363,31.384],"bounds":[-86.1935,30.9929,-84.9994,31.7744],"area_sqkm":6961},
-"USS12Y":{"feature_id":3027689,"worldview":"all","unit_code":"232","name":"Eau Claire-Menomonie, WI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-91.529,44.9452],"bounds":[-92.1571,44.5959,-90.9215,45.2922],"area_sqkm":9331},
-"USS12Z":{"feature_id":3093225,"worldview":"all","unit_code":"233","name":"Edwards-Glenwood Springs, CO","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-107.652,39.5367],"bounds":[-109.0515,38.9777,-106.1759,40.0915],"area_sqkm":18903},
-"USS130":{"feature_id":3158761,"worldview":"all","unit_code":"236","name":"Elmira-Corning, NY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-77.4184,42.2901],"bounds":[-77.7499,41.9986,-76.5358,42.5804],"area_sqkm":6348},
-"USS131":{"feature_id":3224297,"worldview":"all","unit_code":"238","name":"El Paso-Las Cruces, TX-NM","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-106.1074,31.8494],"bounds":[-107.2997,30.6293,-104.9071,33.0528],"area_sqkm":28759},
-"USS132":{"feature_id":3289833,"worldview":"all","unit_code":"240","name":"Erie-Meadville, PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-80.1406,42.0093],"bounds":[-80.5199,41.4804,-79.6106,42.5161],"area_sqkm":9036},
-"USS133":{"feature_id":3355369,"worldview":"all","unit_code":"244","name":"Fargo-Wahpeton, ND-MN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-96.7804,46.59],"bounds":[-97.7062,45.9352,-96.1723,47.24],"area_sqkm":18942},
-"USS134":{"feature_id":3420905,"worldview":"all","unit_code":"246","name":"Fayetteville-Sanford-Lumberton, NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-79.0999,34.9666],"bounds":[-79.768,34.2993,-78.4947,35.6283],"area_sqkm":12337},
-"USS136":{"feature_id":3486441,"worldview":"all","unit_code":"258","name":"Fort Wayne-Huntington-Auburn, IN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-85.2449,41.1665],"bounds":[-85.6866,40.5682,-84.8021,41.7602],"area_sqkm":9744},
-"USS137":{"feature_id":3551977,"worldview":"all","unit_code":"260","name":"Fresno-Madera-Hanford, CA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-119.6171,36.7896],"bounds":[-120.9187,35.7887,-118.3606,37.778],"area_sqkm":30946},
-"USS138":{"feature_id":3617513,"worldview":"all","unit_code":"264","name":"Gainesville-Lake City, FL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-82.5103,29.7597],"bounds":[-83.2399,28.9145,-82.0491,30.5977],"area_sqkm":10569},
-"USS139":{"feature_id":3683049,"worldview":"all","unit_code":"266","name":"Grand Rapids-Kentwood-Muskegon, MI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-85.9724,43.1201],"bounds":[-87.1472,42.4154,-84.8353,43.8155],"area_sqkm":27141},
-"USS13A":{"feature_id":3748585,"worldview":"all","unit_code":"267","name":"Green Bay-Shawano, WI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.4933,44.8142],"bounds":[-89.2244,44.2404,-86.7784,45.3789],"area_sqkm":15019},
-"USS13B":{"feature_id":3814121,"worldview":"all","unit_code":"268","name":"Greensboro--Winston-Salem--High Point, NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-79.9782,36.0343],"bounds":[-80.9736,35.5042,-79.2366,36.5623],"area_sqkm":16174},
-"USS13C":{"feature_id":3945193,"worldview":"all","unit_code":"273","name":"Greenville-Spartanburg-Anderson, SC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-82.2889,34.5867],"bounds":[-83.3539,33.9532,-81.3666,35.2155],"area_sqkm":17892},
-"USS13D":{"feature_id":3879657,"worldview":"all","unit_code":"272","name":"Greenville-Kinston-Washington, NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-77.0222,35.4216],"bounds":[-77.8342,35.0081,-76.4678,35.8331],"area_sqkm":6441},
-"USS13E":{"feature_id":4010729,"worldview":"all","unit_code":"276","name":"Harrisburg-York-Lebanon, PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-77.1031,40.1912],"bounds":[-77.6718,39.7198,-76.1512,40.6596],"area_sqkm":11729},
-"USS13F":{"feature_id":5845737,"worldview":"all","unit_code":"338","name":"Lima-Van Wert-Celina, OH","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-84.3412,40.672],"bounds":[-84.8042,40.3517,-83.8798,40.9903],"area_sqkm":5786},
-"USS13G":{"feature_id":4076265,"worldview":"all","unit_code":"277","name":"Harrisonburg-Staunton, VA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-78.9336,38.3674],"bounds":[-79.5333,37.8816,-78.4857,38.8501],"area_sqkm":6203},
-"USS13H":{"feature_id":4141801,"worldview":"all","unit_code":"278","name":"Hartford-East Hartford, CT","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-72.3613,41.6099],"bounds":[-73.0295,41.1778,-71.7877,42.0388],"area_sqkm":8253},
-"USS13K":{"feature_id":4272873,"worldview":"all","unit_code":"284","name":"Hot Springs-Malvern, AR","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-93.0458,34.4621],"bounds":[-93.4081,34.1496,-92.6687,34.7735],"area_sqkm":4272},
-"USS13M":{"feature_id":5911273,"worldview":"all","unit_code":"339","name":"Lincoln-Beatrice, NE","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-96.6881,40.527],"bounds":[-97.3684,40.0008,-96.4633,41.0469],"area_sqkm":7804},
-"USS13N":{"feature_id":4338409,"worldview":"all","unit_code":"288","name":"Houston-The Woodlands, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-95.3084,29.6785],"bounds":[-96.7946,28.2797,-94.3534,31.0581],"area_sqkm":40609},
-"USS13P":{"feature_id":4403945,"worldview":"all","unit_code":"290","name":"Huntsville-Decatur, AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.9031,34.6498],"bounds":[-87.531,34.2991,-86.2558,34.999],"area_sqkm":8633},
-"USS13Q":{"feature_id":4469481,"worldview":"all","unit_code":"292","name":"Idaho Falls-Rexburg-Blackfoot, ID","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-112.3856,43.8165],"bounds":[-113.7984,42.863,-111.0439,44.755],"area_sqkm":34774},
-"USS13R":{"feature_id":4535017,"worldview":"all","unit_code":"294","name":"Indianapolis-Carmel-Muncie, IN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.3225,39.5575],"bounds":[-87.0926,38.725,-85.2003,40.3798],"area_sqkm":24665},
-"USS13S":{"feature_id":4600553,"worldview":"all","unit_code":"296","name":"Ithaca-Cortland, NY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-76.2843,42.5298],"bounds":[-76.6967,42.263,-75.864,42.791],"area_sqkm":3491},
-"USS13T":{"feature_id":4731625,"worldview":"all","unit_code":"298","name":"Jackson-Vicksburg-Brookhaven, MS","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-90.3052,32.3679],"bounds":[-91.1746,31.3492,-89.653,33.3751],"area_sqkm":20598},
-"USS13V":{"feature_id":4797161,"worldview":"all","unit_code":"300","name":"Jacksonville-St. Marys-Palatka, FL-GA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-81.8887,30.2516],"bounds":[-82.4598,29.3244,-81.1508,31.1696],"area_sqkm":15962},
-"USS13W":{"feature_id":4862697,"worldview":"all","unit_code":"304","name":"Johnson City-Kingsport-Bristol, TN-VA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-82.5929,36.443],"bounds":[-83.2889,35.9539,-81.6054,36.929],"area_sqkm":9406},
-"USS13X":{"feature_id":4928233,"worldview":"all","unit_code":"306","name":"Johnstown-Somerset, PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-78.8822,40.2258],"bounds":[-79.4176,39.7216,-78.3484,40.726],"area_sqkm":6018},
-"USS13Y":{"feature_id":4993769,"worldview":"all","unit_code":"308","name":"Jonesboro-Paragould, AR","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-90.6602,35.8538],"bounds":[-91.0392,35.4386,-90.1902,36.268],"area_sqkm":6577},
-"USS13Z":{"feature_id":5059305,"worldview":"all","unit_code":"309","name":"Joplin-Miami, MO-OK","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-94.339,37.0166],"bounds":[-95.0377,36.6675,-94.0523,37.3642],"area_sqkm":5692},
-"USS140":{"feature_id":5124841,"worldview":"all","unit_code":"310","name":"Kalamazoo-Battle Creek-Portage, MI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-85.2366,42.092],"bounds":[-85.7918,41.7589,-84.7096,42.4222],"area_sqkm":8172},
-"USS141":{"feature_id":5190377,"worldview":"all","unit_code":"312","name":"Kansas City-Overland Park-Kansas City, MO-KS","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-94.3381,39.0859],"bounds":[-95.5704,38.026,-93.4772,40.1301],"area_sqkm":37958},
-"USS143":{"feature_id":5452521,"worldview":"all","unit_code":"316","name":"Kokomo-Peru, IN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.0533,40.6878],"bounds":[-86.3758,40.3736,-85.8621,40.9992],"area_sqkm":2292},
-"USS144":{"feature_id":5518057,"worldview":"all","unit_code":"318","name":"Lafayette-Opelousas-Morgan City, LA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-91.9936,30.048],"bounds":[-92.7386,29.2396,-91.0826,30.85],"area_sqkm":19117},
-"USS145":{"feature_id":5583593,"worldview":"all","unit_code":"320","name":"Lafayette-West Lafayette-Frankfort, IN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.9515,40.4331],"bounds":[-87.5314,40.1273,-86.2423,40.7376],"area_sqkm":7006},
-"USS147":{"feature_id":5714665,"worldview":"all","unit_code":"332","name":"Las Vegas-Henderson, NV","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-116.531,37.1181],"bounds":[-118.1963,35.0019,-114.0428,39.1634],"area_sqkm":86342},
-"USS148":{"feature_id":5780201,"worldview":"all","unit_code":"336","name":"Lexington-Fayette--Richmond--Frankfort, KY","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-84.2813,38.0056],"bounds":[-85.1701,37.5153,-83.4339,38.4929],"area_sqkm":10826},
-"USS149":{"feature_id":5976809,"worldview":"all","unit_code":"340","name":"Little Rock-North Little Rock, AR","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-92.2573,34.6243],"bounds":[-93.3059,33.7042,-91.3453,35.5342],"area_sqkm":23120},
-"USS14B":{"feature_id":6042345,"worldview":"all","unit_code":"348","name":"Los Angeles-Long Beach, CA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-116.9325,34.581],"bounds":[-119.6363,32.75,-114.1312,35.8092],"area_sqkm":111084},
-"USS14C":{"feature_id":6107881,"worldview":"all","unit_code":"350","name":"Louisville","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-85.6779,38.1303],"bounds":[-86.4909,37.422,-84.867,38.8318],"area_sqkm":16913},
-"USS14D":{"feature_id":6173417,"worldview":"all","unit_code":"352","name":"Lubbock-Plainview-Levelland, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-101.8233,33.6396],"bounds":[-102.6154,32.9597,-101.0388,34.3131],"area_sqkm":14373},
-"USS14E":{"feature_id":6238953,"worldview":"all","unit_code":"356","name":"Macon-Bibb County--Warner Robins, GA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-83.7479,32.7436],"bounds":[-84.2026,32.2826,-83.2265,33.2026],"area_sqkm":7010},
-"USS14F":{"feature_id":6304489,"worldview":"all","unit_code":"357","name":"Madison-Janesville-Beloit, WI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.7202,43.0704],"bounds":[-90.43,42.4919,-88.7763,43.6437],"area_sqkm":17605},
-"USS14G":{"feature_id":7680745,"worldview":"all","unit_code":"404","name":"New Bern-Morehead City, NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-76.8097,34.9757],"bounds":[-77.731,34.5317,-76.0066,35.4184],"area_sqkm":9951},
-"USS14H":{"feature_id":7746281,"worldview":"all","unit_code":"406","name":"New Orleans-Metairie-Hammond, LA-MS","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.8429,29.9401],"bounds":[-90.9637,28.8551,-88.7584,31.016],"area_sqkm":30686},
-"USS14K":{"feature_id":6370025,"worldview":"all","unit_code":"359","name":"Mankato-New Ulm, MN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-94.4345,44.1742],"bounds":[-95.1088,43.8478,-93.7677,44.4982],"area_sqkm":6687},
-"USS14M":{"feature_id":6435561,"worldview":"all","unit_code":"360","name":"Mansfield-Ashland-Bucyrus, OH","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-82.6196,40.8084],"bounds":[-83.1127,40.5499,-82.125,41.066],"area_sqkm":4555},
-"USS14N":{"feature_id":7811817,"worldview":"all","unit_code":"408","name":"New York-Newark, NY-NJ-CT-PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-73.5695,40.8399],"bounds":[-75.6496,39.4752,-71.7775,42.177],"area_sqkm":53581},
-"USS14P":{"feature_id":6566633,"worldview":"all","unit_code":"362","name":"Martin-Union City, TN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.9713,36.2849],"bounds":[-89.4858,36.0618,-88.5163,36.5072],"area_sqkm":3665},
-"USS14Q":{"feature_id":6697705,"worldview":"all","unit_code":"365","name":"McAllen-Edinburg, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-98.4457,26.4116],"bounds":[-99.1718,26.0363,-97.8617,26.7857],"area_sqkm":8172},
-"USS14R":{"feature_id":6763241,"worldview":"all","unit_code":"366","name":"Medford-Grants Pass, OR","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-123.0956,42.4979],"bounds":[-124.042,41.9951,-122.2827,42.9968],"area_sqkm":15569},
-"USS14S":{"feature_id":6828777,"worldview":"all","unit_code":"368","name":"Memphis-Forrest City, TN-MS-AR","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-90.1206,35.0401],"bounds":[-91.1525,34.4238,-89.1839,35.6523],"area_sqkm":16931},
-"USS14T":{"feature_id":6894313,"worldview":"all","unit_code":"370","name":"Miami-Port St. Lucie-Fort Lauderdale, FL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-80.4557,26.1424],"bounds":[-82.9875,24.3963,-79.9743,27.8614],"area_sqkm":34501},
-"USS14V":{"feature_id":6959849,"worldview":"all","unit_code":"372","name":"Midland-Odessa, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-101.9531,32.0888],"bounds":[-102.7991,31.6511,-101.6887,32.5253],"area_sqkm":8325},
-"USS14W":{"feature_id":7025385,"worldview":"all","unit_code":"376","name":"Milwaukee-Racine-Waukesha, WI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.056,43.0657],"bounds":[-89.0136,42.4919,-87.0439,43.6335],"area_sqkm":21944},
-"USS14X":{"feature_id":7090921,"worldview":"all","unit_code":"378","name":"Minneapolis-St. Paul, MN-WI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-93.1962,45.06],"bounds":[-95.1399,43.8481,-92.1348,46.2471],"area_sqkm":42362},
-"USS14Y":{"feature_id":7156457,"worldview":"all","unit_code":"380","name":"Mobile-Daphne-Fairhope, AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.0146,30.9249],"bounds":[-88.4644,30.1444,-87.3666,31.6993],"area_sqkm":14392},
-"USS150":{"feature_id":7221993,"worldview":"all","unit_code":"384","name":"Monroe-Ruston, LA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-92.2571,32.6373],"bounds":[-92.8814,32.2586,-91.4334,33.0145],"area_sqkm":8698},
-"USS151":{"feature_id":7353065,"worldview":"all","unit_code":"390","name":"Morgantown-Fairmont, WV","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-79.9572,39.4587],"bounds":[-80.4982,39.1949,-79.4766,39.7214],"area_sqkm":4471},
-"USS152":{"feature_id":7418601,"worldview":"all","unit_code":"393","name":"Moses Lake-Othello, WA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-119.4919,47.296],"bounds":[-120.0429,46.6255,-117.9593,47.9622],"area_sqkm":17899},
-"USS153":{"feature_id":7484137,"worldview":"all","unit_code":"394","name":"Mount Pleasant-Alma, MI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-84.8463,43.4678],"bounds":[-85.0888,43.1176,-84.3678,43.8154],"area_sqkm":4103},
-"USS154":{"feature_id":7549673,"worldview":"all","unit_code":"396","name":"Myrtle Beach-Conway, SC-NC","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-78.9796,33.7133],"bounds":[-79.6809,33.0498,-77.897,34.3718],"area_sqkm":10443},
-"USS155":{"feature_id":7615209,"worldview":"all","unit_code":"400","name":"Nashville-Davidson--Murfreesboro, TN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.558,35.8302],"bounds":[-87.6119,34.9994,-85.7786,36.6524],"area_sqkm":23242},
-"USS156":{"feature_id":7877353,"worldview":"all","unit_code":"412","name":"North Port-Sarasota, FL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-82.0651,27.2083],"bounds":[-82.823,26.7696,-81.5623,27.6467],"area_sqkm":9105},
-"USS157":{"feature_id":7942889,"worldview":"all","unit_code":"416","name":"Oklahoma City-Shawnee, OK","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-97.4652,35.4257],"bounds":[-98.3135,34.6812,-96.6193,36.1648],"area_sqkm":20297},
-"USS158":{"feature_id":8008425,"worldview":"all","unit_code":"420","name":"Omaha-Council Bluffs-Fremont, NE-IA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-96.0316,41.3271],"bounds":[-96.9091,40.7835,-95.1546,41.8663],"area_sqkm":17085},
-"USS159":{"feature_id":8073961,"worldview":"all","unit_code":"422","name":"Orlando-Lakeland-Deltona, FL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-81.4769,28.5103],"bounds":[-82.3117,27.3367,-80.6635,29.6711],"area_sqkm":27313},
-"USS15A":{"feature_id":8139497,"worldview":"all","unit_code":"424","name":"Paducah-Mayfield, KY-IL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.7925,36.9652],"bounds":[-89.1826,36.5012,-88.1872,37.4254],"area_sqkm":5470},
-"USS15B":{"feature_id":8205033,"worldview":"all","unit_code":"425","name":"Parkersburg-Marietta-Vienna, WV-OH","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-81.519,39.2718],"bounds":[-81.8537,38.8956,-81.0368,39.646],"area_sqkm":4196},
-"USS160":{"feature_id":8401641,"worldview":"all","unit_code":"429","name":"Phoenix-Mesa, AZ","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-111.6678,33.504],"bounds":[-113.3351,32.5013,-110.0006,34.4993],"area_sqkm":60180},
-"USS161":{"feature_id":10367721,"worldview":"all","unit_code":"517","name":"Spencer-Spirit Lake, IA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-95.1509,43.2062],"bounds":[-95.3888,42.9097,-94.9134,43.5012],"area_sqkm":3471},
-"USS162":{"feature_id":10236649,"worldview":"all","unit_code":"508","name":"Shreveport-Bossier City-Minden, LA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-93.6401,32.4342],"bounds":[-94.0434,31.8442,-93.1464,33.0195],"area_sqkm":10210},
-"USS163":{"feature_id":209641,"worldview":"all","unit_code":"107","name":"Altoona-Huntingdon, PA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-78.2355,40.4034],"bounds":[-78.6204,40.0614,-77.6766,40.7437],"area_sqkm":4827},
-"USS164":{"feature_id":10105577,"worldview":"all","unit_code":"497","name":"Scottsboro-Fort Payne, AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-85.8384,34.5939],"bounds":[-86.359,34.1993,-85.5136,34.9911],"area_sqkm":6017},
-"USS165":{"feature_id":1192681,"worldview":"all","unit_code":"161","name":"Burlington-Fort Madison-Keokuk, IA-IL-MO","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-91.3113,40.6347],"bounds":[-91.9508,40.1931,-90.7852,41.0742],"area_sqkm":9180},
-"USS166":{"feature_id":6501097,"worldview":"all","unit_code":"361","name":"Marinette-Iron Mountain, WI-MI","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-87.7772,45.5116],"bounds":[-88.6842,44.7644,-87.1278,46.247],"area_sqkm":15425},
-"USS167":{"feature_id":10957545,"worldview":"all","unit_code":"539","name":"Tupelo-Corinth, MS","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-88.5333,34.5364],"bounds":[-89.2465,34.0739,-88.1563,34.9961],"area_sqkm":7276},
-"USS168":{"feature_id":7287529,"worldview":"all","unit_code":"388","name":"Montgomery-Selma-Alexander City, AL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-86.4426,32.5361],"bounds":[-87.4731,31.9616,-85.593,33.1073],"area_sqkm":16048},
-"USS169":{"feature_id":9843433,"worldview":"all","unit_code":"484","name":"San Antonio-New Braunfels-Pearsall, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-98.6257,29.3788],"bounds":[-99.6033,28.6127,-97.631,30.139],"area_sqkm":25357},
-"USS170":{"feature_id":4207337,"worldview":"all","unit_code":"279","name":"Hattiesburg-Laurel, MS","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-89.3115,31.569],"bounds":[-89.7558,30.9098,-88.8343,32.2244],"area_sqkm":10389},
-"USS171":{"feature_id":5255913,"worldview":"all","unit_code":"313","name":"Kennewick-Richland-Walla Walla, WA","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-118.995,46.2893],"bounds":[-119.8767,45.8362,-117.9915,46.7391],"area_sqkm":16221},
-"USS172":{"feature_id":9712361,"worldview":"all","unit_code":"480","name":"Salisbury-Cambridge, MD-DE","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-75.6835,38.4439],"bounds":[-76.4388,37.8866,-74.9842,39.0027],"area_sqkm":12853},
-"USS173":{"feature_id":1323753,"worldview":"all","unit_code":"163","name":"Cape Coral-Fort Myers-Naples, FL","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-81.406,26.365],"bounds":[-82.335,25.7695,-80.8727,26.9589],"area_sqkm":13656},
-"USS174":{"feature_id":1258217,"worldview":"all","unit_code":"162","name":"Burlington-South Burlington-Barre, VT","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-73.0755,44.5179],"bounds":[-73.3902,44.0129,-72.2171,45.0167],"area_sqkm":8007},
-"USS175":{"feature_id":5386985,"worldview":"all","unit_code":"315","name":"Knoxville-Morristown-Sevierville, TN","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-83.8751,36.0283],"bounds":[-84.9142,35.4605,-82.8961,36.592],"area_sqkm":16619},
-"USS176":{"feature_id":5321449,"worldview":"all","unit_code":"314","name":"Kerrville-Fredericksburg, TX","description":"core statistical area","unit_code_description":"","source_date":"2019","iso_3166_1_alpha_3":"USA","iso_3166_1":"US","z_min":1,"centroid":[-99.1724,30.1403],"bounds":[-99.7576,29.7814,-98.5878,30.4999],"area_sqkm":6523}}
-}}}
diff --git a/webpack.config.js b/webpack.config.js
index ff8f4ea..633d668 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -17,7 +17,6 @@ var webpackConfig = {
line: './src/visualizations/recycleable/line_charts/line.js',
custom_pbg_table: './src/visualizations/custom/tables/custom_pbg_table.js',
map_test: './src/visualizations/custom/maps/map_test.js',
- map_min: './src/visualizations/custom/maps/map_minimal.js',
},
output: {
filename: "[name].js",