From 2c0c09a50ddbb74ebde98be67bbb67350d27ba0f Mon Sep 17 00:00:00 2001 From: davemfish Date: Wed, 28 Aug 2024 13:27:10 -0400 Subject: [PATCH 01/26] add heat equity layer to default map. #113 --- frontend/src/map/baseLayers.js | 15 +++++++++++++++ frontend/src/map/map.jsx | 2 ++ 2 files changed, 17 insertions(+) diff --git a/frontend/src/map/baseLayers.js b/frontend/src/map/baseLayers.js index 7385041..1c43c4f 100644 --- a/frontend/src/map/baseLayers.js +++ b/frontend/src/map/baseLayers.js @@ -1,11 +1,15 @@ import XYZ from 'ol/source/XYZ'; import TileLayer from 'ol/layer/Tile'; import MapboxVectorLayer from 'ol/layer/MapboxVector'; +import VectorLayer from 'ol/layer/Vector'; +import VectorSource from 'ol/source/Vector'; import VectorTileLayer from 'ol/layer/VectorTile'; import VectorTileSource from 'ol/source/VectorTile'; +import GeoJSON from 'ol/format/GeoJSON'; import MVT from 'ol/format/MVT'; import { labels, nonLabels } from './mapboxLayerNames'; +import { publicUrl } from '../utils'; const satelliteLayer = new TileLayer({ source: new XYZ({ @@ -55,10 +59,21 @@ const parcelLayer = new VectorTileLayer({ parcelLayer.set('title', 'Parcels'); parcelLayer.setZIndex(2); +const heatEquityLayer = new VectorLayer({ + source: new VectorSource({ + format: new GeoJSON(), + url: publicUrl('/opt/appdata/acs_block_group_equity.geojson'), + }), + minZoom: 12, // don't display this layer below zoom level 14 +}); +heatEquityLayer.set('title', 'Heat Equity'); +heatEquityLayer.setZIndex(2); + export { satelliteLayer, lightMapLayer, streetMapLayer, labelLayer, parcelLayer, + heatEquityLayer, }; diff --git a/frontend/src/map/map.jsx b/frontend/src/map/map.jsx index 8fbceba..003d154 100644 --- a/frontend/src/map/map.jsx +++ b/frontend/src/map/map.jsx @@ -41,6 +41,7 @@ import { streetMapLayer, labelLayer, parcelLayer, + heatEquityLayer, } from './baseLayers'; import { hoveredFeatureStyle, @@ -175,6 +176,7 @@ const map = new Map({ scenarioLayerGroup, serviceshedLayerUCM, serviceshedLayerUNA, + heatEquityLayer, ], view: new View({ center: [-10964048.932711, 3429505.23069662], // San Antonio, TX EPSG:3857 From ba83e4cac03a9a972b0b3919e57c8f682941eb07 Mon Sep 17 00:00:00 2001 From: davemfish Date: Wed, 28 Aug 2024 13:39:59 -0400 Subject: [PATCH 02/26] style the equity layer. #113 --- frontend/src/map/baseLayers.js | 18 +++++++++++++++++- frontend/src/map/map.jsx | 1 - 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/frontend/src/map/baseLayers.js b/frontend/src/map/baseLayers.js index 1c43c4f..fb4d949 100644 --- a/frontend/src/map/baseLayers.js +++ b/frontend/src/map/baseLayers.js @@ -7,9 +7,11 @@ import VectorTileLayer from 'ol/layer/VectorTile'; import VectorTileSource from 'ol/source/VectorTile'; import GeoJSON from 'ol/format/GeoJSON'; import MVT from 'ol/format/MVT'; +import { Fill, Stroke, Style } from 'ol/style'; import { labels, nonLabels } from './mapboxLayerNames'; import { publicUrl } from '../utils'; +import HEAT_EQUITY_COLORMAP from '../../../appdata/equity_colormap.json'; const satelliteLayer = new TileLayer({ source: new XYZ({ @@ -64,7 +66,21 @@ const heatEquityLayer = new VectorLayer({ format: new GeoJSON(), url: publicUrl('/opt/appdata/acs_block_group_equity.geojson'), }), - minZoom: 12, // don't display this layer below zoom level 14 + style: (feature) => { + console.log(feature); + const color = HEAT_EQUITY_COLORMAP[feature.get('bivariate_category')]; + return new Style({ + // stroke: new Stroke({ + // color: highlightedStrokeColor, + // width: 3, + // lineDash: [5, 5], + // }), + fill: new Fill({ + color: color, + }), + }); + }, + minZoom: 9, // don't display this layer below zoom level 14 }); heatEquityLayer.set('title', 'Heat Equity'); heatEquityLayer.setZIndex(2); diff --git a/frontend/src/map/map.jsx b/frontend/src/map/map.jsx index 003d154..98d6fba 100644 --- a/frontend/src/map/map.jsx +++ b/frontend/src/map/map.jsx @@ -470,7 +470,6 @@ export default function MapComponent(props) { map.removeLayer(serviceshedLayerUCM); map.removeLayer(serviceshedLayerUNA); const sources = {}; - console.log(servicesheds) if (Object.keys(servicesheds).length) { Object.entries(servicesheds).forEach(([model, path]) => { const source = new VectorSource({ From 7bd7993caa7597416339ca9914fe3940c8bc62ce Mon Sep 17 00:00:00 2001 From: davemfish Date: Thu, 29 Aug 2024 16:55:09 -0400 Subject: [PATCH 03/26] added component for legend to equity layers. #113 --- frontend/src/map/equityLegend.jsx | 59 +++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 frontend/src/map/equityLegend.jsx diff --git a/frontend/src/map/equityLegend.jsx b/frontend/src/map/equityLegend.jsx new file mode 100644 index 0000000..512910f --- /dev/null +++ b/frontend/src/map/equityLegend.jsx @@ -0,0 +1,59 @@ +import React from 'react'; + +import { + HTMLTable, +} from '@blueprintjs/core'; + +import colormap from '../../../appdata/equity_colormap.json'; + +export default function EquityLegend(props) { + const { + show, + } = props; + + const matrix = [ + ['hotter', 2, 12, 22], + ['', 1, 11, 21], + ['cooler', 0, 10, 20], + ['', 'less', '', 'more'], + ]; + + const colorBlocks = []; + matrix.forEach((row) => { + const blocks = []; + row.forEach((idx) => { + if (typeof idx === 'number') { + const color = colormap[idx]; + blocks.push( + +
+ , + ); + } else { + blocks.push({idx}); + } + }); + colorBlocks.push({blocks}); + }); + + if (show) { + return ( +
+ Heat Equity + + + {colorBlocks} + + + % BIPOC +
+ ); + } + return
; +} From e1626461a7de5cfe98099ae55ab8ab1d87cac1ff Mon Sep 17 00:00:00 2001 From: davemfish Date: Thu, 29 Aug 2024 16:55:46 -0400 Subject: [PATCH 04/26] styling equity layer legend. #113. --- frontend/src/index.css | 56 ++++++++++++++++++++++++------ frontend/src/map/baseLayers.js | 4 +-- frontend/src/map/legendControl.jsx | 2 +- frontend/src/map/map.jsx | 22 ++++++++---- scripts/prepare_lulc.py | 6 ++-- 5 files changed, 68 insertions(+), 22 deletions(-) diff --git a/frontend/src/index.css b/frontend/src/index.css index 9add286..f546e8f 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -76,19 +76,58 @@ html, body, #root, .App { font-weight: 600; } -.map-lulc-legend { +.map-legend { background-color: rgba(255,255,255,0.9); - display: flex; - /*height: 1rem;/* - /*padding-bottom: 2rem;*/ - width: 350px; position: absolute; bottom: 1rem; right: 1rem; border-radius: 5px; - padding: 0.5rem; font-weight: 600; align-items: center; + text-align: center; + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +/*.map-equity-legend { + display: grid; + gap: 0.3rem; + grid-template-columns: repeat(3, 1fr); + padding: 0.5rem; +}*/ +.map-legend table.bp4-html-table { + padding-left: 1rem; + padding-right: 1rem; + padding-top: 0.2rem; +} + +.map-legend table.bp4-html-table td { + padding: 0.2rem; + text-align: center; + vertical-align: middle; +} + +.map-legend .title { + font-size: 1.2rem; + vertical-align: middle; +} + +.map-legend .axis-title { + padding-left: 40px; + padding-bottom: 3rem; +} + +.map-lulc-legend { + display: flex; + /*height: 1rem;/* + /*padding-bottom: 2rem;*/ + width: 350px; + padding: 0.5rem; +} + +/*de-saturate to match saturation adjustment in lulcLayer.js*/ +.lulc-legend { + filter: saturate(60%); } /*.edit-wallpaper { @@ -275,11 +314,6 @@ html, body, #root, .App { text-align: center; } -/*de-saturate to match saturation adjustment in lulcLayer.js*/ -.lulc-legend { - filter: saturate(60%); -} - #invest-runner { display: flex; flex-direction: column; diff --git a/frontend/src/map/baseLayers.js b/frontend/src/map/baseLayers.js index fb4d949..b0fc360 100644 --- a/frontend/src/map/baseLayers.js +++ b/frontend/src/map/baseLayers.js @@ -67,7 +67,6 @@ const heatEquityLayer = new VectorLayer({ url: publicUrl('/opt/appdata/acs_block_group_equity.geojson'), }), style: (feature) => { - console.log(feature); const color = HEAT_EQUITY_COLORMAP[feature.get('bivariate_category')]; return new Style({ // stroke: new Stroke({ @@ -83,7 +82,8 @@ const heatEquityLayer = new VectorLayer({ minZoom: 9, // don't display this layer below zoom level 14 }); heatEquityLayer.set('title', 'Heat Equity'); -heatEquityLayer.setZIndex(2); +heatEquityLayer.set('type', 'equity'); +heatEquityLayer.setZIndex(1); export { satelliteLayer, diff --git a/frontend/src/map/legendControl.jsx b/frontend/src/map/legendControl.jsx index 2106a76..fd34a97 100644 --- a/frontend/src/map/legendControl.jsx +++ b/frontend/src/map/legendControl.jsx @@ -38,7 +38,7 @@ export default function LegendControl(props) { { (show) ? ( -
+
- +
+ + +
); } diff --git a/scripts/prepare_lulc.py b/scripts/prepare_lulc.py index 2780886..09137cb 100644 --- a/scripts/prepare_lulc.py +++ b/scripts/prepare_lulc.py @@ -9,8 +9,8 @@ import pygeoprocessing from osgeo import osr -shared_drive = 'H:/Shared drives/Online Urban ES Modeling Tool/Data from Chris/NLUD 2023' -base_raster_path = os.path.join(shared_drive, 'overlay_simple.tif') +shared_drive = 'H:/Shared drives/Online Urban ES Modeling Tool/Data from Chris/LULC and Parameters August 2024' +base_raster_path = os.path.join(shared_drive, 'lulc_overlay_3857.tif') target_raster_path = '../appdata/lulc_overlay_3857.tif' base_info = pygeoprocessing.get_raster_info(base_raster_path) @@ -20,6 +20,8 @@ srs.ImportFromEPSG(3857) target_proj_wkt = srs.ExportToWkt() +# even if we don't need to reproject, this has benefit +# of adding compression. pygeoprocessing.warp_raster( base_raster_path=base_raster_path, target_pixel_size=base_info['pixel_size'], From 3d2103834925a09744ab7b3412dbdc2329dee412 Mon Sep 17 00:00:00 2001 From: davemfish Date: Fri, 30 Aug 2024 10:43:06 -0400 Subject: [PATCH 05/26] use a layer group for the equity layer and lulc. #113 --- frontend/src/map/LayerPanel.jsx | 40 +++++++++++++++++++++++++++++++++ frontend/src/map/baseLayers.js | 18 +++++++++++++-- frontend/src/map/map.jsx | 32 ++++++++++++++++++++------ 3 files changed, 81 insertions(+), 9 deletions(-) diff --git a/frontend/src/map/LayerPanel.jsx b/frontend/src/map/LayerPanel.jsx index 8360d51..ff50460 100644 --- a/frontend/src/map/LayerPanel.jsx +++ b/frontend/src/map/LayerPanel.jsx @@ -30,11 +30,13 @@ export default function LayerPanel(props) { setVisibility, show, switchBasemap, + switchEnviro, switchScenario, selectedScenario, } = props; const [scenario, setScenario] = useState(null); + const [enviro, setEnviro] = useState(null); const [basemap, setBasemap] = useState(null); useEffect(() => { @@ -43,6 +45,11 @@ export default function LayerPanel(props) { if (isVisible) { setBasemap(title); } + } + if (type === 'enviro') { + if (isVisible) { + setEnviro(title); + } } else if (type === 'scenario') { if (isVisible) { setScenario(title); @@ -65,6 +72,12 @@ export default function LayerPanel(props) { setBasemap(title); }; + const handleChangeEnviro = (event) => { + const title = event.target.value; + switchEnviro(title); + setEnviro(title); + }; + const handleChangeScenario = (event) => { const title = event.target.value; switchScenario(title); @@ -73,7 +86,9 @@ export default function LayerPanel(props) { const checkboxes = []; const basemaps = []; + const enviros = []; const scenarios = []; + let enviroGroupCheckbox; let scenarioGroupCheckbox; layers.forEach(([type, title, isVisible]) => { if (!title) { @@ -95,6 +110,14 @@ export default function LayerPanel(props) { value={title} /> ); + } else if (type === 'enviro') { + enviros.push( + + ); } else if (type === 'scenario-group') { scenarioGroupCheckbox = ( setVisibility(title, !isVisible)} /> ); + } else if (type === 'enviro-group') { + enviroGroupCheckbox = ( + setVisibility(title, !isVisible)} + /> + ); } else { checkboxes.push( } + {enviroGroupCheckbox} + + {enviros} +

