Merge pull request #1061 from matkoniecz/feature/various-tweaks

Various tweaks discovered during testing of new layer
This commit is contained in:
Mike Simpson 2023-01-19 14:34:47 +00:00 committed by GitHub
commit 69b49a4e81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 150 additions and 133 deletions

View File

@ -361,8 +361,6 @@
<LineSymbolizer stroke="#888" stroke-width="3.0"/> <LineSymbolizer stroke="#888" stroke-width="3.0"/>
</Rule> </Rule>
</Style> </Style>
<Style name="empty_map">
</Style>
<Style name="conservation_area"> <Style name="conservation_area">
<Rule> <Rule>
<PolygonSymbolizer fill="#73ebaf" /> <PolygonSymbolizer fill="#73ebaf" />

View File

@ -60,7 +60,7 @@ function ShowIfAvailable(data) {
} }
const LinkIfAvailable = (link) => { const LinkIfAvailable = (link) => {
return <>{link ? <a href={link.toString()}>{link.toString()}</a> : MissingData }</> return <>{link ? <a href={link.toString()} target="_blank">{link.toString()}</a> : MissingData }</>
} }
const StatusInfo = ({status, statusBeforeAliasing}) => { const StatusInfo = ({status, statusBeforeAliasing}) => {

View File

@ -57,9 +57,9 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
e.preventDefault(); e.preventDefault();
props.onMapColourScale('planning_combined') props.onMapColourScale('planning_combined')
} }
const switchToEmptyMapStyle = (e) => { const switchToAllPlanningApplicationsMapStyle = (e) => {
e.preventDefault(); e.preventDefault();
props.onMapColourScale('empty_map') props.onMapColourScale('planning_applications_status_all')
} }
const { flood, floodSwitchOnClick, housing, housingSwitchOnClick, creative, creativeSwitchOnClick, vista, vistaSwitchOnClick, parcel, parcelSwitchOnClick, conservation, conservationSwitchOnClick } = useDisplayPreferences(); const { flood, floodSwitchOnClick, housing, housingSwitchOnClick, creative, creativeSwitchOnClick, vista, vistaSwitchOnClick, parcel, parcelSwitchOnClick, conservation, conservationSwitchOnClick } = useDisplayPreferences();
const communityLinkUrl = `/${props.mode}/${Category.Community}/${props.building.building_id}`; const communityLinkUrl = `/${props.mode}/${Category.Community}/${props.building.building_id}`;
@ -110,8 +110,8 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
{'Click here to view possible locations of future applications'} {'Click here to view possible locations of future applications'}
</button> </button>
: :
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={switchToEmptyMapStyle}> <button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={switchToAllPlanningApplicationsMapStyle}>
{'Click here to hide possible locations of future applications'} {'Click to see planning applications'}
</button> </button>
} }
<UserOpinionEntry <UserOpinionEntry
@ -140,7 +140,7 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
slug="planning_live_application" slug="planning_live_application"
value={null} value={null}
disabled={true} disabled={true}
tooltip={"GLA official description: \"All areas with more than a 1 in 1,000 annual probability of either river or sea flooding.\""} tooltip={"the GLA official description: \"All areas with more than a 1 in 1,000 annual probability of either river or sea flooding.\""}
/> />
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={floodSwitchOnClick}> <button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={floodSwitchOnClick}>
{(flood === 'enabled')? 'Click to hide Flood Zones' : 'Click to see Flood Zones mapped'} {(flood === 'enabled')? 'Click to hide Flood Zones' : 'Click to see Flood Zones mapped'}
@ -150,7 +150,7 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
slug="planning_live_application" slug="planning_live_application"
value={null} value={null}
disabled={true} disabled={true}
tooltip={"GLA official description: \"Housing zones are areas funded by the Mayor and government to attract developers and relevant partners to build new homes.\""} tooltip={"the GLA official description: \"Housing zones are areas funded by the Mayor and government to attract developers and relevant partners to build new homes.\""}
/> />
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={housingSwitchOnClick}> <button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={housingSwitchOnClick}>
{(housing === 'enabled')? 'Click to hide Housing Zones' : 'Click to see Housing Zones mapped'} {(housing === 'enabled')? 'Click to hide Housing Zones' : 'Click to see Housing Zones mapped'}
@ -206,12 +206,12 @@ const PlanningView: React.FunctionComponent<CategoryViewProps> = (props) => {
{'Click to see individual protected buildings mapped'} {'Click to see individual protected buildings mapped'}
</button> </button>
: :
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={switchToEmptyMapStyle}> <button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={switchToAllPlanningApplicationsMapStyle}>
{'Click to hide individual protected buildings on map'} {'Click to see planning applications'}
</button> </button>
} }
<button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={conservationSwitchOnClick}> <button className="map-switcher-inline btn btn-outline btn-outline-dark" onClick={conservationSwitchOnClick}>
{(conservation === 'enabled')? 'Click to hide Convervation Areas' : 'Click to see Convervation Areas'} {(conservation === 'enabled')? 'Click to hide Conservation Areas' : 'Click to see Conservation Areas'}
</button> </button>
<NumericDataEntryWithFormattedLink <NumericDataEntryWithFormattedLink
title={dataFields.planning_list_id.title} title={dataFields.planning_list_id.title}

