Skip to content

Commit

Permalink
Merge pull request #168 from commonknowledge/feature/map-711-toggle-c…
Browse files Browse the repository at this point in the history
…horopleth-on-off

Allow choropleth to be toggled on and off
  • Loading branch information
janbaykara authored Dec 18, 2024
2 parents 2c77ff4 + 186db03 commit 83b3784
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ const PoliticalChoropleths: React.FC<PoliticalChoroplethsProps> = ({
boundaryType,
tileset,
}) => {
// Show the layer only if the report is set to show the boundary type
// Show the layer only if the report is set to show the boundary type and the VisualisationType is choropleth
const visibility =
report.displayOptions?.dataVisualisation?.boundaryType === boundaryType
report.displayOptions?.dataVisualisation?.boundaryType === boundaryType &&
report.displayOptions?.dataVisualisation?.showDataVisualisation?.choropleth
? 'visible'
: 'none'

Expand All @@ -43,12 +44,6 @@ const PoliticalChoropleths: React.FC<PoliticalChoroplethsProps> = ({
const [selectedBoundary, setSelectedBoundary] = useAtom(selectedBoundaryAtom)
useClickOnBoundaryEvents(visibility === 'visible' ? tileset : null)

useEffect(() => {
if (visibility === 'none') {
setSelectedBoundary(null)
}
}, [visibility])

// When the map is loaded and we have the data, add the data to the boundaries
useEffect(() => {
if (map.loaded && dataByBoundary) {
Expand Down Expand Up @@ -79,16 +74,19 @@ const PoliticalChoropleths: React.FC<PoliticalChoroplethsProps> = ({
promoteId={tileset.promoteId}
>
{/* Fill of the boundary */}
<Layer
beforeId="road-simple"
id={`${tileset.mapboxSourceId}-fill`}
source={tileset.mapboxSourceId}
source-layer={tileset.sourceLayerId}
type="fill"
filter={getChoroplethFillFilter(dataByBoundary, tileset)}
paint={getChoroplethFill(dataByBoundary, visibility === 'visible')}
//layout={{ visibility: delayedVisibility }}
/>

<>
<Layer
beforeId="road-simple"
id={`${tileset.mapboxSourceId}-fill`}
source={tileset.mapboxSourceId}
source-layer={tileset.sourceLayerId}
type="fill"
filter={getChoroplethFillFilter(dataByBoundary, tileset)}
paint={getChoroplethFill(dataByBoundary, visibility === 'visible')}
/>
</>

{/* Border of the boundary */}
<Layer
beforeId={PLACEHOLDER_LAYER_ID_CHOROPLETH}
Expand All @@ -111,7 +109,11 @@ const PoliticalChoropleths: React.FC<PoliticalChoroplethsProps> = ({
type="line"
paint={getSelectedChoroplethEdge()}
filter={['==', ['get', tileset.promoteId], selectedBoundary]}
layout={{ visibility, 'line-join': 'round', 'line-round-limit': 0.1 }}
layout={{
visibility,
'line-join': 'round',
'line-round-limit': 0.1,
}}
/>
</Source>
<Source
Expand All @@ -131,10 +133,8 @@ const PoliticalChoropleths: React.FC<PoliticalChoroplethsProps> = ({
'interpolate',
['exponential', 1],
['zoom'],
//
7.5,
0,
//
7.8,
1,
],
Expand All @@ -156,10 +156,8 @@ const PoliticalChoropleths: React.FC<PoliticalChoroplethsProps> = ({
'interpolate',
['exponential', 1],
['zoom'],
//
7.5,
0,
//
7.8,
1,
],
Expand Down
266 changes: 148 additions & 118 deletions nextjs/src/app/reports/[id]/(components)/ReportVisualisation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ import {
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { Switch } from '@/components/ui/switch'
import { startCase } from 'lodash'
import React from 'react'
import { VisualisationType } from '../reportContext'
import React, { useState } from 'react'
import { VisualisationLabels, VisualisationType } from '../reportContext'
import useDataByBoundary from '../useDataByBoundary'
import CollapsibleSection from './CollapsibleSection'
import { UpdateConfigProps } from './ReportConfiguration'
import { useReport } from './ReportProvider'

const ReportVisualisation: React.FC<UpdateConfigProps> = ({
updateVisualisationConfig,
}) => {
const { report } = useReport()
const { report, updateReport } = useReport()
const {
layers,
politicalBoundaries,
Expand All @@ -31,136 +31,166 @@ const ReportVisualisation: React.FC<UpdateConfigProps> = ({
boundaryType: dataVisualisation?.boundaryType,
})

const visualisationType = dataVisualisation?.visualisationType
const [checkedTypes, setCheckedTypes] = useState<Record<string, boolean>>(
() =>
Object.values(VisualisationType).reduce(
(acc, type) => ({
...acc,
[type]: type === dataVisualisation?.visualisationType,
}),
{}
)
)

const handleSwitchChange = (type: VisualisationType, checked: boolean) => {
setCheckedTypes((prev) => ({
...prev,
[type]: checked,
}))

updateReport({
displayOptions: {
...report.displayOptions,
dataVisualisation: {
...report.displayOptions.dataVisualisation,
showDataVisualisation: {
...Object.values(VisualisationType).reduce(
(acc, visType) => {
acc[visType] =
report.displayOptions.dataVisualisation
?.showDataVisualisation?.[visType] ?? false
return acc
},
{} as Record<VisualisationType, boolean>
),
[type]: checked,
},
visualisationType: checked ? type : undefined,
},
},
})
}
const dataSourceId = dataVisualisation?.dataSource
const dataSourceField = dataVisualisation?.dataSourceField
const selectedDataSource = layers.find((layer) => layer.id === dataSourceId)
const selectedBoundaryLabel = politicalBoundaries.find(
(boundary) => boundary.boundaryType === dataVisualisation?.boundaryType
)?.label

const isLoading = !fieldNames || fieldNames.length === 0

return (
<CollapsibleSection id="report-visualisation" title="Data Visualisation">
<div className="flex flex-col gap-3">
<div>
<Select
onValueChange={(type) =>
updateVisualisationConfig({
visualisationType: type as VisualisationType,
})
}
value={visualisationType}
>
<Label
htmlFor="select-vis-type"
className="text-white text-sm font-medium"
>
Type
</Label>
<SelectTrigger
id="select-vis-type"
disabled
className="w-full border-meepGray-100 text-meepGray-100 mt-2 font-medium"
>
<SelectValue />
</SelectTrigger>
<SelectContent>
{Object.values(VisualisationType).map((type) => (
<SelectItem className="font-medium" key={type} value={type}>
{startCase(type)}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="text-meepGray-400 text-sm font-normal mb-3 mt-3">
Colour shading by category
</p>
</div>

{report.layers.length && (
<div>
<Select
onValueChange={(type) =>
updateVisualisationConfig({
dataSource: type as MapLayer['id'],
})
}
value={dataSourceId}
>
<div className="text-white text-sm font-medium">Type</div>
<div className="flex flex-col gap-2">
{Object.values(VisualisationType).map((type) => (
<div key={type} className="flex items-center space-x-2 mt-2">
<Switch
id={`switch-${type}`}
checked={checkedTypes[type]}
onCheckedChange={(checked) => handleSwitchChange(type, checked)}
/>
<Label
htmlFor="select-vis-type"
className="text-white text-sm font-medium"
htmlFor={`switch-${type}`}
>
Colour by
{startCase(type)}
</Label>
<SelectTrigger
id="select-vis-type"
className="w-full border-meepGray-100 text-meepGray-100 mt-2 font-medium"
>
<SelectValue />
</SelectTrigger>
<SelectContent>
{layers.map((layer) => (
<SelectItem
className="font-medium"
key={layer.id}
value={layer.id}
>
{startCase(layer.name)}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="text-meepGray-400 text-sm font-normal mb-3 mt-3">
Select which data will populate your {selectedBoundaryLabel}
</p>
</div>
)}
{selectedDataSource?.source.dataType === 'AREA_STATS' && (
<div>
<Select
onValueChange={(type) =>
updateVisualisationConfig({
dataSourceField: type as MapLayer['id'],
})
}
value={dataSourceField}
defaultOpen={!dataSourceField}
required
disabled={isLoading}
>
<Label
htmlFor="select-vis-type"
className="text-white text-sm font-medium"
>
Select data field
</Label>
<SelectTrigger
id="select-vis-type"
className="w-full border-meepGray-100 text-meepGray-100 mt-2 font-medium flex items-center"
>
{isLoading ? <LoadingIcon size={'18'} /> : <SelectValue />}
</SelectTrigger>
{!isLoading && (
<SelectContent>
{fieldNames.map((field) => (
<SelectItem
className="font-medium"
key={field}
value={field}
>
{field}
</SelectItem>
))}
</SelectContent>
{VisualisationLabels[type] && (
<span className="text-meepGray-400 text-xs ml-2">
{VisualisationLabels[type]}
</span>
)}
</Select>
<p className="text-meepGray-400 text-sm font-normal mb-3 mt-3">
Select the field from your data source
</p>
</div>
</div>
))}
</div>
{checkedTypes['choropleth'] && (
<>
{report.layers.length && (
<div>
<Select
onValueChange={(type) =>
updateVisualisationConfig({
dataSource: type as MapLayer['id'],
})
}
value={dataSourceId}
>
<Label
htmlFor="select-vis-type"
className="text-white text-sm font-medium"
>
Colour by
</Label>
<SelectTrigger
id="select-vis-type"
className="w-full border-meepGray-100 text-meepGray-100 mt-2 font-medium"
>
<SelectValue />
</SelectTrigger>
<SelectContent>
{layers.map((layer) => (
<SelectItem
className="font-medium"
key={layer.id}
value={layer.id}
>
{startCase(layer.name)}
</SelectItem>
))}
</SelectContent>
</Select>
<p className="text-meepGray-400 text-sm font-normal mb-3 mt-3">
Select which data will populate your {selectedBoundaryLabel}
</p>
</div>
)}

{selectedDataSource?.source.dataType === 'AREA_STATS' && (
<div>
<Select
onValueChange={(type) =>
updateVisualisationConfig({
dataSourceField: type as MapLayer['id'],
})
}
value={dataSourceField}
defaultOpen={!dataSourceField}
required
disabled={isLoading}
>
<Label
htmlFor="select-vis-type"
className="text-white text-sm font-medium"
>
Select data field
</Label>
<SelectTrigger
id="select-vis-type"
className="w-full border-meepGray-100 text-meepGray-100 mt-2 font-medium flex items-center"
>
{isLoading ? <LoadingIcon size={'18'} /> : <SelectValue />}
</SelectTrigger>
{!isLoading && (
<SelectContent>
{fieldNames.map((field) => (
<SelectItem
className="font-medium"
key={field}
value={field}
>
{field}
</SelectItem>
))}
</SelectContent>
)}
</Select>
<p className="text-meepGray-400 text-sm font-normal mb-3 mt-3">
Select the field from your data source
</p>
</div>
)}
</>
)}
</div>
</CollapsibleSection>
Expand Down
Loading

0 comments on commit 83b3784

Please sign in to comment.