{ + map.getAllLayers().forEach((layer) => { + if (layer.get('type') === 'enviro') { + layer.setVisible(layer.get('title') === title); + } + }); + // setShowLegendControl(title === 'Landcover'); setMapLayers(); }; @@ -544,6 +561,7 @@ export default function MapComponent(props) { layers={layers} setVisibility={setVisibility} switchBasemap={switchBasemap} + switchEnviro={switchEnviro} switchScenario={switchScenario} selectedScenario={selectedScenario} /> From 567fbeca8d3bc57777e30f939c8163ffedb5ba36 Mon Sep 17 00:00:00 2001 From: davemfish Date: Sat, 31 Aug 2024 12:26:34 -0400 Subject: [PATCH 06/26] fixing visibility of legends. 113. --- frontend/src/map/baseLayers.js | 2 +- ...egendControl.jsx => lulcLegendControl.jsx} | 2 +- frontend/src/map/map.jsx | 38 ++++++++++++------- 3 files changed, 26 insertions(+), 16 deletions(-) rename frontend/src/map/{legendControl.jsx => lulcLegendControl.jsx} (97%) diff --git a/frontend/src/map/baseLayers.js b/frontend/src/map/baseLayers.js index 0105545..befd38e 100644 --- a/frontend/src/map/baseLayers.js +++ b/frontend/src/map/baseLayers.js @@ -91,7 +91,7 @@ const heatEquityLayer = new VectorLayer({ }); heatEquityLayer.set('title', 'Heat Equity'); heatEquityLayer.set('type', 'enviro'); -heatEquityLayer.setZIndex(1); +// heatEquityLayer.setZIndex(1); const enviroLayerGroup = new LayerGroup({}); enviroLayerGroup.set('type', 'enviro-group'); diff --git a/frontend/src/map/legendControl.jsx b/frontend/src/map/lulcLegendControl.jsx similarity index 97% rename from frontend/src/map/legendControl.jsx rename to frontend/src/map/lulcLegendControl.jsx index fd34a97..2a9f1af 100644 --- a/frontend/src/map/legendControl.jsx +++ b/frontend/src/map/lulcLegendControl.jsx @@ -19,7 +19,7 @@ const LULC_TYPES = { tree: 'tree cover', }; -export default function LegendControl(props) { +export default function LULCLegendControl(props) { const { lulcCode, setLulcStyle, diff --git a/frontend/src/map/map.jsx b/frontend/src/map/map.jsx index 989f8b5..e631b3f 100644 --- a/frontend/src/map/map.jsx +++ b/frontend/src/map/map.jsx @@ -33,7 +33,7 @@ import OverlayOp from 'jsts/org/locationtech/jts/operation/overlay/OverlayOp'; import { Button, Icon } from '@blueprintjs/core'; import ParcelControl from './parcelControl'; -import LegendControl from './legendControl'; +import LULCLegendControl from './legendControl'; import EquityLegend from './equityLegend'; import { lulcTileLayer, getStyle } from './lulcLayer'; import LayerPanel from './LayerPanel'; @@ -207,8 +207,8 @@ export default function MapComponent(props) { const [showLayerControl, setShowLayerControl] = useState(false); const [selectedParcel, setSelectedParcel] = useState(null); const [hoveredCode, setHoveredCode] = useState(null); - const [showLegendControl, setShowLegendControl] = useState(false); - const [showEquityLegend, setShowEquityLegend] = useState(true); + const [showLULCLegend, setShowLULCLegend] = useState(false); + const [showEquityLegend, setShowEquityLegend] = useState(false); // refs for elements to insert openlayers-controlled nodes into the dom const mapElementRef = useRef(); @@ -240,6 +240,22 @@ export default function MapComponent(props) { enviroLayerGroup.getVisible(), ], ); + let landcoverVis = false; + const landcoverLayer = map.getAllLayers().find( + (layer) => layer.get('title') === 'Landcover' + ); + if (landcoverLayer) { + landcoverVis = landcoverLayer.getVisible(); + } + let equityLayers = []; + equityLayers = equityLayers.concat(map.getAllLayers().find( + (layer) => Boolean(layer.get('title')) && layer.get('title').includes('Equity') + )); + const equityVis = equityLayers.some((x => x.getVisible())); + setShowLULCLegend( + (landcoverVis && enviroLayerGroup.getVisible()) || scenarioLayerGroup.getVisible() + ); + setShowEquityLegend(equityVis && enviroLayerGroup.getVisible()); setLayers(lyrs); }; @@ -252,16 +268,12 @@ export default function MapComponent(props) { const setVisibility = (title, visible) => { // Use getLayers instead of getAllLayers // so that this can work for Layers and LayerGroups. - // But note this will not reach Layers w/in Groups. + // But note this will not reach Layers within Groups. + // For Layers within groups, we use the dedicated + // switch* methods below. map.getLayers().forEach(lyr => { if (lyr.get('title') === title) { lyr.setVisible(visible); - if (lyr.get('type') === 'scenario-group') { - setShowLegendControl(visible); - } - if (lyr.get('type') === 'equity') { - setShowEquityLegend(visible); - } } }); setMapLayers(); @@ -273,7 +285,6 @@ export default function MapComponent(props) { layer.setVisible(layer.get('title') === title); } }); - // setShowLegendControl(title === 'Landcover'); setMapLayers(); }; @@ -283,7 +294,6 @@ export default function MapComponent(props) { layer.setVisible(layer.get('title') === title); } }); - // setShowLegendControl(title === 'Landcover'); setMapLayers(); }; @@ -575,8 +585,8 @@ export default function MapComponent(props) { immutableStudyArea={Boolean(scenarios.length)} />

- From 1f4524709482b3598f6b9b85d9b1945302d93da2 Mon Sep 17 00:00:00 2001 From: davemfish Date: Tue, 3 Sep 2024 09:45:43 -0400 Subject: [PATCH 07/26] added zoom to default extent control. #113 --- frontend/src/index.css | 3 ++- frontend/src/map/baseLayers.js | 2 +- frontend/src/map/map.jsx | 16 ++++++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/frontend/src/index.css b/frontend/src/index.css index f546e8f..d9f6390 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -38,8 +38,9 @@ html, body, #root, .App { } .layers-control { + display: grid; position: absolute; - top: 3.5rem; + top: 5.5rem; left: 0.5rem; } diff --git a/frontend/src/map/baseLayers.js b/frontend/src/map/baseLayers.js index befd38e..05e3c2b 100644 --- a/frontend/src/map/baseLayers.js +++ b/frontend/src/map/baseLayers.js @@ -91,7 +91,7 @@ const heatEquityLayer = new VectorLayer({ }); heatEquityLayer.set('title', 'Heat Equity'); heatEquityLayer.set('type', 'enviro'); -// heatEquityLayer.setZIndex(1); +heatEquityLayer.setOpacity(0.7); const enviroLayerGroup = new LayerGroup({}); enviroLayerGroup.set('type', 'enviro-group'); diff --git a/frontend/src/map/map.jsx b/frontend/src/map/map.jsx index e631b3f..d05d6b5 100644 --- a/frontend/src/map/map.jsx +++ b/frontend/src/map/map.jsx @@ -24,7 +24,7 @@ import { Translate, defaults as defaultInteractions, } from 'ol/interaction'; -import { defaults } from 'ol/control'; +import { defaults, ZoomToExtent } from 'ol/control'; import OL3Parser from 'jsts/org/locationtech/jts/io/OL3Parser'; import WKTWriter from 'jsts/org/locationtech/jts/io/WKTWriter'; @@ -33,13 +33,14 @@ import OverlayOp from 'jsts/org/locationtech/jts/operation/overlay/OverlayOp'; import { Button, Icon } from '@blueprintjs/core'; import ParcelControl from './parcelControl'; -import LULCLegendControl from './legendControl'; +import LULCLegendControl from './lulcLegendControl'; import EquityLegend from './equityLegend'; import { lulcTileLayer, getStyle } from './lulcLayer'; import LayerPanel from './LayerPanel'; import { satelliteLayer, streetMapLayer, + lightMapLayer, labelLayer, parcelLayer, enviroLayerGroup, @@ -166,6 +167,7 @@ satelliteLayer.setVisible(true); const map = new Map({ layers: [ satelliteLayer, + lightMapLayer, streetMapLayer, // lulcLayer, parcelLayer, @@ -187,7 +189,13 @@ const map = new Map({ controls: defaults({ rotate: false, attribution: true, - }), + }).extend([ + new ZoomToExtent({ + extent: [ + -11009102, 3400218, -10932324, 3471028 + ], + }), + ]), }); export default function MapComponent(props) { @@ -495,7 +503,7 @@ export default function MapComponent(props) { scenarioLayers.push(mostRecentLyr); scenarioLayerGroup.setLayers(new Collection(scenarioLayers)); map.addLayer(scenarioLayerGroup); - setShowLegendControl(true); + setShowLULCLegend(true); } clearSelection(); }, [scenarios]); From 7a54ff068a4607b0459eb2dc692943eb8a2bcc80 Mon Sep 17 00:00:00 2001 From: davemfish Date: Tue, 3 Sep 2024 12:15:57 -0400 Subject: [PATCH 08/26] debugging legend visibility. #113 --- frontend/src/index.css | 10 ++++++++-- frontend/src/map/map.jsx | 22 ++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/frontend/src/index.css b/frontend/src/index.css index d9f6390..a76ccf2 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -77,11 +77,17 @@ html, body, #root, .App { font-weight: 600; } -.map-legend { - background-color: rgba(255,255,255,0.9); +.legend-container { position: absolute; bottom: 1rem; right: 1rem; +} + +.map-legend { + background-color: rgba(255,255,255,0.9); + /*position: absolute; + bottom: 1rem; + right: 1rem;*/ border-radius: 5px; font-weight: 600; align-items: center; diff --git a/frontend/src/map/map.jsx b/frontend/src/map/map.jsx index d05d6b5..2ea512b 100644 --- a/frontend/src/map/map.jsx +++ b/frontend/src/map/map.jsx @@ -427,7 +427,7 @@ export default function MapComponent(props) { map.getAllLayers().forEach((layer) => { // Need to check base Landcover vs Scenario layers since scenario // layers will be in front of base Landcover - if (layer.get('title') === 'Landcover' && layer.get('type') === 'base') { + if (layer.get('title') === 'Landcover') { if (layer.getVisible()) { baseData = layer.getData(event.pixel); } @@ -440,13 +440,14 @@ export default function MapComponent(props) { if (scenarioData && scenarioData[1]) { // check band [1] for nodata // Get here if a Scenario LULC is visible setHoveredCode(scenarioData[0].toString()); - } else if (baseData && baseData[1]) { + return; + } + if (baseData && baseData[1]) { // Base LULC visible but no Scenario LULC visible setHoveredCode(baseData[0].toString()); - } else { - // No scenario LULC or base LULC selected / visible - setHoveredCode(null); + return; } + setHoveredCode(null); }); // Some layers have style dependent on zoom level @@ -491,6 +492,7 @@ export default function MapComponent(props) { // A naive approach where we don't need to know if scenarios changed // because a new one was created, or because the study area was switched. map.removeLayer(scenarioLayerGroup); + scenarioLayerGroup.setVisible(false); if (scenarios.length) { const scenarioLayers = []; scenarios.forEach((scene) => { @@ -502,8 +504,8 @@ export default function MapComponent(props) { mostRecentLyr.setVisible(true); scenarioLayers.push(mostRecentLyr); scenarioLayerGroup.setLayers(new Collection(scenarioLayers)); + scenarioLayerGroup.setVisible(true); map.addLayer(scenarioLayerGroup); - setShowLULCLegend(true); } clearSelection(); }, [scenarios]); @@ -592,15 +594,15 @@ export default function MapComponent(props) { refreshStudyArea={refreshStudyArea} immutableStudyArea={Boolean(scenarios.length)} /> -
+
+ -
); From aa74bafdc48d8afabc9fc74f5b54a12ecea3674a Mon Sep 17 00:00:00 2001 From: davemfish Date: Wed, 4 Sep 2024 16:41:21 -0400 Subject: [PATCH 09/26] new landing tab for first-time users. #113 --- frontend/package.json | 13 +- frontend/src/App.jsx | 12 ++ frontend/src/edit/edit.jsx | 27 +++- frontend/src/edit/explore.jsx | 49 ++++++ frontend/src/index.css | 27 ++-- frontend/src/map/equityLegend.jsx | 4 +- frontend/src/map/map.jsx | 18 ++- frontend/src/map/parcelControl.jsx | 54 +++---- frontend/yarn.lock | 242 ++++++++++------------------- 9 files changed, 230 insertions(+), 216 deletions(-) create mode 100644 frontend/src/edit/explore.jsx diff --git a/frontend/package.json b/frontend/package.json index 22c49f2..f0cc417 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -2,8 +2,7 @@ "name": "urban-es-modeler", "private": true, "version": "0.0.0", - "scripts": - { + "scripts": { "start": "vite", "start-docker": "cross-env MODE=docker vite --host 0.0.0.0 --port 3000", "build": "vite build", @@ -11,9 +10,8 @@ "test": "vitest run --dir tests --coverage", "test-e2e": "vitest run --dir tests-e2e" }, - "dependencies": - { - "@blueprintjs/core": "^4.4.0", + "dependencies": { + "@blueprintjs/core": "^5.12.0", "dotenv": "^16.0.0", "jsts": "^2.9.3", "localforage": "^1.10.0", @@ -21,8 +19,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0" }, - "devDependencies": - { + "devDependencies": { "@babel/eslint-parser": "^7.18.2", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^14.0.0", @@ -43,4 +40,4 @@ "vite": "^4.4.9", "vitest": "^0.34.0" } -} \ No newline at end of file +} diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 18763d6..fe0fb7d 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -25,6 +25,8 @@ export default function App() { const [patternSampleWKT, setPatternSampleWKT] = useState(null); const [selectedScenario, setSelectedScenario] = useState(null); const [servicesheds, setServicesheds] = useState({}); + const [activeTab, setActiveTab] = useState('explore'); + const [start, setStart] = useState(0); const switchStudyArea = async (id) => { let area; @@ -67,6 +69,11 @@ export default function App() { setPatternSamplingMode((mode) => !mode); }; + const startBuilding = () => { + setStart((start) => start + 1); + setActiveTab('scenarios'); + }; + useEffect(() => { (async () => { let SID = localStorage.getItem('sessionID'); @@ -121,6 +128,8 @@ export default function App() { scenarios={scenarios} selectedScenario={selectedScenario} servicesheds={servicesheds} + activeTab={activeTab} + start={start} />
diff --git a/frontend/src/edit/edit.jsx b/frontend/src/edit/edit.jsx index 19a61d7..580e628 100644 --- a/frontend/src/edit/edit.jsx +++ b/frontend/src/edit/edit.jsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { FocusStyleManager, + Section, Tab, Tabs, } from '@blueprintjs/core'; @@ -13,6 +14,7 @@ import StudyAreaTable from './studyAreaTable'; import InputStudyAreaName from './inputStudyAreaName'; import InvestRunner from './investRunner'; import Results from './results'; +import Explore from './explore'; import { getInvestResults } from '../requests'; import nlcdLookup from '../../../appdata/nlcd_colormap.json'; @@ -43,9 +45,12 @@ export default function EditMenu(props) { savedStudyAreas, setSelectedScenario, setServicesheds, + setActiveTab, + activeTab, + startBuilding, } = props; - const [activeTab, setActiveTab] = useState('scenarios'); + // const [activeTab, setActiveTab] = useState('explore'); const [results, setResults] = useState({}); const [scenarioDescriptions, setScenarioDescriptions] = useState(null); @@ -114,6 +119,15 @@ export default function EditMenu(props) { onChange={(tabID) => setActiveTab(tabID)} selectedTabId={activeTab} > + + )} + /> ) : ( -

