From 896353d3ec28da6f9fba915bb6f05a2dd808acc6 Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Thu, 17 Feb 2022 15:17:47 +0100 Subject: [PATCH 1/5] feat: Show filters in right panel for maps --- app/charts/chart-config-ui-options.ts | 4 ++-- app/charts/map/map-state.tsx | 10 +++++++++- app/configurator/map/map-chart-options.tsx | 23 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/app/charts/chart-config-ui-options.ts b/app/charts/chart-config-ui-options.ts index 8c0996c24..8ddb187c6 100644 --- a/app/charts/chart-config-ui-options.ts +++ b/app/charts/chart-config-ui-options.ts @@ -285,13 +285,13 @@ export const chartConfigOptionsUISpec: ChartSpecs = { field: "areaLayer", optional: false, values: ["Measure"], - filters: false, + filters: true, }, { field: "symbolLayer", optional: false, values: ["Measure"], - filters: false, + filters: true, }, ], interactiveFilters: [], diff --git a/app/charts/map/map-state.tsx b/app/charts/map/map-state.tsx index f68e12f60..714d70676 100644 --- a/app/charts/map/map-state.tsx +++ b/app/charts/map/map-state.tsx @@ -31,6 +31,7 @@ import { GeoData, GeoFeature, GeoShapes, + isGeoCoordinatesDimension, isGeoShapesDimension, Observation, } from "../../domain/data"; @@ -173,13 +174,20 @@ const useMapState = ({ // Right now hierarchies are only created for geoShapes if (isGeoShapesDimension(dimension) && geoShapes) { + const dimensionLabels = dimension.values.map((d) => d.label); const hierarchyLabels = ( (geoShapes as any).topology.objects.shapes.geometries as GeoFeature[] ) .filter((d) => d.properties.hierarchyLevel === hierarchyLevel) .map((d) => d.properties.label); - return data.filter((d) => hierarchyLabels.includes(getLabel(d))); + return data + .filter((d) => dimensionLabels.includes(getLabel(d))) + .filter((d) => hierarchyLabels.includes(getLabel(d))); + } else if (isGeoCoordinatesDimension(dimension)) { + const dimensionLabels = dimension.values.map((d) => d.label); + + return data.filter((d) => dimensionLabels.includes(getLabel(d))); } return data; diff --git a/app/configurator/map/map-chart-options.tsx b/app/configurator/map/map-chart-options.tsx index bbf2f5ab7..fbe35f374 100644 --- a/app/configurator/map/map-chart-options.tsx +++ b/app/configurator/map/map-chart-options.tsx @@ -23,6 +23,7 @@ import { ChartOptionSelectField, ColorPickerField, } from "../components/field"; +import { DimensionValuesMultiFilter } from "../components/filters"; export const MapColumnOptions = ({ state, @@ -331,6 +332,18 @@ export const AreaLayerSettings = memo( )} + {!isHidden && ( + + Filter + + + + + )} ); } @@ -444,6 +457,16 @@ export const SymbolLayerSettings = memo( /> + + Filter + + + + ); } From 37b1836a89464a1dc5354feca276e3b48786e9c8 Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Thu, 17 Feb 2022 15:27:25 +0100 Subject: [PATCH 2/5] fix: Bounding box zoom for no points --- app/charts/map/helpers.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/charts/map/helpers.ts b/app/charts/map/helpers.ts index 7564e247f..6593bec20 100644 --- a/app/charts/map/helpers.ts +++ b/app/charts/map/helpers.ts @@ -18,13 +18,16 @@ export const getBBox = ( const visiblePoints = symbols.filter( (d) => d.properties.observation !== undefined ); - const [minLng, maxLng] = extent(visiblePoints, (d) => d.coordinates[0]); - const [minLat, maxLat] = extent(visiblePoints, (d) => d.coordinates[1]); - symbolsBbox = [ - [minLng, minLat], - [maxLng, maxLat], - ] as BBox; + if (visiblePoints.length > 0) { + const [minLng, maxLng] = extent(visiblePoints, (d) => d.coordinates[0]); + const [minLat, maxLat] = extent(visiblePoints, (d) => d.coordinates[1]); + + symbolsBbox = [ + [minLng, minLat], + [maxLng, maxLat], + ] as BBox; + } } if (shapesBbox !== undefined) { From f612fb2fa2f119657e3473a1e4a0e8dccb98e803 Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Thu, 17 Feb 2022 16:04:51 +0100 Subject: [PATCH 3/5] refactor: Remove redundant filtering --- app/charts/map/map-state.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/charts/map/map-state.tsx b/app/charts/map/map-state.tsx index 529aafd17..9499f86bd 100644 --- a/app/charts/map/map-state.tsx +++ b/app/charts/map/map-state.tsx @@ -173,20 +173,15 @@ const useMapState = ({ // Right now hierarchies are only created for geoShapes if (isGeoShapesDimension(dimension) && geoShapes) { - const dimensionLabels = dimension.values.map((d) => d.label); const hierarchyLabels = ( (geoShapes as any).topology.objects.shapes.geometries as GeoFeature[] ) .filter((d) => d.properties.hierarchyLevel === hierarchyLevel) .map((d) => d.properties.label); - return data - .filter((d) => dimensionLabels.includes(getLabel(d))) - .filter((d) => hierarchyLabels.includes(getLabel(d))); + return data.filter((d) => hierarchyLabels.includes(getLabel(d))); } else if (isGeoCoordinatesDimension(dimension)) { - const dimensionLabels = dimension.values.map((d) => d.label); - - return data.filter((d) => dimensionLabels.includes(getLabel(d))); + return data; } return data; From 0cf6f227a22412aba7a23c79c330a0ff7e6de279 Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Thu, 17 Feb 2022 16:06:56 +0100 Subject: [PATCH 4/5] feat: Add an option to hide shapes --- app/charts/map/chart-map.tsx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/app/charts/map/chart-map.tsx b/app/charts/map/chart-map.tsx index bc533c2d1..88fd5b132 100644 --- a/app/charts/map/chart-map.tsx +++ b/app/charts/map/chart-map.tsx @@ -97,13 +97,28 @@ export const ChartMapVisualization = ({ const dimension = dimensions?.find((d) => d.iri === areaDimensionIri); if (isGeoShapesDimension(dimension) && geoShapes && observations) { - const { topology } = geoShapes; + const activeFilters = chartConfig.filters[areaDimensionIri]; + const activeFiltersIris = activeFilters + ? activeFilters.type === "single" + ? [activeFilters.value] + : activeFilters.type === "multi" + ? Object.keys(activeFilters.values) + : undefined + : undefined; + const { topology } = geoShapes; const topojson = topojsonFeature( topology, topology.objects.shapes ) as AreaLayer["shapes"]; + // Completely hide unselected shapes (so they don't affect the legend, etc) + if (activeFiltersIris) { + topojson.features = topojson.features.filter((d) => + activeFiltersIris.includes(d.properties.iri) + ); + } + topojson.features.forEach((d: GeoFeature) => { // Should we match by labels? const observation = observations.find( @@ -118,7 +133,13 @@ export const ChartMapVisualization = ({ mesh: topojsonMesh(topology, topology.objects.shapes), }; } - }, [areaDimensionIri, dimensions, observations, geoShapes]); + }, [ + areaDimensionIri, + dimensions, + chartConfig.filters, + observations, + geoShapes, + ]); const symbolLayer: SymbolLayer | undefined = useMemo(() => { const dimension = dimensions?.find((d) => d.iri === symbolDimensionIri); From 52dd62988e0efdfa519e347d72b89bdf1bc0d804 Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Thu, 17 Feb 2022 17:05:56 +0100 Subject: [PATCH 5/5] feat: Remove redundant geoShapes passing to mapState --- app/charts/map/chart-map.tsx | 7 ------- app/charts/map/map-state.tsx | 30 +++++++----------------------- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/app/charts/map/chart-map.tsx b/app/charts/map/chart-map.tsx index 88fd5b132..553f9ae96 100644 --- a/app/charts/map/chart-map.tsx +++ b/app/charts/map/chart-map.tsx @@ -185,7 +185,6 @@ export const ChartMapVisualization = ({ measures={measures} dimensions={dimensions} baseLayer={chartConfig.baseLayer} - geoShapes={geoShapes} /> ); } else if (fetching) { @@ -204,7 +203,6 @@ export const ChartMapPrototype = ({ measures, dimensions, baseLayer, - geoShapes, }: { observations: Observation[]; features: GeoData; @@ -212,7 +210,6 @@ export const ChartMapPrototype = ({ measures: DimensionMetaDataFragment[]; dimensions: DimensionMetaDataFragment[]; baseLayer: BaseLayer; - geoShapes?: GeoShapes; }) => { return ( @@ -223,7 +220,6 @@ export const ChartMapPrototype = ({ measures={measures} dimensions={dimensions} baseLayer={baseLayer} - geoShapes={geoShapes} /> ); @@ -237,7 +233,6 @@ export const ChartMap = memo( measures, dimensions, baseLayer, - geoShapes, }: { features: GeoData; observations: Observation[]; @@ -245,7 +240,6 @@ export const ChartMap = memo( dimensions: DimensionMetaDataFragment[]; fields: MapFields; baseLayer: BaseLayer; - geoShapes?: GeoShapes; }) => { return ( diff --git a/app/charts/map/map-state.tsx b/app/charts/map/map-state.tsx index 9499f86bd..c17e72345 100644 --- a/app/charts/map/map-state.tsx +++ b/app/charts/map/map-state.tsx @@ -27,14 +27,7 @@ import { MapFields, SequentialPaletteType, } from "../../configurator/config-types"; -import { - GeoData, - GeoFeature, - GeoShapes, - isGeoCoordinatesDimension, - isGeoShapesDimension, - Observation, -} from "../../domain/data"; +import { GeoData, isGeoShapesDimension, Observation } from "../../domain/data"; import { useOptionalNumericVariable, useStringVariable, @@ -143,12 +136,10 @@ const useMapState = ({ measures, dimensions, baseLayer, - geoShapes, }: Pick & { features: GeoData; fields: MapFields; baseLayer: BaseLayer; - geoShapes?: GeoShapes; }): MapState => { const width = useWidth(); const { areaLayer, symbolLayer } = fields; @@ -172,21 +163,20 @@ const useMapState = ({ const dimension = dimensions.find((d) => d.iri === geoDimensionIri); // Right now hierarchies are only created for geoShapes - if (isGeoShapesDimension(dimension) && geoShapes) { - const hierarchyLabels = ( - (geoShapes as any).topology.objects.shapes.geometries as GeoFeature[] - ) + if ( + isGeoShapesDimension(dimension) && + features.areaLayer?.shapes?.features + ) { + const hierarchyLabels = features.areaLayer.shapes.features .filter((d) => d.properties.hierarchyLevel === hierarchyLevel) .map((d) => d.properties.label); return data.filter((d) => hierarchyLabels.includes(getLabel(d))); - } else if (isGeoCoordinatesDimension(dimension)) { - return data; } return data; }, - [data, dimensions, geoShapes] + [data, dimensions, features.areaLayer?.shapes.features] ); const areaData = useMemo( @@ -320,14 +310,12 @@ const MapChartProvider = ({ measures, dimensions, baseLayer, - geoShapes, children, }: Pick & { features: GeoData; children: ReactNode; fields: MapFields; baseLayer: BaseLayer; - geoShapes?: GeoShapes; }) => { const state = useMapState({ data, @@ -336,7 +324,6 @@ const MapChartProvider = ({ measures, dimensions, baseLayer, - geoShapes, }); return ( {children} @@ -350,13 +337,11 @@ export const MapChart = ({ measures, dimensions, baseLayer, - geoShapes, children, }: Pick & { features: GeoData; fields: MapFields; baseLayer: BaseLayer; - geoShapes?: GeoShapes; children: ReactNode; }) => { return ( @@ -369,7 +354,6 @@ export const MapChart = ({ fields={fields} measures={measures} dimensions={dimensions} - geoShapes={geoShapes} baseLayer={baseLayer} > {children}