View File

@ -189,8 +189,8 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition[]} =
{ {
mapStyle: 'planning_applications_status_recent', mapStyle: 'planning_applications_status_recent',
legend: { legend: {
title: 'Last 12 months - planning applications submissions/decisions (official data)', title: 'The last 12 months - planning applications submissions/decisions (official data)',
disclaimer: 'The map shows applications where the submission or decision data falls within last 12 months.', disclaimer: 'The map shows applications where the submission or decision data falls within the last 12 months.',
elements: [ elements: [
{ color: '#a040a0', text: 'Submitted, awaiting decision' }, { color: '#a040a0', text: 'Submitted, awaiting decision' },
{ color: '#fff200', text: 'Appeal In Progress' }, { color: '#fff200', text: 'Appeal In Progress' },
@ -248,15 +248,6 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition[]} =
{ color: '#8500d4', text: 'In Archaeological Priority Area'}, { color: '#8500d4', text: 'In Archaeological Priority Area'},
] ]
}, },
},
{
mapStyle: 'empty_map',
legend: {
title: 'Empty map',
disclaimer: 'This is an empty map to see overlays without distraction.',
elements: [
]
},
} }
], ],
[Category.Sustainability]: [{ [Category.Sustainability]: [{

View File

@ -15,7 +15,6 @@ export type BuildingMapTileset = 'date_year' |
'planning_applications_status_recent' | 'planning_applications_status_recent' |
'planning_applications_status_very_recent' | 'planning_applications_status_very_recent' |
'planning_combined' | 'planning_combined' |
'empty_map' |
'sust_dec' | 'sust_dec' |
'building_attachment_form' | 'building_attachment_form' |
'landuse' | 'landuse' |

View File

@ -3,8 +3,8 @@ import React, { createContext, useCallback, useContext, useEffect, useState } fr
import { LayerEnablementState, MapTheme } from './config/map-config'; import { LayerEnablementState, MapTheme } from './config/map-config';
interface DisplayPreferencesContextState { interface DisplayPreferencesContextState {
resetLayers: (e: React.FormEvent<HTMLFormElement>) => void; showOverlayList: (e: React.FormEvent<HTMLFormElement>) => void;
anyLayerModifiedState: () => boolean; resetLayersAndHideTheirList: (e: React.FormEvent<HTMLFormElement>) => void;
vista: LayerEnablementState; vista: LayerEnablementState;
vistaSwitch: (e: React.FormEvent<HTMLFormElement>) => void; vistaSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
@ -41,6 +41,10 @@ interface DisplayPreferencesContextState {
darkLightTheme: MapTheme; darkLightTheme: MapTheme;
darkLightThemeSwitch: (e: React.FormEvent<HTMLFormElement>) => void; darkLightThemeSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
darkLightThemeSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>; darkLightThemeSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
showLayerSelection: LayerEnablementState;
showLayerSelectionSwitch: (e: React.FormEvent<HTMLFormElement>) => void;
showLayerSelectionSwitchOnClick: React.MouseEventHandler<HTMLButtonElement>;
} }
const stub = (): never => { const stub = (): never => {
@ -48,8 +52,8 @@ const stub = (): never => {
}; };
export const DisplayPreferencesContext = createContext<DisplayPreferencesContextState>({ export const DisplayPreferencesContext = createContext<DisplayPreferencesContextState>({
resetLayers: stub, showOverlayList: stub,
anyLayerModifiedState: stub, resetLayersAndHideTheirList: stub,
vista: undefined, vista: undefined,
vistaSwitch: stub, vistaSwitch: stub,
@ -86,6 +90,10 @@ export const DisplayPreferencesContext = createContext<DisplayPreferencesContext
darkLightTheme: undefined, darkLightTheme: undefined,
darkLightThemeSwitch: stub, darkLightThemeSwitch: stub,
darkLightThemeSwitchOnClick: undefined, darkLightThemeSwitchOnClick: undefined,
showLayerSelection: undefined,
showLayerSelectionSwitch: stub,
showLayerSelectionSwitchOnClick: undefined,
}); });
const noop = () => {}; const noop = () => {};
@ -99,6 +107,7 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
const defaultParcel = 'disabled' const defaultParcel = 'disabled'
const defaultConservation = 'disabled' const defaultConservation = 'disabled'
const defaultHistoricData = 'disabled' const defaultHistoricData = 'disabled'
const defaultShowLayerSelection = 'disabled'
const [vista, setVista] = useState<LayerEnablementState>(defaultVista); const [vista, setVista] = useState<LayerEnablementState>(defaultVista);
const [flood, setFlood] = useState<LayerEnablementState>(defaultFlood); const [flood, setFlood] = useState<LayerEnablementState>(defaultFlood);
const [creative, setCreative] = useState<LayerEnablementState>(defaultCreative); const [creative, setCreative] = useState<LayerEnablementState>(defaultCreative);
@ -108,10 +117,17 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
const [conservation, setConservation] = useState<LayerEnablementState>(defaultConservation); const [conservation, setConservation] = useState<LayerEnablementState>(defaultConservation);
const [historicData, setHistoricData] = useState<LayerEnablementState>(defaultHistoricData); const [historicData, setHistoricData] = useState<LayerEnablementState>(defaultHistoricData);
const [darkLightTheme, setDarkLightTheme] = useState<MapTheme>('night'); const [darkLightTheme, setDarkLightTheme] = useState<MapTheme>('night');
const [showLayerSelection, setShowLayerSelection] = useState<LayerEnablementState>(defaultShowLayerSelection);
const resetLayers = useCallback( const showOverlayList = useCallback(
(e) => {
setShowLayerSelection('enabled')
},
[]
)
const resetLayersAndHideTheirList = useCallback(
(e) => { (e) => {
e.preventDefault();
setVista(defaultVista); setVista(defaultVista);
setFlood(defaultFlood); setFlood(defaultFlood);
setCreative(defaultCreative); setCreative(defaultCreative);
@ -120,8 +136,9 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
setParcel(defaultParcel); setParcel(defaultParcel);
setConservation(defaultConservation); setConservation(defaultConservation);
setHistoricData(defaultHistoricData); setHistoricData(defaultHistoricData);
setShowLayerSelection(defaultShowLayerSelection); // reset layers + hiding this panel is integrated into one action
//setDarkLightTheme('night'); // reset only layers //setDarkLightTheme('night'); // reset only layers
}, },
[] []
) )
@ -289,11 +306,26 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
setDarkLightTheme(newDarkLightTheme); setDarkLightTheme(newDarkLightTheme);
} }
const showLayerSelectionSwitch = useCallback(
(e) => {
flipShowLayerSelection(e)
},
[showLayerSelection],
)
const showLayerSelectionSwitchOnClick = (e) => {
flipShowLayerSelection(e)
}
function flipShowLayerSelection(e) {
e.preventDefault();
const newShowLayerSelection = (showLayerSelection === 'enabled')? 'disabled' : 'enabled';
setShowLayerSelection(newShowLayerSelection);
}
return ( return (
<DisplayPreferencesContext.Provider value={{ <DisplayPreferencesContext.Provider value={{
resetLayers, showOverlayList,
anyLayerModifiedState, resetLayersAndHideTheirList,
vista, vista,
vistaSwitch, vistaSwitch,
@ -324,7 +356,11 @@ export const DisplayPreferencesProvider: React.FC<{}> = ({children}) => {
darkLightTheme, darkLightTheme,
darkLightThemeSwitch, darkLightThemeSwitch,
darkLightThemeSwitchOnClick darkLightThemeSwitchOnClick,
showLayerSelection,
showLayerSelectionSwitch,
showLayerSelectionSwitchOnClick
}}> }}>
{children} {children}
</DisplayPreferencesContext.Provider> </DisplayPreferencesContext.Provider>

View File

@ -53,9 +53,14 @@ function getCurrentMenuLinks(username: string): MenuLink[][] {
to: "/data-extracts.html", to: "/data-extracts.html",
text: "Download data" text: "Download data"
}, },
{
to: "https://github.com/colouring-cities/manual/wiki",
text: "Open Manual - Wiki",
external: true
},
{ {
to: "https://github.com/colouring-london/colouring-london", to: "https://github.com/colouring-london/colouring-london",
text: "Access open code", text: "Open code",
external: true external: true
}, },
{ {
@ -68,7 +73,6 @@ function getCurrentMenuLinks(username: string): MenuLink[][] {
to: "/showcase.html", to: "/showcase.html",
text: "Case Study Showcase", text: "Case Study Showcase",
disabled: true, disabled: true,
note: "Not Yet Activated"
}, },
], ],
[ [

View File

@ -6,10 +6,10 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const BoroughSwitcher: React.FC<{}> = () => { export const BoroughSwitcher: React.FC<{}> = () => {
const { borough, boroughSwitch, darkLightTheme } = useDisplayPreferences(); const { borough, boroughSwitch, darkLightTheme } = useDisplayPreferences();
return ( return (
<form className={`borough-switcher map-button ${darkLightTheme}`} onSubmit={boroughSwitch}> <form className={`borough-switcher map-button ${borough}-state ${darkLightTheme}`} onSubmit={boroughSwitch}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(borough === 'enabled')? 'Switch off Borough Boundaries' : 'Switch on Borough Boundaries'} {(borough === 'enabled')? 'Borough Boundaries on' : 'Borough Boundaries off'}
</button> </button>
</form> </form>
); );

View File

@ -6,10 +6,10 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const ConservationAreaSwitcher: React.FC<{}> = (props) => { export const ConservationAreaSwitcher: React.FC<{}> = (props) => {
const { conservation, conservationSwitch, darkLightTheme } = useDisplayPreferences(); const { conservation, conservationSwitch, darkLightTheme } = useDisplayPreferences();
return ( return (
<form className={`conservation-switcher map-button ${darkLightTheme}`} onSubmit={conservationSwitch}> <form className={`conservation-switcher map-button ${conservation}-state ${darkLightTheme}`} onSubmit={conservationSwitch}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(conservation === 'enabled')? 'Switch off Conservation Areas' : 'Switch on Conservation Areas'} {(conservation === 'enabled')? 'Conservation Areas on' : 'Conservation Areas off'}
</button> </button>
</form> </form>
); );

View File

@ -6,10 +6,10 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const CreativeSwitcher: React.FC<{}> = () => { export const CreativeSwitcher: React.FC<{}> = () => {
const { creative, creativeSwitch, darkLightTheme } = useDisplayPreferences(); const { creative, creativeSwitch, darkLightTheme } = useDisplayPreferences();
return ( return (
<form className={`creative-switcher map-button ${darkLightTheme}`} onSubmit={creativeSwitch}> <form className={`creative-switcher map-button ${creative}-state ${darkLightTheme}`} onSubmit={creativeSwitch}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(creative === 'enabled')? 'Switch off Creative Enterprise Zones' : 'Switch on Creative Enterprise Zones'} {(creative === 'enabled')? 'Enterprise Zones on' : 'Creative Enterprise Zones off'}
</button> </button>
</form> </form>
); );

View File

@ -4,17 +4,23 @@ import './map-button.css';
import { useDisplayPreferences } from '../displayPreferences-context'; import { useDisplayPreferences } from '../displayPreferences-context';
interface DataLayerSwitcherProps { interface DataLayerSwitcherProps {
currentDisplay: string;
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
} }
const DataLayerSwitcher: React.FC<DataLayerSwitcherProps> = (props) => { const DataLayerSwitcher: React.FC<DataLayerSwitcherProps> = (props) => {
const { darkLightTheme } = useDisplayPreferences(); const { showLayerSelection, showOverlayList, resetLayersAndHideTheirList, darkLightTheme } = useDisplayPreferences();
const handleSubmit = (evt) => {
evt.preventDefault();
if (showLayerSelection === 'enabled') {
resetLayersAndHideTheirList(evt)
} else {
showOverlayList(evt)
}
}
return ( return (
<form className={`data-switcher map-button ${darkLightTheme}`} onSubmit={props.onSubmit}> <form className={`data-switcher map-button ${darkLightTheme}`} onSubmit={handleSubmit}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(props.currentDisplay === 'enabled')? 'Hide layer options' : 'Show layer options'} {(showLayerSelection === 'enabled')? 'Clear layer options' : 'Show layer options'}
</button> </button>
</form> </form>
); );

View File

@ -6,10 +6,10 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const FloodSwitcher: React.FC<{}> = () => { export const FloodSwitcher: React.FC<{}> = () => {
const { flood, floodSwitch, darkLightTheme } = useDisplayPreferences(); const { flood, floodSwitch, darkLightTheme } = useDisplayPreferences();
return ( return (
<form className={`flood-switcher map-button ${darkLightTheme}`} onSubmit={floodSwitch}> <form className={`flood-switcher map-button ${flood}-state ${darkLightTheme}`} onSubmit={floodSwitch}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(flood === 'enabled')? 'Switch off Flood Zones' : 'Switch on Flood Zones'} {(flood === 'enabled')? 'Flood Zones on' : 'Flood Zones of'}
</button> </button>
</form> </form>
); );

View File

@ -6,10 +6,10 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const HistoricDataSwitcher: React.FC<{}> = (props) => { export const HistoricDataSwitcher: React.FC<{}> = (props) => {
const { historicData, historicDataSwitch, darkLightTheme } = useDisplayPreferences(); const { historicData, historicDataSwitch, darkLightTheme } = useDisplayPreferences();
return ( return (
<form className={`historic-data-switcher map-button ${darkLightTheme}`} onSubmit={historicDataSwitch}> <form className={`historic-data-switcher map-button ${historicData}-state ${darkLightTheme}`} onSubmit={historicDataSwitch}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(historicData === 'enabled')? 'Switch off the OS 1890s Historical Map' : 'Switch on the OS 1890s Historical Map'} {(historicData === 'enabled')? 'The OS 1890s Historical Map on' : 'The OS 1890s Historical Map off'}
</button> </button>
</form> </form>
); );

View File

@ -6,10 +6,10 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const HousingSwitcher: React.FC<{}> = () => { export const HousingSwitcher: React.FC<{}> = () => {
const { housing, housingSwitch, darkLightTheme } = useDisplayPreferences(); const { housing, housingSwitch, darkLightTheme } = useDisplayPreferences();
return ( return (
<form className={`housing-switcher map-button ${darkLightTheme}`} onSubmit={housingSwitch}> <form className={`housing-switcher map-button ${housing}-state ${darkLightTheme}`} onSubmit={housingSwitch}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(housing === 'enabled')? 'Switch off Housing Zones' : 'Switch on Housing Zones'} {(housing === 'enabled')? 'Housing Zones on' : 'Housing Zones off'}
</button> </button>
</form> </form>
); );

View File

@ -14,6 +14,6 @@ export function BuildingBaseLayerAllZoom({ theme }: {theme: MapTheme}) {
url={getTileLayerUrl(tileset)} url={getTileLayerUrl(tileset)}
minZoom={1} minZoom={1}
maxZoom={109} maxZoom={109}
detectRetina={true} detectRetina={false}
/>; />;
} }

View File

@ -14,6 +14,6 @@ export function BuildingBaseLayer({ theme }: {theme: MapTheme}) {
url={getTileLayerUrl(tileset)} url={getTileLayerUrl(tileset)}
minZoom={14} minZoom={14}
maxZoom={19} maxZoom={19}
detectRetina={true} detectRetina={false}
/>; />;
} }

View File

@ -11,6 +11,6 @@ export function BuildingDataLayer({tileset, revisionId} : { tileset: BuildingMap
url={getTileLayerUrl(tileset, {rev: revisionId})} url={getTileLayerUrl(tileset, {rev: revisionId})}
minZoom={9} minZoom={9}
maxZoom={19} maxZoom={19}
detectRetina={true} detectRetina={false}
/>; />;
} }

View File

@ -11,6 +11,6 @@ export function BuildingHighlightLayer({selectedBuildingId, baseTileset}: {selec
url={getTileLayerUrl('highlight', {highlight: `${selectedBuildingId}`, base: baseTileset})} url={getTileLayerUrl('highlight', {highlight: `${selectedBuildingId}`, base: baseTileset})}
minZoom={13} minZoom={13}
maxZoom={19} maxZoom={19}
detectRetina={true} detectRetina={false}
/>; />;
} }

View File

@ -9,6 +9,6 @@ export function BuildingNumbersLayer({revisionId}: {revisionId: string}) {
url={getTileLayerUrl('number_labels', {rev: revisionId})} url={getTileLayerUrl('number_labels', {rev: revisionId})}
minZoom={17} minZoom={17}
maxZoom={19} maxZoom={19}
detectRetina={true} detectRetina={false}
/>; />;
} }

View File

@ -31,7 +31,7 @@ export function CityBaseMapLayer({ theme }: { theme: MapTheme }) {
attribution={attribution} attribution={attribution}
maxNativeZoom={18} maxNativeZoom={18}
maxZoom={19} maxZoom={19}
detectRetina={true} detectRetina={false}
className={theme_class} className={theme_class}
/>; />;
} }

View File

@ -16,7 +16,7 @@ export function HousingBoundaryLayer() {
if(housing == "enabled") { if(housing == "enabled") {
return boundaryGeojson && return boundaryGeojson &&
<GeoJSON <GeoJSON
attribution="Housing Zones from <a href=https://data.london.gov.uk/dataset/housing_zones>London Datastore</a>. The boundaries are based on Ordnance Survey mapping and the data is published under Ordnance Survey's 'presumption to publish'. Contains OS data © Crown copyright and database rights 2019. Greater London Authority - Contains public sector information licensed under the <a href=https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/>Open Government Licence v3.0</a>'" attribution="Housing Zones from <a href=https://data.london.gov.uk/dataset/housing_zones>London Datastore</a>. The boundaries are based on Ordnance Survey mapping and the data is published under Ordnance Survey's 'presumption to publish'. Contains OS data © Crown copyright and database rights 2019. The Greater London Authority - Contains public sector information licensed under the <a href=https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/>Open Government Licence v3.0</a>'"
data={boundaryGeojson} data={boundaryGeojson}
style={{color: '#FF8000', fill: true, weight: 1, opacity: 0.6}} style={{color: '#FF8000', fill: true, weight: 1, opacity: 0.6}}
/>; />;

View File

@ -22,16 +22,8 @@ export function ParcelBoundaryLayer() {
style={{color: '#ff0', fill: false, weight: 1}} style={{color: '#ff0', fill: false, weight: 1}}
/* minNativeZoom={17}*/ /* minNativeZoom={17}*/
/>; />;
} else if (parcel == "disabled") {
return <div></div>
// do not display anything
return boundaryGeojson &&
<GeoJSON
data={boundaryGeojson}
style={{color: '#0f0', fill: false, weight: 1}} />
} else { } else {
return boundaryGeojson && return <div></div>
<GeoJSON data={boundaryGeojson} style={{color: '#0f0', fill: true}}/>;
} }
} }

View File

@ -16,7 +16,7 @@ export function VistaBoundaryLayer() {
if(vista == "enabled") { if(vista == "enabled") {
return boundaryGeojson && return boundaryGeojson &&
<GeoJSON <GeoJSON
attribution=' London Views Management Framework (LVMF) Extended background vistas from <a href=https://data.london.gov.uk/dataset/london-views-management-framework-lvmf-extended-background-vistas>London Datastore</a>: <a href=https://creativecommons.org/licenses/by/4.0/legalcode>CC-BY-SA 4.0</a> by Greater London Authority (GLA)' attribution=' London Views Management Framework (LVMF) Extended background vistas from <a href=https://data.london.gov.uk/dataset/london-views-management-framework-lvmf-extended-background-vistas>London Datastore</a>: <a href=https://creativecommons.org/licenses/by/4.0/legalcode>CC-BY-SA 4.0</a> by the Greater London Authority (GLA)'
data={boundaryGeojson} data={boundaryGeojson}
style={{color: '#0f0', fill: true, weight: 1, opacity: 0.6}} style={{color: '#0f0', fill: true, weight: 1, opacity: 0.6}}
/>; />;

View File

@ -17,6 +17,10 @@
.map-button .btn { .map-button .btn {
margin: 0; margin: 0;
min-width: 310px; min-width: 310px;
color: #191b1d;
}
.map-button .btn:hover {
color: #fff;
} }
.map-button.night .btn { .map-button.night .btn {
color: #fff; color: #fff;
@ -24,25 +28,55 @@
border-color: #343a40; border-color: #343a40;
} }
.map-button.night .btn:hover { .map-button.night .btn:hover {
color: #343a40; color: #d4d7da;
background-color: transparent; background-color: transparent;
background-image: none; background-image: none;
border-color: #343a40; border-color: #343a40;
} }
.map-button.disabled-state,
.map-button.disabled-state .btn{
background-color: #df7474;
}
.map-button.night.disabled-state,
.map-button.night.disabled-state .btn{
background-color: #b03f3f;
}
.map-button.disabled .btn:hover {
background-color: transparent;
background-image: none;
}
.map-button.night.disabled .btn:hover {
background-color: transparent;
background-image: none;
}
.map-button.enabled-state {
color: #75e775;
background-color: #75e775;
}
.map-button.enabled-state .btn{
background-color: #75e775;
}
.map-button.night.enabled-state {
color: #448844;
background-color: #448844;
}
.map-button.night.enabled-state .btn{
background-color: #448844;
}
.map-button.enabled .btn:hover {
background-color: transparent;
background-image: none;
}
.map-button.night.enabled .btn:hover {
background-color: transparent;
background-image: none;
}
@media (max-width: 990px){ @media (max-width: 990px){
.map-button { .map-button {
visibility: hidden; visibility: hidden;
} }
} }
.reset-switcher {
top: 37px;
margin-right: 60px;
}
.reset-switcher .btn {
min-width: 280px;
}
.theme-switcher { .theme-switcher {
top: 77px; top: 77px;
} }

View File

@ -5,8 +5,6 @@ import 'leaflet/dist/leaflet.css';
import './map.css'; import './map.css';
import { apiGet } from '../apiHelpers'; import { apiGet } from '../apiHelpers';
import { HelpIcon } from '../components/icons';
import { Category } from '../config/categories-config';
import { initialMapViewport, mapBackgroundColor, MapTheme, LayerEnablementState } from '../config/map-config'; import { initialMapViewport, mapBackgroundColor, MapTheme, LayerEnablementState } from '../config/map-config';
import { Building } from '../models/building'; import { Building } from '../models/building';
@ -31,7 +29,6 @@ import { Legend } from './legend';
import SearchBox from './search-box'; import SearchBox from './search-box';
import ThemeSwitcher from './theme-switcher'; import ThemeSwitcher from './theme-switcher';
import DataLayerSwitcher from './data-switcher'; import DataLayerSwitcher from './data-switcher';
import { ResetSwitcher } from './reset-switcher';
import { BoroughSwitcher } from './borough-switcher'; import { BoroughSwitcher } from './borough-switcher';
import { ParcelSwitcher } from './parcel-switcher'; import { ParcelSwitcher } from './parcel-switcher';
import { FloodSwitcher } from './flood-switcher'; import { FloodSwitcher } from './flood-switcher';
@ -64,8 +61,7 @@ export const ColouringMap : FC<ColouringMapProps> = ({
categoryMapDefinitions, categoryMapDefinitions,
children children
}) => { }) => {
const { darkLightTheme, darkLightThemeSwitch } = useDisplayPreferences(); const { darkLightTheme, darkLightThemeSwitch, showLayerSelection } = useDisplayPreferences();
const [dataLayers, setDataLayers] = useState<LayerEnablementState>('disabled');
const [position, setPosition] = useState(initialMapViewport.position); const [position, setPosition] = useState(initialMapViewport.position);
const [zoom, setZoom] = useState(initialMapViewport.zoom); const [zoom, setZoom] = useState(initialMapViewport.zoom);
@ -88,18 +84,6 @@ export const ColouringMap : FC<ColouringMapProps> = ({
[onBuildingAction], [onBuildingAction],
) )
const layerSwitch = useCallback(
(e) => {
e.preventDefault();
const newDisplayState = (dataLayers === 'enabled')? 'disabled' : 'enabled';
setDataLayers(newDisplayState);
},
[dataLayers],
)
const hasSelection = selectedBuildingId != undefined;
const isEdit = ['edit', 'multi-edit'].includes(mode);
return ( return (
<div className="map-container"> <div className="map-container">
<MapContainer <MapContainer
@ -174,11 +158,10 @@ export const ColouringMap : FC<ColouringMapProps> = ({
mode !== 'basic' && mode !== 'basic' &&
<> <>
<Legend mapColourScaleDefinitions={categoryMapDefinitions} mapColourScale={mapColourScale} onMapColourScale={onMapColourScale}/> <Legend mapColourScaleDefinitions={categoryMapDefinitions} mapColourScale={mapColourScale} onMapColourScale={onMapColourScale}/>
<ResetSwitcher/>
<ThemeSwitcher onSubmit={darkLightThemeSwitch} currentTheme={darkLightTheme} /> <ThemeSwitcher onSubmit={darkLightThemeSwitch} currentTheme={darkLightTheme} />
<DataLayerSwitcher onSubmit={layerSwitch} currentDisplay={dataLayers} /> <DataLayerSwitcher />
{ {
(dataLayers == "enabled") ? (showLayerSelection == "enabled") ?
<> <>
<BoroughSwitcher/> <BoroughSwitcher/>
<ParcelSwitcher/> <ParcelSwitcher/>

View File

@ -6,10 +6,10 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const ParcelSwitcher: React.FC<{}> = () => { export const ParcelSwitcher: React.FC<{}> = () => {
const { parcel, parcelSwitch, darkLightTheme } = useDisplayPreferences(); const { parcel, parcelSwitch, darkLightTheme } = useDisplayPreferences();
return ( return (
<form className={`parcel-switcher map-button ${darkLightTheme}`} onSubmit={parcelSwitch}> <form className={`parcel-switcher map-button ${parcel}-state ${darkLightTheme}`} onSubmit={parcelSwitch}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(parcel === 'enabled')? 'Switch off Parcel (sample) overlay' : 'Switch on Parcel (sample) overlay'} {(parcel === 'enabled')? 'Parcel overlay (sample) on' : 'Parcel overlay (sample) off'}
</button> </button>
</form> </form>
); );

View File

@ -1,20 +0,0 @@
import React from 'react';
import './map-button.css';
import { useDisplayPreferences } from '../displayPreferences-context';
export const ResetSwitcher: React.FC<{}> = () => {
const { resetLayers, darkLightTheme, anyLayerModifiedState } = useDisplayPreferences();
if(anyLayerModifiedState()) {
return (
<form className={`reset-switcher map-button ${darkLightTheme}`} onSubmit={resetLayers}>
<button className="btn btn-outline btn-outline-dark"
type="submit">
{"Reset layers"}
</button>
</form>
);
} else {
return <></>
}
}

View File

@ -6,10 +6,10 @@ import { useDisplayPreferences } from '../displayPreferences-context';
export const VistaSwitcher: React.FC<{}> = () => { export const VistaSwitcher: React.FC<{}> = () => {
const { vista, vistaSwitch, darkLightTheme } = useDisplayPreferences(); const { vista, vistaSwitch, darkLightTheme } = useDisplayPreferences();
return ( return (
<form className={`vista-switcher map-button ${darkLightTheme}`} onSubmit={vistaSwitch}> <form className={`vista-switcher map-button ${vista}-state ${darkLightTheme}`} onSubmit={vistaSwitch}>
<button className="btn btn-outline btn-outline-dark" <button className="btn btn-outline btn-outline-dark"
type="submit"> type="submit">
{(vista === 'enabled')? 'Switch off Protected Vistas' : 'Switch on Protected Vistas'} {(vista === 'enabled')? 'Protected Vistas on' : 'Protected Vistas off'}
</button> </button>
</form> </form>
); );

View File

@ -191,13 +191,6 @@ const LAYER_QUERIES = {
OR planning_heritage_at_risk_url <> '' OR planning_heritage_at_risk_url <> ''
OR planning_in_apa_url <> '' OR planning_in_apa_url <> ''
`, `,
empty_map: `
SELECT
geometry_id
FROM
buildings
WHERE
sust_dec IS NOT NULL`,
conservation_area: ` conservation_area: `
SELECT SELECT
geometry_id geometry_id

View File

@ -39,6 +39,7 @@ def load_data_into_database(cursor, data):
if entry['_source']['description'] != None: if entry['_source']['description'] != None:
description = entry['_source']['description'].strip() description = entry['_source']['description'].strip()
application_id = entry['_source']['lpa_app_no'] application_id = entry['_source']['lpa_app_no']
application_id_with_borough_identifier = entry['_source']['id']
decision_date = parse_date_string_into_date_object(entry['_source']['decision_date']) decision_date = parse_date_string_into_date_object(entry['_source']['decision_date'])
last_synced_date = parse_date_string_into_date_object(entry['_source']['last_synced']) last_synced_date = parse_date_string_into_date_object(entry['_source']['last_synced'])
uprn = entry['_source']['uprn'] uprn = entry['_source']['uprn']
@ -65,8 +66,8 @@ def load_data_into_database(cursor, data):
"status": status, "status": status,
"status_before_aliasing": status_before_aliasing, "status_before_aliasing": status_before_aliasing,
"status_explanation_note": status_explanation_note, "status_explanation_note": status_explanation_note,
"data_source": "Greater London Authority's Planning London DataHub", "data_source": "the Greater London Authority's Planning London DataHub",
"data_source_link": None, "data_source_link": "https://www.london.gov.uk/programmes-strategies/planning/digital-planning/planning-london-datahub",
"address": address_data.planning_data_entry_to_address(entry), "address": address_data.planning_data_entry_to_address(entry),
} }
if entry["address"] != None: if entry["address"] != None:
@ -87,7 +88,7 @@ def load_data_into_database(cursor, data):
print("last_synced_date is treated as invalid:", entry["last_synced_date"]) print("last_synced_date is treated as invalid:", entry["last_synced_date"])
entry["last_synced_date"] = None entry["last_synced_date"] = None
if "Hackney" in entry["application_id"]: if "Hackney" in application_id_with_borough_identifier:
if entry["application_url"] != None: if entry["application_url"] != None:
if "https://" not in entry["application_url"]: if "https://" not in entry["application_url"]:
entry["application_url"] = "https://developmentandhousing.hackney.gov.uk" + entry["application_url"] entry["application_url"] = "https://developmentandhousing.hackney.gov.uk" + entry["application_url"]