- Click on the map to add parcels -

+
+
    +
  1. Click on the map to select a parcel
  2. +
  3. Add any number of parcels to a study area
  4. +
+
) } +
+ {INTRO_TEXT} + + + + {ECO_TEXT} + + {SCENARIO_TEXT} + + + + +
+
+ ); +} diff --git a/frontend/src/index.css b/frontend/src/index.css index a76ccf2..1d96ab4 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -77,17 +77,26 @@ html, body, #root, .App { font-weight: 600; } -.legend-container { +.layer-info div { + display: flex; +} + +.layer-info button:first-child { + flex-grow: 1; +} + +/*.legend-container { position: absolute; bottom: 1rem; right: 1rem; -} +}*/ -.map-legend { +/*.map-legend {*/ +.legend-container { background-color: rgba(255,255,255,0.9); - /*position: absolute; + position: absolute; bottom: 1rem; - right: 1rem;*/ + right: 1rem; border-radius: 5px; font-weight: 600; align-items: center; @@ -102,24 +111,24 @@ html, body, #root, .App { grid-template-columns: repeat(3, 1fr); padding: 0.5rem; }*/ -.map-legend table.bp4-html-table { +.equity-legend table.bp4-html-table { padding-left: 1rem; padding-right: 1rem; padding-top: 0.2rem; } -.map-legend table.bp4-html-table td { +.equity-legend table.bp4-html-table td { padding: 0.2rem; text-align: center; vertical-align: middle; } -.map-legend .title { +.equity-legend .title { font-size: 1.2rem; vertical-align: middle; } -.map-legend .axis-title { +.equity-legend .axis-title { padding-left: 40px; padding-bottom: 3rem; } diff --git a/frontend/src/map/equityLegend.jsx b/frontend/src/map/equityLegend.jsx index 512910f..7c2b24e 100644 --- a/frontend/src/map/equityLegend.jsx +++ b/frontend/src/map/equityLegend.jsx @@ -44,9 +44,9 @@ export default function EquityLegend(props) { if (show) { return ( -
+
Heat Equity - + {colorBlocks} diff --git a/frontend/src/map/map.jsx b/frontend/src/map/map.jsx index 2ea512b..1472ac6 100644 --- a/frontend/src/map/map.jsx +++ b/frontend/src/map/map.jsx @@ -210,7 +210,10 @@ export default function MapComponent(props) { scenarios, selectedScenario, servicesheds, + activeTab, + start, } = props; + console.log(activeTab) const [layers, setLayers] = useState([]); const [showLayerControl, setShowLayerControl] = useState(false); const [selectedParcel, setSelectedParcel] = useState(null); @@ -348,6 +351,18 @@ export default function MapComponent(props) { ); }; + useEffect(() => { + const center = [-10968819.475036152, 3423289.328458109]; + if (start) { + setVisibility('Environment', false); + const view = map.getView(); + view.animate({ + center: center, + zoom: 17, + }); + } + }, [start]); + useEffect(() => { if (selectedScenario) { switchScenario(selectedScenario); } }, [selectedScenario]); @@ -387,6 +402,7 @@ export default function MapComponent(props) { ); map.on(['click'], async (event) => { + console.log(map.getCoordinateFromPixel(event.pixel)); // NOTE that a feature's geometry can change with the tile/zoom level and // view position and so its coordinates will change slightly. parcelLayer.getFeatures(event.pixel).then(async (features) => { @@ -596,7 +612,7 @@ export default function MapComponent(props) { />
- {(!parcel) - ?

Select a parcel

- : ( - <> - - - - {parcel.parcelID} - {parcel.address || '123 Main St'} - - - - -
- ); + if (parcel) { + return ( +
+

{parcel.address}

+
+ + +
+
+ ); + } + return
; } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 2b29a9f..ea50f45 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -219,7 +219,7 @@ core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.16.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.10.2", "@babel/runtime@^7.16.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7": version "7.18.3" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.3.tgz#c7b654b57f6f63cf7f8b418ac9ca04408c4579f4" integrity sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug== @@ -279,45 +279,37 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@blueprintjs/colors@^4.1.3": - version "4.1.3" - resolved "https://registry.yarnpkg.com/@blueprintjs/colors/-/colors-4.1.3.tgz#7e0a32a086bdc68ea51df0dda1f94913dbd874c1" - integrity sha512-ANRQZT5h9+zC8B/y0S9B+SqEpicL0XRT4drAhiPFHBrOStRZWzOh3bPrwNSPqr7tdShxYtMyxbH+fkHMetZaxg== - -"@blueprintjs/core@^4.4.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-4.4.0.tgz#e21f79db8410d354bed9c43862d1ba03e8524d78" - integrity sha512-RXjcw+CK/YgspJpn6eDg8izg2gS4jDuCryJBfoz8EyhSwsNblsE9ww85/1XMmA/ve5/RnrEqE9YNew30TO/Ucw== - dependencies: - "@blueprintjs/colors" "^4.1.3" - "@blueprintjs/icons" "^4.3.0" - "@juggle/resize-observer" "^3.3.1" - "@types/dom4" "^2.0.1" - classnames "^2.2" - dom4 "^2.1.5" - normalize.css "^8.0.1" - popper.js "^1.16.1" - react-popper "^1.3.7" - react-transition-group "^4.4.1" - tslib "~2.3.1" +"@blueprintjs/colors@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@blueprintjs/colors/-/colors-5.1.2.tgz#caa1edf6521670e4be3e9f2061cd3fe14e363a5b" + integrity sha512-7CWwVsXK4YTN9Z/wkjnS3p7VE8YfIXXv2UaySAbtcw6rBkmoSHjLRtfohSA5yNy8xYTQ4KY2odKZSUW0W/Nltw== + dependencies: + tslib "~2.6.2" -"@blueprintjs/icons@^4.3.0": - version "4.3.0" - resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-4.3.0.tgz#01fb41cc323b9ce98f078f8273730884979b7da5" - integrity sha512-uLEdVUkWe0E2Bzfh2mqW2/3DRCqFo/vsSBYXrqOzFPiBsxCnu8ySEPInJWU+OHHPA/zM1hYMfrvKjfyaIIgbew== +"@blueprintjs/core@^5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-5.12.0.tgz#3c5030ab98fa94d8ba02d76988e41296741f3480" + integrity sha512-ILXicpMElDsWK3up46HBxdGAdkm5gTYUpSZXwzWi0TKmjUPm7LhiYNsfUpMhtgMuQT2CsCOY8kh6sbBpInoHNQ== dependencies: - change-case "^4.1.2" - classnames "^2.2" - tslib "~2.3.1" + "@blueprintjs/colors" "^5.1.2" + "@blueprintjs/icons" "^5.12.0" + "@popperjs/core" "^2.11.8" + classnames "^2.3.1" + normalize.css "^8.0.1" + react-popper "^2.3.0" + react-transition-group "^4.4.5" + react-uid "^2.3.3" + tslib "~2.6.2" + use-sync-external-store "^1.2.0" -"@es-joy/jsdoccomment@~0.31.0": - version "0.31.0" - resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz#dbc342cc38eb6878c12727985e693eaef34302bc" - integrity sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ== +"@blueprintjs/icons@^5.12.0": + version "5.12.0" + resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-5.12.0.tgz#02040336b1c08c0a1123dd2a27007d98a1d7a9d8" + integrity sha512-S80N2kJ0lwPFpWfYgFSxr2KEXcaNRcyOgAo2a+juwu47Mv0YUMdbeQNPPP2WkLc0387ZsvN/w5yz1rez6wyAsQ== dependencies: - comment-parser "1.3.1" - esquery "^1.4.0" - jsdoc-type-pratt-parser "~3.1.0" + change-case "^4.1.2" + classnames "^2.3.1" + tslib "~2.6.2" "@esbuild/android-arm64@0.18.20": version "0.18.20" @@ -458,14 +450,6 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -"@hypnosphi/create-react-context@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@hypnosphi/create-react-context/-/create-react-context-0.3.1.tgz#f8bfebdc7665f5d426cba3753e0e9c7d3154d7c6" - integrity sha512-V1klUed202XahrWJLLOT3EXNeCpFHCcJntdFGI15ntCwau+jfT386w7OFTMaCqOgXUH1fa0w/I1oZs+i/Rfr0A== - dependencies: - gud "^1.0.0" - warning "^4.0.3" - "@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" @@ -552,11 +536,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@juggle/resize-observer@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.3.1.tgz#b50a781709c81e10701004214340f25475a171a0" - integrity sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw== - "@mapbox/jsonlint-lines-primitives@~2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz#ce56e539f83552b58d10d672ea4d6fc9adc7b234" @@ -591,6 +570,11 @@ resolved "https://registry.yarnpkg.com/@petamoriken/float16/-/float16-3.6.3.tgz#7ed8f2ae05ea4096f0ccdf2c2655d04aca545d33" integrity sha512-Yx6Z93kmz3JVPYoPPRFJXnt2/G4kfaxRROcZVVHsE4zOClJXvkOVidv/JfvP6hWn16lykbKYKVzUsId6mqXdGg== +"@popperjs/core@^2.11.8": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== + "@puppeteer/browsers@1.4.3": version "1.4.3" resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.4.3.tgz#39bfd8bf999d707ed2914b036fa2febac2960985" @@ -679,11 +663,6 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.5.tgz#ae69bcbb1bebb68c4ac0b11e9d8ed04526b3562b" integrity sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng== -"@types/dom4@^2.0.1": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/dom4/-/dom4-2.0.2.tgz#6495303f049689ce936ed328a3e5ede9c51408ee" - integrity sha512-Rt4IC1T7xkCWa0OG1oSsPa0iqnxlDeQqKXZAHrQGLb7wFGncWm85MaxKUjAGejOrUynOgWlFi4c6S6IyJwoK4g== - "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" @@ -1220,10 +1199,10 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== -classnames@^2.2: - version "2.3.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== +classnames@^2.3.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== cliui@^7.0.2: version "7.0.4" @@ -1274,11 +1253,6 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -comment-parser@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b" - integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA== - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1417,18 +1391,6 @@ deep-eql@^4.1.3: dependencies: type-detect "^4.0.0" -deep-equal@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" - integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== - dependencies: - is-arguments "^1.0.4" - is-date-object "^1.0.1" - is-regex "^1.0.4" - object-is "^1.0.1" - object-keys "^1.1.1" - regexp.prototype.flags "^1.2.0" - deep-equal@^2.0.5: version "2.2.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.1.tgz#c72ab22f3a7d3503a4ca87dde976fe9978816739" @@ -1536,11 +1498,6 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" -dom4@^2.1.5: - version "2.1.6" - resolved "https://registry.yarnpkg.com/dom4/-/dom4-2.1.6.tgz#c90df07134aa0dbd81ed4d6ba1237b36fc164770" - integrity sha512-JkCVGnN4ofKGbjf5Uvc8mmxaATIErKQKSgACdBXpsQ3fY6DlIpAyWfiBSrGkttATssbDCp3psiAKWXk5gmjycA== - domexception@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" @@ -1769,19 +1726,6 @@ eslint-plugin-import@^2.25.3: resolve "^1.22.0" tsconfig-paths "^3.14.1" -eslint-plugin-jsdoc@^39.3.2: - version "39.3.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.2.tgz#b9c3becdbd860a75b8bd07bd04a0eaaad7c79403" - integrity sha512-RSGN94RYzIJS/WfW3l6cXzRLfJWxvJgNQZ4w0WCaxJWDJMigtwTsILEAfKqmmPkT2rwMH/s3C7G5ChDE6cwPJg== - dependencies: - "@es-joy/jsdoccomment" "~0.31.0" - comment-parser "1.3.1" - debug "^4.3.4" - escape-string-regexp "^4.0.0" - esquery "^1.4.0" - semver "^7.3.7" - spdx-expression-parse "^3.0.1" - eslint-plugin-jsx-a11y@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" @@ -2221,11 +2165,6 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -gud@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" - integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== - happy-dom@^9.20.3: version "9.20.3" resolved "https://registry.yarnpkg.com/happy-dom/-/happy-dom-9.20.3.tgz#4b097e889b33ef553d1c62b25a797ff05f7528e3" @@ -2418,7 +2357,7 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== -is-arguments@^1.0.4, is-arguments@^1.1.1: +is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== @@ -2530,7 +2469,7 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-regex@^1.0.4, is-regex@^1.1.4: +is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -2700,11 +2639,6 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsdoc-type-pratt-parser@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz#a4a56bdc6e82e5865ffd9febc5b1a227ff28e67e" - integrity sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw== - jsdom@^22.1.0: version "22.1.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-22.1.0.tgz#0fca6d1a37fbeb7f4aac93d1090d782c56b611c8" @@ -3076,7 +3010,7 @@ object-inspect@^1.12.0, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== -object-is@^1.0.1, object-is@^1.1.5: +object-is@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== @@ -3385,11 +3319,6 @@ pkg-types@^1.0.3: mlly "^1.2.0" pathe "^1.1.0" -popper.js@^1.14.4, popper.js@^1.16.1: - version "1.16.1" - resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" - integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== - postcss@^8.4.27: version "8.4.29" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" @@ -3432,7 +3361,7 @@ progress@2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.8.1: +prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -3539,6 +3468,11 @@ react-dom@^18.2.0: loose-envify "^1.1.0" scheduler "^0.23.0" +react-fast-compare@^3.0.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" + integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== + react-is@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -3554,17 +3488,12 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-popper@^1.3.7: - version "1.3.11" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.11.tgz#a2cc3f0a67b75b66cfa62d2c409f9dd1fcc71ffd" - integrity sha512-VSA/bS+pSndSF2fiasHK/PTEEAyOpX60+H5EPAjoArr8JGm+oihu4UbrqcEBpQibJxBVCpYyjAX7abJ+7DoYVg== - dependencies: - "@babel/runtime" "^7.1.2" - "@hypnosphi/create-react-context" "^0.3.1" - deep-equal "^1.1.1" - popper.js "^1.14.4" - prop-types "^15.6.1" - typed-styles "^0.0.7" +react-popper@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba" + integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q== + dependencies: + react-fast-compare "^3.0.1" warning "^4.0.2" react-refresh@^0.14.0: @@ -3572,16 +3501,23 @@ react-refresh@^0.14.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== -react-transition-group@^4.4.1: - version "4.4.2" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" - integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== +react-transition-group@^4.4.5: + version "4.4.5" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" + integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== dependencies: "@babel/runtime" "^7.5.5" dom-helpers "^5.0.1" loose-envify "^1.4.0" prop-types "^15.6.2" +react-uid@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/react-uid/-/react-uid-2.3.3.tgz#6a485ccc868555997f3506c6db97a3e735d97adf" + integrity sha512-iNpDovcb9qBpBTo8iUgqRSQOS8GV3bWoNaTaUptHkXtAooXSo0OWe7vN6TqqB8x3x0bNBbQx96kkmSltQ5h9kQ== + dependencies: + tslib "^2.0.0" + react@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" @@ -3607,7 +3543,7 @@ regenerator-runtime@^0.13.4: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: +regexp.prototype.flags@^1.4.1, regexp.prototype.flags@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== @@ -3722,13 +3658,6 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.7: - version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" - integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== - dependencies: - lru-cache "^6.0.0" - sentence-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" @@ -3832,24 +3761,6 @@ source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" - integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== - stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -4074,6 +3985,11 @@ tsconfig-paths@^3.14.1: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@^2.0.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + tslib@^2.0.1: version "2.6.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" @@ -4084,10 +4000,10 @@ tslib@^2.0.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== +tslib@~2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -4113,11 +4029,6 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -typed-styles@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" - integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== - ufo@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.1.2.tgz#d0d9e0fa09dece0c31ffd57bd363f030a35cfe76" @@ -4188,6 +4099,11 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +use-sync-external-store@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9" + integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" @@ -4290,7 +4206,7 @@ w3c-xmlserializer@^4.0.0: dependencies: xml-name-validator "^4.0.0" -warning@^4.0.2, warning@^4.0.3: +warning@^4.0.2: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== From 1171f4a9d142c6e01f4ad842bd192605a3d214b8 Mon Sep 17 00:00:00 2001 From: davemfish Date: Thu, 5 Sep 2024 08:42:02 -0400 Subject: [PATCH 10/26] different behavior for start button when a study area already exists. #113 --- frontend/src/App.jsx | 5 ++++- frontend/src/edit/studyAreaTable.jsx | 2 +- frontend/src/map/map.jsx | 1 + frontend/src/map/parcelControl.jsx | 2 -- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index fe0fb7d..c9c9cec 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -70,7 +70,9 @@ export default function App() { }; const startBuilding = () => { - setStart((start) => start + 1); + if (!studyArea.parcels.length) { + setStart((start) => start + 1); + } setActiveTab('scenarios'); }; @@ -98,6 +100,7 @@ export default function App() { area.parcels.length > 0 )); if (areas.length) { + setActiveTab('scenarios'); setSavedStudyAreas(areas); await switchStudyArea(areas[0].id); // TODO: switch to most recently created } else { diff --git a/frontend/src/edit/studyAreaTable.jsx b/frontend/src/edit/studyAreaTable.jsx index 6d45bb7..619dd20 100644 --- a/frontend/src/edit/studyAreaTable.jsx +++ b/frontend/src/edit/studyAreaTable.jsx @@ -57,7 +57,7 @@ export default function StudyAreaTable(props) {