Rewrite map with hooks, add map colour toggle
Map and Legend components rewritten using hooks. Also, each category can now have multiple available colour scales. These can be switched using a select dropdown in the legend.
This commit is contained in:
parent
d3a17f2e5f
commit
a4d1afab81
@ -446,6 +446,68 @@
|
||||
<LineSymbolizer stroke="#888" stroke-width="3.0"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Style name="community_local_significance_total">
|
||||
<Rule>
|
||||
<Filter>[community_local_significance_total] >= 100</Filter>
|
||||
<PolygonSymbolizer fill="#bd0026" />
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[community_local_significance_total] >= 50 and [community_local_significance_total] < 100</Filter>
|
||||
<PolygonSymbolizer fill="#e31a1c" />
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[community_local_significance_total] >= 20 and [community_local_significance_total] < 50</Filter>
|
||||
<PolygonSymbolizer fill="#fc4e2a" />
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[community_local_significance_total] >= 10 and [community_local_significance_total] < 20</Filter>
|
||||
<PolygonSymbolizer fill="#fd8d3c" />
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[community_local_significance_total] >= 3 and [community_local_significance_total] < 10</Filter>
|
||||
<PolygonSymbolizer fill="#feb24c" />
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[community_local_significance_total] = 2</Filter>
|
||||
<PolygonSymbolizer fill="#fed976" />
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[community_local_significance_total] = 1</Filter>
|
||||
<PolygonSymbolizer fill="#ffe8a9" />
|
||||
</Rule>
|
||||
|
||||
<Rule>
|
||||
<MaxScaleDenominator>17061</MaxScaleDenominator>
|
||||
<MinScaleDenominator>4264</MinScaleDenominator>
|
||||
<LineSymbolizer stroke="#888" stroke-width="1.0"/>
|
||||
</Rule>
|
||||
<Rule>
|
||||
<MaxScaleDenominator>4264</MaxScaleDenominator>
|
||||
<MinScaleDenominator>0</MinScaleDenominator>
|
||||
<LineSymbolizer stroke="#888" stroke-width="3.0"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Style name="community_in_public_ownership">
|
||||
<Rule>
|
||||
<Filter>[in_public_ownership] = true</Filter>
|
||||
<PolygonSymbolizer fill="#1166ff" />
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[in_public_ownership] = false</Filter>
|
||||
<PolygonSymbolizer fill="#ffaaa0" />
|
||||
</Rule>
|
||||
|
||||
<Rule>
|
||||
<MaxScaleDenominator>17061</MaxScaleDenominator>
|
||||
<MinScaleDenominator>4264</MinScaleDenominator>
|
||||
<LineSymbolizer stroke="#888" stroke-width="1.0"/>
|
||||
</Rule>
|
||||
<Rule>
|
||||
<MaxScaleDenominator>4264</MaxScaleDenominator>
|
||||
<MinScaleDenominator>0</MinScaleDenominator>
|
||||
<LineSymbolizer stroke="#888" stroke-width="3.0"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Style name="landuse">
|
||||
<Rule>
|
||||
<Filter>[current_landuse_order] = "Agriculture And Fisheries"</Filter>
|
||||
|
@ -23,8 +23,8 @@ export interface CategoryMapDefinition {
|
||||
|
||||
export const defaultMapCategory = Category.Age;
|
||||
|
||||
export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
[Category.Age]: {
|
||||
export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition[]} = {
|
||||
[Category.Age]: [{
|
||||
mapStyle: 'date_year',
|
||||
legend: {
|
||||
title: 'Age',
|
||||
@ -46,8 +46,8 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
{ color: '#d0c291', text: '<1700' },
|
||||
]
|
||||
},
|
||||
},
|
||||
[Category.Size]: {
|
||||
}],
|
||||
[Category.Size]: [{
|
||||
mapStyle: 'size_height',
|
||||
legend: {
|
||||
title: 'Height to apex',
|
||||
@ -62,15 +62,15 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
{ color: '#980043', text: '≥152'}
|
||||
]
|
||||
},
|
||||
},
|
||||
[Category.Team]: {
|
||||
}],
|
||||
[Category.Team]: [{
|
||||
mapStyle: undefined,
|
||||
legend: {
|
||||
title: 'Team',
|
||||
elements: []
|
||||
},
|
||||
},
|
||||
[Category.Construction]: {
|
||||
}],
|
||||
[Category.Construction]: [{
|
||||
mapStyle: 'construction_core_material',
|
||||
legend: {
|
||||
title: 'Construction',
|
||||
@ -85,8 +85,8 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
{ color: "#c48a85", text: "Other Man-Made Material" }
|
||||
]
|
||||
},
|
||||
},
|
||||
[Category.Location]: {
|
||||
}],
|
||||
[Category.Location]: [{
|
||||
mapStyle: 'location',
|
||||
legend: {
|
||||
title: 'Location',
|
||||
@ -99,8 +99,9 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
{ color: '#bae4bc', text: '<20%' }
|
||||
]
|
||||
},
|
||||
},
|
||||
[Category.Community]: {
|
||||
}],
|
||||
[Category.Community]: [
|
||||
{
|
||||
mapStyle: 'likes',
|
||||
legend: {
|
||||
title: 'Like Me',
|
||||
@ -115,7 +116,35 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
]
|
||||
}
|
||||
},
|
||||
[Category.Planning]: {
|
||||
{
|
||||
mapStyle: 'community_local_significance_total',
|
||||
legend: {
|
||||
title: 'Local Significance',
|
||||
description: 'People who think the building should be locally listed',
|
||||
elements: [
|
||||
{ color: '#bd0026', text: '100+' },
|
||||
{ color: '#e31a1c', text: '50–99' },
|
||||
{ color: '#fc4e2a', text: '20–49' },
|
||||
{ color: '#fd8d3c', text: '10–19' },
|
||||
{ color: '#feb24c', text: '3–9' },
|
||||
{ color: '#fed976', text: '2' },
|
||||
{ color: '#ffe8a9', text: '1'}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
mapStyle: 'community_in_public_ownership',
|
||||
legend: {
|
||||
title: 'Public Ownership',
|
||||
description: 'Is the building in some form of public/community ownership',
|
||||
elements: [
|
||||
{color: '#1166ff', text: 'Yes'},
|
||||
{color: '#ffaaa0', text: 'No'}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
[Category.Planning]: [{
|
||||
mapStyle: 'planning_combined',
|
||||
legend: {
|
||||
title: 'Statutory protections',
|
||||
@ -128,8 +157,8 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
{ color: '#858ed4', text: 'Locally listed'},
|
||||
]
|
||||
},
|
||||
},
|
||||
[Category.Sustainability]: {
|
||||
}],
|
||||
[Category.Sustainability]: [{
|
||||
mapStyle: 'sust_dec',
|
||||
legend: {
|
||||
title: 'Sustainability',
|
||||
@ -144,8 +173,8 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
{ color: "#e31d23", text: 'G' },
|
||||
]
|
||||
},
|
||||
},
|
||||
[Category.Type]: {
|
||||
}],
|
||||
[Category.Type]: [{
|
||||
mapStyle: 'building_attachment_form',
|
||||
legend: {
|
||||
title: 'Type',
|
||||
@ -156,8 +185,8 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
{ color: "#226291", text: "Mid-Terrace" }
|
||||
]
|
||||
},
|
||||
},
|
||||
[Category.LandUse]: {
|
||||
}],
|
||||
[Category.LandUse]: [{
|
||||
mapStyle: 'landuse',
|
||||
legend: {
|
||||
title: 'Land Use',
|
||||
@ -177,15 +206,15 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
{ color: '#ffffff', text: 'Vacant & Derelict' }
|
||||
]
|
||||
},
|
||||
},
|
||||
[Category.Streetscape]: {
|
||||
}],
|
||||
[Category.Streetscape]: [{
|
||||
mapStyle: undefined,
|
||||
legend: {
|
||||
title: 'Streetscape',
|
||||
elements: []
|
||||
},
|
||||
},
|
||||
[Category.Dynamics]: {
|
||||
}],
|
||||
[Category.Dynamics]: [{
|
||||
mapStyle: 'dynamics_demolished_count',
|
||||
legend: {
|
||||
title: 'Dynamics',
|
||||
@ -218,6 +247,6 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition} = {
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
}]
|
||||
|
||||
};
|
||||
|
@ -8,6 +8,8 @@ export type BuildingMapTileset = 'date_year' |
|
||||
'construction_core_material' |
|
||||
'location' |
|
||||
'likes' |
|
||||
'community_local_significance_total' |
|
||||
'community_in_public_ownership' |
|
||||
'planning_combined' |
|
||||
'sust_dec' |
|
||||
'building_attachment_form' |
|
||||
|
@ -35,7 +35,7 @@ import { sendBuildingUpdate } from './api-data/building-update';
|
||||
* to all modules that import leaflet or react-leaflet.
|
||||
*/
|
||||
const ColouringMap = loadable(
|
||||
() => import('./map/map'),
|
||||
async () => (await import('./map/map')).ColouringMap,
|
||||
{ ssr: false }
|
||||
);
|
||||
|
||||
|
@ -56,6 +56,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.map-legend .style-select {
|
||||
background-color: inherit;
|
||||
padding: 0.5rem 0.25rem;
|
||||
margin: 0.25rem 0.5rem;
|
||||
width: auto;
|
||||
font-size: 18px;
|
||||
border: 1px solid;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.map-legend .h4,
|
||||
.map-legend p,
|
||||
.data-legend {
|
||||
|
@ -1,72 +1,76 @@
|
||||
import React from 'react';
|
||||
import React, { FC, useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import './legend.css';
|
||||
|
||||
import { DownIcon, UpIcon } from '../components/icons';
|
||||
import { Logo } from '../components/logo';
|
||||
import { LegendConfig } from '../config/category-maps-config';
|
||||
import { CategoryMapDefinition, LegendConfig } from '../config/category-maps-config';
|
||||
import { BuildingMapTileset } from '../config/tileserver-config';
|
||||
|
||||
interface LegendProps {
|
||||
legendConfig: LegendConfig;
|
||||
mapColourScaleDefinitions: CategoryMapDefinition[];
|
||||
mapColourScale: BuildingMapTileset;
|
||||
onMapColourScale: (x: BuildingMapTileset) => void;
|
||||
}
|
||||
|
||||
interface LegendState {
|
||||
collapseList: boolean;
|
||||
}
|
||||
export const Legend : FC<LegendProps> = ({
|
||||
mapColourScaleDefinitions,
|
||||
mapColourScale,
|
||||
onMapColourScale
|
||||
}) => {
|
||||
const [collapseList, setCollapseList] = useState(false);
|
||||
|
||||
class Legend extends React.Component<LegendProps, LegendState> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {collapseList: false};
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.onResize= this.onResize.bind(this);
|
||||
}
|
||||
const handleToggle = useCallback(() => {
|
||||
setCollapseList(!collapseList);
|
||||
}, [collapseList]);
|
||||
|
||||
const onResize = useCallback(({target}) => {
|
||||
setCollapseList((target.outerHeight < 670 || target.outerWidth < 768))
|
||||
}, []);
|
||||
|
||||
handleClick() {
|
||||
this.setState(state => ({
|
||||
collapseList: !state.collapseList
|
||||
}));
|
||||
}
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', onResize);
|
||||
|
||||
if(window?.outerHeight) {
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('resize', this.onResize);
|
||||
if (window && window.outerHeight) {
|
||||
// if we're in the browser, pass in as though from event to initialise
|
||||
this.onResize({target: window});
|
||||
}
|
||||
onResize({target: window});
|
||||
}
|
||||
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.onResize);
|
||||
return () => {
|
||||
window.removeEventListener('resize', onResize);
|
||||
}
|
||||
}, [onResize]);
|
||||
|
||||
const legendConfig = mapColourScaleDefinitions.find(def => def.mapStyle === mapColourScale)?.legend;
|
||||
|
||||
|
||||
onResize(e) {
|
||||
this.setState({collapseList: (e.target.outerHeight < 670 || e.target.outerWidth < 768)}); // magic number needs to be consistent with CSS expander-button media query
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
title = undefined,
|
||||
elements = [],
|
||||
description = undefined,
|
||||
disclaimer = undefined
|
||||
} = this.props.legendConfig ?? {};
|
||||
} = legendConfig ?? {};
|
||||
|
||||
return (
|
||||
<div className="map-legend">
|
||||
<Logo variant="default" />
|
||||
{
|
||||
mapColourScaleDefinitions.length > 1 ?
|
||||
<select className='style-select' onChange={e => onMapColourScale(e.target.value as BuildingMapTileset)}>
|
||||
{
|
||||
mapColourScaleDefinitions.map(def =>
|
||||
<option key={def.mapStyle} value={def.mapStyle}>{def.legend.title}</option>
|
||||
)
|
||||
}
|
||||
</select> :
|
||||
title && <h4 className="h4">{title}</h4>
|
||||
}
|
||||
{
|
||||
elements.length > 0 &&
|
||||
<button className="expander-button btn btn-outline-secondary btn-sm" type="button" onClick={this.handleClick} >
|
||||
<button className="expander-button btn btn-outline-secondary btn-sm" type="button" onClick={handleToggle} >
|
||||
{
|
||||
this.state.collapseList ?
|
||||
collapseList ?
|
||||
<UpIcon /> :
|
||||
<DownIcon />
|
||||
}
|
||||
@ -78,7 +82,7 @@ class Legend extends React.Component<LegendProps, LegendState> {
|
||||
{
|
||||
elements.length === 0 ?
|
||||
<p className="data-intro">Coming soon…</p> :
|
||||
<ul className={this.state.collapseList ? 'collapse data-legend' : 'data-legend'} >
|
||||
<ul className={collapseList ? 'collapse data-legend' : 'data-legend'} >
|
||||
{
|
||||
disclaimer && <p className='legend-disclaimer'>{disclaimer}</p>
|
||||
}
|
||||
@ -108,9 +112,4 @@ class Legend extends React.Component<LegendProps, LegendState> {
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Legend;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { Component, Fragment, useEffect } from 'react';
|
||||
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { AttributionControl, MapContainer, ZoomControl, useMapEvent, Pane, useMap } from 'react-leaflet';
|
||||
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
@ -18,9 +18,10 @@ import { BuildingDataLayer } from './layers/building-data-layer';
|
||||
import { BuildingNumbersLayer } from './layers/building-numbers-layer';
|
||||
import { BuildingHighlightLayer } from './layers/building-highlight-layer';
|
||||
|
||||
import Legend from './legend';
|
||||
import { Legend } from './legend';
|
||||
import SearchBox from './search-box';
|
||||
import ThemeSwitcher from './theme-switcher';
|
||||
import { BuildingMapTileset } from '../config/tileserver-config';
|
||||
|
||||
interface ColouringMapProps {
|
||||
selectedBuildingId: number;
|
||||
@ -30,56 +31,58 @@ interface ColouringMapProps {
|
||||
onBuildingAction: (building: Building) => void;
|
||||
}
|
||||
|
||||
interface ColouringMapState {
|
||||
theme: MapTheme;
|
||||
position: [number, number];
|
||||
zoom: number;
|
||||
}
|
||||
export const ColouringMap : FC<ColouringMapProps> = ({
|
||||
category,
|
||||
mode,
|
||||
revisionId,
|
||||
onBuildingAction,
|
||||
selectedBuildingId,
|
||||
children
|
||||
}) => {
|
||||
|
||||
/**
|
||||
* Map area
|
||||
*/
|
||||
class ColouringMap extends Component<ColouringMapProps, ColouringMapState> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
theme: 'light',
|
||||
...initialMapViewport
|
||||
};
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleLocate = this.handleLocate.bind(this);
|
||||
this.themeSwitch = this.themeSwitch.bind(this);
|
||||
}
|
||||
const [theme, setTheme] = useState<MapTheme>('light');
|
||||
const [position, setPosition] = useState(initialMapViewport.position);
|
||||
const [zoom, setZoom] = useState(initialMapViewport.zoom);
|
||||
|
||||
handleLocate(lat: number, lng: number, zoom: number){
|
||||
this.setState({
|
||||
position: [lat, lng],
|
||||
zoom: zoom
|
||||
});
|
||||
}
|
||||
const [mapColourScale, setMapColourScale] = useState<BuildingMapTileset>();
|
||||
|
||||
handleClick(e) {
|
||||
const handleLocate = useCallback(
|
||||
(lat: number, lng: number, zoom: number) => {
|
||||
setPosition([lat, lng]);
|
||||
setZoom(zoom);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const handleClick = useCallback(
|
||||
async (e) => {
|
||||
const {lat, lng} = e.latlng;
|
||||
apiGet(`/api/buildings/locate?lat=${lat}&lng=${lng}`)
|
||||
.then(data => {
|
||||
const data = await apiGet(`/api/buildings/locate?lat=${lat}&lng=${lng}`);
|
||||
const building = data?.[0];
|
||||
this.props.onBuildingAction(building);
|
||||
}).catch(err => console.error(err));
|
||||
}
|
||||
onBuildingAction(building);
|
||||
},
|
||||
[onBuildingAction],
|
||||
)
|
||||
|
||||
themeSwitch(e) {
|
||||
const themeSwitch = useCallback(
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
const newTheme = (this.state.theme === 'light')? 'night' : 'light';
|
||||
this.setState({theme: newTheme});
|
||||
const newTheme = (theme === 'light')? 'night' : 'light';
|
||||
setTheme(newTheme);
|
||||
},
|
||||
[theme],
|
||||
)
|
||||
|
||||
const categoryMapDefinitions = useMemo(() => categoryMapsConfig[category], [category]);
|
||||
|
||||
useEffect(() => {
|
||||
if(!categoryMapDefinitions.some(def => def.mapStyle === mapColourScale)) {
|
||||
setMapColourScale(categoryMapDefinitions[0].mapStyle);
|
||||
}
|
||||
}, [categoryMapDefinitions, mapColourScale]);
|
||||
|
||||
render() {
|
||||
const categoryMapDefinition = categoryMapsConfig[this.props.category];
|
||||
|
||||
const tileset = categoryMapDefinition.mapStyle;
|
||||
|
||||
const hasSelection = this.props.selectedBuildingId != undefined;
|
||||
const isEdit = ['edit', 'multi-edit'].includes(this.props.mode);
|
||||
const hasSelection = selectedBuildingId != undefined;
|
||||
const isEdit = ['edit', 'multi-edit'].includes(mode);
|
||||
|
||||
return (
|
||||
<div className="map-container">
|
||||
@ -92,24 +95,24 @@ class ColouringMap extends Component<ColouringMapProps, ColouringMapState> {
|
||||
zoomControl={false}
|
||||
attributionControl={false}
|
||||
>
|
||||
<ClickHandler onClick={this.handleClick} />
|
||||
<MapBackgroundColor theme={this.state.theme} />
|
||||
<MapViewport position={this.state.position} zoom={this.state.zoom} />
|
||||
<ClickHandler onClick={handleClick} />
|
||||
<MapBackgroundColor theme={theme} />
|
||||
<MapViewport position={position} zoom={zoom} />
|
||||
|
||||
<Pane
|
||||
key={this.state.theme}
|
||||
key={theme}
|
||||
name={'cc-base-pane'}
|
||||
style={{zIndex: 50}}
|
||||
>
|
||||
<CityBaseMapLayer theme={this.state.theme} />
|
||||
<BuildingBaseLayer theme={this.state.theme} />
|
||||
<CityBaseMapLayer theme={theme} />
|
||||
<BuildingBaseLayer theme={theme} />
|
||||
</Pane>
|
||||
|
||||
{
|
||||
tileset &&
|
||||
mapColourScale &&
|
||||
<BuildingDataLayer
|
||||
tileset={tileset}
|
||||
revisionId={this.props.revisionId}
|
||||
tileset={mapColourScale}
|
||||
revisionId={revisionId}
|
||||
/>
|
||||
}
|
||||
|
||||
@ -118,12 +121,12 @@ class ColouringMap extends Component<ColouringMapProps, ColouringMapState> {
|
||||
style={{zIndex: 300}}
|
||||
>
|
||||
<CityBoundaryLayer />
|
||||
<BuildingNumbersLayer revisionId={this.props.revisionId} />
|
||||
<BuildingNumbersLayer revisionId={revisionId} />
|
||||
{
|
||||
this.props.selectedBuildingId &&
|
||||
selectedBuildingId &&
|
||||
<BuildingHighlightLayer
|
||||
selectedBuildingId={this.props.selectedBuildingId}
|
||||
baseTileset={tileset}
|
||||
selectedBuildingId={selectedBuildingId}
|
||||
baseTileset={mapColourScale}
|
||||
/>
|
||||
}
|
||||
</Pane>
|
||||
@ -132,23 +135,22 @@ class ColouringMap extends Component<ColouringMapProps, ColouringMapState> {
|
||||
<AttributionControl prefix=""/>
|
||||
</MapContainer>
|
||||
{
|
||||
this.props.mode !== 'basic' &&
|
||||
<Fragment>
|
||||
mode !== 'basic' &&
|
||||
<>
|
||||
{
|
||||
!hasSelection &&
|
||||
<div className="map-notice">
|
||||
<HelpIcon /> {isEdit ? 'Click a building to edit' : 'Click a building for details'}
|
||||
</div>
|
||||
}
|
||||
<Legend legendConfig={categoryMapDefinition?.legend} />
|
||||
{/* <ThemeSwitcher onSubmit={this.themeSwitch} currentTheme={this.state.theme} /> */}
|
||||
<SearchBox onLocate={this.handleLocate} />
|
||||
</Fragment>
|
||||
<Legend mapColourScaleDefinitions={categoryMapDefinitions} mapColourScale={mapColourScale} onMapColourScale={setMapColourScale}/>
|
||||
{/* <ThemeSwitcher onSubmit={this.themeSwitch} currentTheme={theme} /> */}
|
||||
<SearchBox onLocate={handleLocate} />
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function ClickHandler({ onClick }: {onClick: (e) => void}) {
|
||||
useMapEvent('click', (e) => onClick(e));
|
||||
@ -180,5 +182,3 @@ function MapViewport({
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default ColouringMap;
|
||||
|
@ -84,6 +84,27 @@ const LAYER_QUERIES = {
|
||||
buildings
|
||||
WHERE
|
||||
likes_total > 0`,
|
||||
community_local_significance_total: `
|
||||
SELECT
|
||||
geometry_id,
|
||||
community_local_significance_total
|
||||
FROM
|
||||
buildings
|
||||
WHERE
|
||||
community_local_significance_total > 0
|
||||
`,
|
||||
community_in_public_ownership: `
|
||||
SELECT
|
||||
geometry_id,
|
||||
CASE
|
||||
WHEN community_public_ownership = 'Not in public/community ownership' THEN false
|
||||
ELSE true
|
||||
END AS in_public_ownership
|
||||
FROM
|
||||
buildings
|
||||
WHERE
|
||||
community_public_ownership IS NOT NULL
|
||||
`,
|
||||
planning_combined: `
|
||||
SELECT
|
||||
geometry_id,
|
||||
|
Loading…
Reference in New Issue
Block a user