diff --git a/src/lib/browse/CensusOutputAreaLayerControl.svelte b/src/lib/browse/CensusOutputAreaLayerControl.svelte index 5a4418379..f4a59a515 100644 --- a/src/lib/browse/CensusOutputAreaLayerControl.svelte +++ b/src/lib/browse/CensusOutputAreaLayerControl.svelte @@ -2,6 +2,7 @@ import type { MapGeoJSONFeature } from "maplibre-gl"; import { hoveredToggle, + makeColorRamp, overwriteLineLayer, overwritePmtilesSource, overwritePolygonLayer, @@ -32,7 +33,11 @@ colorBy = ""; } if (colorBy) { - $map.setPaintProperty(name, "fill-color", makeColorRamp()); + $map.setPaintProperty( + name, + "fill-color", + makeColorRamp(["get", colorBy], makeLimits(), colorScale) + ); // InteractiveLayer manages the polygon layer, but we also need to control the outline $map.setLayoutProperty(outlineLayer, "visibility", "visible"); } else { @@ -105,20 +110,6 @@ return [0, 4700, 13000, 33000, 94000, 1980000]; } } - - function makeColorRamp(): any[] { - let limits = makeLimits(); - let fillColor: any[] = ["step", ["get", colorBy]]; - for (let i = 1; i < limits.length; i++) { - fillColor.push(colorScale[i - 1]); - fillColor.push(limits[i]); - } - // Repeat the last color. The upper limit is exclusive, meaning a value - // exactly equal to it will use this fallback. For things like percentages, - // we want to set 100 as the cap. - fillColor.push(colorScale[colorScale.length - 1]); - return fillColor; - } {#if colorBy == "population_density"}

(people per square kilometres)

- + x.toLocaleString())} + /> {/if} + import type { MapGeoJSONFeature } from "maplibre-gl"; + import { + hoveredToggle, + makeColorRamp, + overwriteLineLayer, + overwritePmtilesSource, + overwritePolygonLayer, + } from "../../maplibre_helpers"; + import { map } from "../../stores"; + import { ExternalLink, HelpButton, InteractiveLayer } from "../common"; + import { Checkbox } from "../govuk"; + import { colors } from "./colors"; + import SequentialLegend from "./SequentialLegend.svelte"; + + let name = "imd"; + let outlineLayer = `${name}-outline`; + + let colorScale = colors.sequential_low_to_high; + // The deciles are [1, 10]. The 5 colors cover two each. + let limits = [0, 2, 4, 6, 8, 10]; + + overwritePmtilesSource( + $map, + name, + `https://atip.uk/layers/v1/${name}.pmtiles` + ); + + overwritePolygonLayer($map, { + id: name, + source: name, + sourceLayer: name, + // Decile 1 is the most deprived, but we want to invert for the color scale + color: makeColorRamp(["-", 10, ["get", "decile"]], limits, colorScale), + opacity: hoveredToggle(0.5, 0.7), + }); + overwriteLineLayer($map, { + id: outlineLayer, + source: name, + sourceLayer: name, + color: "black", + width: 0.5, + }); + + let show = false; + // InteractiveLayer manages the polygon layer, but we also need to control the outline + $: { + if ($map.getLayer(outlineLayer)) { + $map.setLayoutProperty( + outlineLayer, + "visibility", + show ? "visible" : "none" + ); + } + } + + function tooltip(feature: MapGeoJSONFeature): string { + return ( + `

${feature.properties.LSOA11CD} has an IMD score of ${feature.properties.score}

` + + `

Rank: ${feature.properties.rank.toLocaleString()} / 32,844 LSOAs

` + ); + } + + + + Indices of Multiple Deprivation + + +

+ The 2019 English IMD scores come from + DLUCH GIS + . Note the LSOAs identified are from the 2011 census. A + detailed breakdown of the score across different categories can be found + here + . +

+

+ License: + Open Government License + . Contains OS data © Crown copyright and database + right 2023. +

+
+
+
+{#if show} + +{/if} + + diff --git a/src/lib/browse/SequentialLegend.svelte b/src/lib/browse/SequentialLegend.svelte index 6e0c4776f..b5ec78089 100644 --- a/src/lib/browse/SequentialLegend.svelte +++ b/src/lib/browse/SequentialLegend.svelte @@ -1,6 +1,6 @@
@@ -12,6 +12,6 @@
{#each limits as limit} - {limit.toLocaleString()} + {limit} {/each}
diff --git a/src/maplibre_helpers.ts b/src/maplibre_helpers.ts index 53da378ae..6def46bf9 100644 --- a/src/maplibre_helpers.ts +++ b/src/maplibre_helpers.ts @@ -257,6 +257,24 @@ export function hoveredToggle( ] as DataDrivenPropertyValueSpecification; } +// Helper for https://maplibre.org/maplibre-style-spec/expressions/#step. +export function makeColorRamp( + input: DataDrivenPropertyValueSpecification, + limits: number[], + colorScale: string[] +): DataDrivenPropertyValueSpecification { + let step: any[] = ["step", input]; + for (let i = 1; i < limits.length; i++) { + step.push(colorScale[i - 1]); + step.push(limits[i]); + } + // Repeat the last color. The upper limit is exclusive, meaning a value + // exactly equal to it will use this fallback. For things like percentages, + // we want to set 100 as the cap. + step.push(colorScale[colorScale.length - 1]); + return step as DataDrivenPropertyValueSpecification; +} + // Suitable for passing to map.fitBounds. Work around https://github.com/Turfjs/turf/issues/1807. export function bbox(gj: GeoJSON): [number, number, number, number] { return turfBbox(gj) as [number, number, number, number]; @@ -291,6 +309,8 @@ const layerZorder = [ "local_planning_authorities-outline", "census_output_areas", "census_output_areas-outline", + "imd", + "imd-outline", // Then smaller optional layers on top "schools", "hospitals", diff --git a/src/pages/BrowseSchemes.svelte b/src/pages/BrowseSchemes.svelte index a0ab83e94..802a0a1f5 100644 --- a/src/pages/BrowseSchemes.svelte +++ b/src/pages/BrowseSchemes.svelte @@ -10,6 +10,7 @@ import { processInput, type Scheme } from "../lib/browse/data"; import Filters from "../lib/browse/Filters.svelte"; import HospitalsLayerControl from "../lib/browse/HospitalsLayerControl.svelte"; + import ImdLayerControl from "../lib/browse/ImdLayerControl.svelte"; import LocalAuthorityDistrictsLayerControl from "../lib/browse/LocalAuthorityDistrictsLayerControl.svelte"; import LocalPlanningAuthoritiesLayerControl from "../lib/browse/LocalPlanningAuthoritiesLayerControl.svelte"; import MrnLayerControl from "../lib/browse/MrnLayerControl.svelte"; @@ -179,6 +180,7 @@ +