From e8413647d0e12263afffd102030928646b4f4439 Mon Sep 17 00:00:00 2001 From: dgboss Date: Wed, 10 Jul 2024 11:58:45 -0700 Subject: [PATCH] Dynamic highlighting of selected fire zone unit (#3772) --- .../features/fba/components/map/FBAMap.tsx | 36 +++++---- .../fba/components/map/featureStylers.ts | 76 ++++++++++++++----- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/web/src/features/fba/components/map/FBAMap.tsx b/web/src/features/fba/components/map/FBAMap.tsx index 5a061083f..ef8a39fa1 100644 --- a/web/src/features/fba/components/map/FBAMap.tsx +++ b/web/src/features/fba/components/map/FBAMap.tsx @@ -22,6 +22,7 @@ import { fireCentreStyler, fireCentreLabelStyler, fireShapeStyler, + fireShapeHighlightStyler, fireShapeLabelStyler, stationStyler, hfiStyler, @@ -95,9 +96,7 @@ const FBAMap = (props: FBAMapProps) => { .find(l => l.getProperties()?.name === layerName) if (layerName === 'fireShapeVector') { - fireShapeVTL.setStyle( - fireShapeStyler(cloneDeep(props.fireShapeAreas), props.advisoryThreshold, props.selectedFireShape, isVisible) - ) + fireShapeVTL.setStyle(fireShapeStyler(cloneDeep(props.fireShapeAreas), props.advisoryThreshold, isVisible)) } else if (layer) { layer.setVisible(isVisible) } @@ -108,19 +107,26 @@ const FBAMap = (props: FBAMapProps) => { new VectorTileLayer({ source: fireCentreVectorSource, style: fireCentreStyler, - zIndex: 50 + zIndex: 49 }) ) const [fireShapeVTL] = useState( new VectorTileLayer({ source: fireShapeVectorSource, - style: fireShapeStyler( + style: fireShapeStyler(cloneDeep(props.fireShapeAreas), props.advisoryThreshold, showShapeStatus), + zIndex: 50, + properties: { name: 'fireShapeVector' } + }) + ) + const [fireShapeHighlightVTL] = useState( + new VectorTileLayer({ + source: fireShapeVectorSource, + style: fireShapeHighlightStyler( cloneDeep(props.fireShapeAreas), props.advisoryThreshold, - props.selectedFireShape, - showShapeStatus + props.selectedFireShape ), - zIndex: 49, + zIndex: 51, properties: { name: 'fireShapeVector' } }) ) @@ -199,16 +205,13 @@ const FBAMap = (props: FBAMapProps) => { useEffect(() => { if (!map) return - fireShapeVTL.setStyle( - fireShapeStyler( - cloneDeep(props.fireShapeAreas), - props.advisoryThreshold, - props.selectedFireShape, - showShapeStatus - ) - ) + fireShapeVTL.setStyle(fireShapeStyler(cloneDeep(props.fireShapeAreas), props.advisoryThreshold, showShapeStatus)) fireShapeLabelVTL.setStyle(fireShapeLabelStyler(props.selectedFireShape)) + fireShapeHighlightVTL.setStyle( + fireShapeHighlightStyler(cloneDeep(props.fireShapeAreas), props.advisoryThreshold, props.selectedFireShape) + ) fireShapeVTL.changed() + fireShapeHighlightVTL.changed() fireShapeLabelVTL.changed() // eslint-disable-next-line react-hooks/exhaustive-deps }, [props.selectedFireShape, props.fireShapeAreas, props.advisoryThreshold]) @@ -279,6 +282,7 @@ const FBAMap = (props: FBAMapProps) => { }), fireCentreVTL, fireShapeVTL, + fireShapeHighlightVTL, fireCentreLabelVTL, fireShapeLabelVTL ], diff --git a/web/src/features/fba/components/map/featureStylers.ts b/web/src/features/fba/components/map/featureStylers.ts index 535169df7..d0972f628 100644 --- a/web/src/features/fba/components/map/featureStylers.ts +++ b/web/src/features/fba/components/map/featureStylers.ts @@ -15,6 +15,12 @@ export const ADVISORY_RED_FILL = 'rgba(128, 0, 0, 0.4)' export const HFI_ADVISORY = 'rgba(255, 128, 0, 0.4)' export const HFI_WARNING = 'rgba(255, 0, 0, 0.4)' +enum FireShapeStatus { + NONE = 0, + ADVISORY = 1, + WARNING = 2 +} + const fireCentreTextStyler = (feature: RenderFeature | ol.Feature): Text => { const text = feature.get('mof_fire_centre_name').replace(' Fire Centre', '\nFire Centre') return new Text({ @@ -44,51 +50,87 @@ export const fireCentreStyler = (): Style => { export const fireShapeStyler = ( fireShapeAreas: FireShapeArea[], advisoryThreshold: number, - selectedFireShape: FireShape | undefined, showZoneStatus: boolean +) => { + const a = (feature: RenderFeature | ol.Feature): Style => { + const fire_shape_id = feature.getProperties().OBJECTID + const fireShapes = fireShapeAreas.filter(f => f.fire_shape_id === fire_shape_id) + const status = getFireShapeStatus(advisoryThreshold, fireShapes) + + return new Style({ + stroke: new Stroke({ + color: 'black', + width: 1 + }), + fill: showZoneStatus ? getAdvisoryFillColor(status) : new Fill({ color: EMPTY_FILL }) + }) + } + return a +} + +export const fireShapeHighlightStyler = ( + fireShapeAreas: FireShapeArea[], + advisoryThreshold: number, + selectedFireShape: FireShape | undefined ) => { const a = (feature: RenderFeature | ol.Feature): Style => { const fire_shape_id = feature.getProperties().OBJECTID const fireShapes = fireShapeAreas.filter(f => f.fire_shape_id === fire_shape_id) const selected = !!(selectedFireShape?.fire_shape_id && selectedFireShape.fire_shape_id === fire_shape_id) - let strokeValue = 'black' - if (selected) { - strokeValue = 'green' - } + const status = getFireShapeStatus(advisoryThreshold, fireShapes) return new Style({ stroke: new Stroke({ - color: strokeValue, - width: selected ? 8 : 1 + color: selected ? getFireShapeStrokeColor(status) : [0, 0, 0, 0], + width: selected ? 8 : 0 }), - fill: showZoneStatus ? getAdvisoryColors(advisoryThreshold, fireShapes) : new Fill({ color: EMPTY_FILL }) + fill: new Fill({ color: EMPTY_FILL }) }) } return a } -export const getAdvisoryColors = (advisoryThreshold: number, fireShapeArea?: FireShapeArea[]) => { - let fill = new Fill({ color: EMPTY_FILL }) +const getFireShapeStatus = (advisoryThreshold: number, fireShapeArea?: FireShapeArea[]) => { if (isUndefined(fireShapeArea) || fireShapeArea.length === 0) { - return fill + return FireShapeStatus.NONE } - const advisoryThresholdArea = fireShapeArea.find(area => area.threshold == 1) const warningThresholdArea = fireShapeArea.find(area => area.threshold == 2) const advisoryPercentage = advisoryThresholdArea?.elevated_hfi_percentage ?? 0 const warningPercentage = warningThresholdArea?.elevated_hfi_percentage ?? 0 + let status = FireShapeStatus.NONE if (advisoryPercentage + warningPercentage > advisoryThreshold) { - // advisory color orange - fill = new Fill({ color: ADVISORY_ORANGE_FILL }) + status = FireShapeStatus.ADVISORY } if (warningPercentage > advisoryThreshold) { - // advisory color red - fill = new Fill({ color: ADVISORY_RED_FILL }) + status = FireShapeStatus.WARNING } - return fill + return status +} + +const getFireShapeStrokeColor = (fireShapeStatus: FireShapeStatus) => { + switch (fireShapeStatus) { + case FireShapeStatus.ADVISORY: + return '#db8701' + case FireShapeStatus.WARNING: + return [227, 0, 1, 0.99] + default: + return 'black' + } +} + +export const getAdvisoryFillColor = (fireShapeStatus: FireShapeStatus) => { + switch (fireShapeStatus) { + case FireShapeStatus.ADVISORY: + return new Fill({ color: ADVISORY_ORANGE_FILL }) + case FireShapeStatus.WARNING: + return new Fill({ color: ADVISORY_RED_FILL }) + default: + return new Fill({ color: EMPTY_FILL }) + } } export const fireShapeLabelStyler = (selectedFireShape: FireShape | undefined) => {