Rework split between app/map-app/map
This commit is contained in:
parent
6625099c03
commit
b9648c47af
@ -1,31 +1,30 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Route, Switch, Link } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { parse } from 'query-string';
|
||||
|
||||
import '../../node_modules/bootstrap/dist/css/bootstrap.min.css';
|
||||
import './app.css';
|
||||
|
||||
import BuildingView from './building/building-view';
|
||||
import ColouringMap from './map/map';
|
||||
import Header from './header';
|
||||
import MultiEdit from './building/multi-edit';
|
||||
import Categories from './building/categories';
|
||||
import Sidebar from './building/sidebar';
|
||||
|
||||
import AboutPage from './pages/about';
|
||||
import ContributorAgreementPage from './pages/contributor-agreement';
|
||||
import PrivacyPolicyPage from './pages/privacy-policy';
|
||||
import Welcome from './pages/welcome';
|
||||
|
||||
import Login from './user/login';
|
||||
import MyAccountPage from './user/my-account';
|
||||
import SignUp from './user/signup';
|
||||
|
||||
import ForgottenPassword from './user/forgotten-password';
|
||||
import PasswordReset from './user/password-reset';
|
||||
|
||||
import { parseCategoryURL } from '../parse';
|
||||
import MapApp from './map-app';
|
||||
|
||||
|
||||
interface AppProps {
|
||||
user?: any;
|
||||
building?: any;
|
||||
building_like?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* App component
|
||||
@ -39,35 +38,28 @@ import { parseCategoryURL } from '../parse';
|
||||
* map or other pages are rendered, based on the URL. Use a react-router-dom <Link /> in
|
||||
* child components to navigate without a full page reload.
|
||||
*/
|
||||
class App extends React.Component<any, any> { // TODO: add proper types
|
||||
class App extends React.Component<AppProps, any> { // TODO: add proper types
|
||||
static propTypes = { // TODO: generate propTypes from TS
|
||||
user: PropTypes.object,
|
||||
building: PropTypes.object,
|
||||
building_like: PropTypes.bool
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Readonly<AppProps>) {
|
||||
super(props);
|
||||
// set building revision id, default 0
|
||||
const rev = (props.building)? +props.building.revision_id : 0;
|
||||
|
||||
this.state = {
|
||||
user: props.user,
|
||||
building: props.building,
|
||||
building_like: props.building_like,
|
||||
revision_id: rev
|
||||
user: props.user
|
||||
};
|
||||
this.login = this.login.bind(this);
|
||||
this.updateUser = this.updateUser.bind(this);
|
||||
this.logout = this.logout.bind(this);
|
||||
this.selectBuilding = this.selectBuilding.bind(this);
|
||||
this.colourBuilding = this.colourBuilding.bind(this);
|
||||
this.increaseRevision = this.increaseRevision.bind(this);
|
||||
}
|
||||
|
||||
login(user) {
|
||||
if (user.error) {
|
||||
this.logout();
|
||||
return
|
||||
return;
|
||||
}
|
||||
this.setState({user: user});
|
||||
}
|
||||
@ -80,171 +72,12 @@ class App extends React.Component<any, any> { // TODO: add proper types
|
||||
this.setState({user: undefined});
|
||||
}
|
||||
|
||||
increaseRevision(revisionId) {
|
||||
revisionId = +revisionId;
|
||||
// bump revision id, only ever increasing
|
||||
if (revisionId > this.state.revision_id){
|
||||
this.setState({revision_id: revisionId})
|
||||
}
|
||||
}
|
||||
|
||||
selectBuilding(building) {
|
||||
this.increaseRevision(building.revision_id);
|
||||
// get UPRNs and update
|
||||
fetch(`/api/buildings/${building.building_id}/uprns.json`, {
|
||||
method: 'GET',
|
||||
headers:{
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
}).then(
|
||||
res => res.json()
|
||||
).then((res) => {
|
||||
if (res.error) {
|
||||
console.error(res);
|
||||
} else {
|
||||
building.uprns = res.uprns;
|
||||
this.setState({building: building});
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error(err)
|
||||
this.setState({building: building});
|
||||
});
|
||||
|
||||
// get if liked and update
|
||||
fetch(`/api/buildings/${building.building_id}/like.json`, {
|
||||
method: 'GET',
|
||||
headers:{
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
}).then(
|
||||
res => res.json()
|
||||
).then((res) => {
|
||||
if (res.error) {
|
||||
console.error(res);
|
||||
} else {
|
||||
this.setState({building_like: res.like});
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error(err)
|
||||
this.setState({building_like: false});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Colour building
|
||||
*
|
||||
* Used in multi-edit mode to colour buildings on map click
|
||||
*
|
||||
* Pulls data from URL to form update
|
||||
*
|
||||
* @param {object} building
|
||||
*/
|
||||
colourBuilding(building) {
|
||||
const cat = parseCategoryURL(window.location.pathname);
|
||||
const q = parse(window.location.search);
|
||||
const data = (cat === 'like')? {like: true}: JSON.parse(q.data as string); // TODO: verify what happens if data is string[]
|
||||
if (cat === 'like'){
|
||||
this.likeBuilding(building.building_id)
|
||||
} else {
|
||||
this.updateBuilding(building.building_id, data)
|
||||
}
|
||||
}
|
||||
|
||||
likeBuilding(buildingId) {
|
||||
fetch(`/api/buildings/${buildingId}/like.json`, {
|
||||
method: 'POST',
|
||||
headers:{
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({like: true})
|
||||
}).then(
|
||||
res => res.json()
|
||||
).then(function(res){
|
||||
if (res.error) {
|
||||
console.error({error: res.error})
|
||||
} else {
|
||||
this.increaseRevision(res.revision_id);
|
||||
}
|
||||
}.bind(this)).catch(
|
||||
(err) => console.error({error: err})
|
||||
);
|
||||
}
|
||||
|
||||
updateBuilding(buildingId, data){
|
||||
fetch(`/api/buildings/${buildingId}.json`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
headers:{
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
}).then(
|
||||
res => res.json()
|
||||
).then(res => {
|
||||
if (res.error) {
|
||||
console.error({error: res.error})
|
||||
} else {
|
||||
this.increaseRevision(res.revision_id);
|
||||
}
|
||||
}).catch(
|
||||
(err) => console.error({error: err})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const building_id = (this.state.building)?
|
||||
this.state.building.building_id
|
||||
: 2503371 // Default to UCL main building. TODO use last selected if any
|
||||
const building = this.state.building;
|
||||
const building_like = this.state.building_like;
|
||||
return (
|
||||
<Fragment>
|
||||
<Header user={this.state.user} />
|
||||
<main>
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Welcome />
|
||||
</Route>
|
||||
<Route exact path="/view/categories.html">
|
||||
<Sidebar>
|
||||
<Categories mode="view" building_id={building_id} />
|
||||
</Sidebar>
|
||||
</Route>
|
||||
<Route exact path="/edit/categories.html">
|
||||
<Sidebar>
|
||||
<Categories mode="edit" building_id={building_id} />
|
||||
</Sidebar>
|
||||
</Route>
|
||||
<Route exact path="/multi-edit/:cat.html" render={(props) => (
|
||||
<MultiEdit
|
||||
{...props}
|
||||
user={this.state.user}
|
||||
/>
|
||||
) } />
|
||||
<Route exact path="/:mode/:cat/building/:building.html" render={(props) => (
|
||||
<BuildingView
|
||||
mode={props.match.params.mode}
|
||||
cat={props.match.params.cat}
|
||||
building={this.state.building}
|
||||
building_like={this.state.building_like}
|
||||
selectBuilding={this.selectBuilding}
|
||||
user={this.state.user}
|
||||
/>
|
||||
) } />
|
||||
</Switch>
|
||||
<Switch>
|
||||
<Route exact path="/(multi-edit.*|edit.*|view.*)?" render={(props) => (
|
||||
<ColouringMap
|
||||
{...props}
|
||||
building={this.state.building}
|
||||
revision_id={this.state.revision_id}
|
||||
selectBuilding={this.selectBuilding}
|
||||
colourBuilding={this.colourBuilding}
|
||||
/>
|
||||
) } />
|
||||
<Route exact path="/about.html" component={AboutPage} />
|
||||
<Route exact path="/login.html">
|
||||
<Login user={this.state.user} login={this.login} />
|
||||
@ -263,6 +96,14 @@ class App extends React.Component<any, any> { // TODO: add proper types
|
||||
</Route>
|
||||
<Route exact path="/privacy-policy.html" component={PrivacyPolicyPage} />
|
||||
<Route exact path="/contributor-agreement.html" component={ContributorAgreementPage} />
|
||||
<Route exact path="/:mode?/:category?/:building?" render={(props) => (
|
||||
<MapApp
|
||||
{...props}
|
||||
building={this.props.building}
|
||||
building_like={this.props.building_like}
|
||||
user={this.state.user}
|
||||
/>
|
||||
)} />
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
</main>
|
||||
|
250
app/src/frontend/map-app.tsx
Normal file
250
app/src/frontend/map-app.tsx
Normal file
@ -0,0 +1,250 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Switch, Route, RouteComponentProps, Redirect } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Welcome from './pages/welcome';
|
||||
import Sidebar from './building/sidebar';
|
||||
import Categories from './building/categories';
|
||||
import MultiEdit from './building/multi-edit';
|
||||
import BuildingView from './building/building-view';
|
||||
import ColouringMap from './map/map';
|
||||
import { parse } from 'query-string';
|
||||
|
||||
interface MapAppRouteParams {
|
||||
mode: 'view' | 'edit' | 'multi-edit';
|
||||
category: string;
|
||||
building?: string;
|
||||
}
|
||||
|
||||
interface MapAppProps extends RouteComponentProps<MapAppRouteParams> {
|
||||
building: any;
|
||||
building_like: boolean;
|
||||
user: any;
|
||||
}
|
||||
|
||||
interface MapAppState {
|
||||
category: string;
|
||||
revision_id: number;
|
||||
building: any;
|
||||
building_like: boolean;
|
||||
}
|
||||
|
||||
class MapApp extends React.Component<MapAppProps, MapAppState> {
|
||||
static propTypes = {
|
||||
category: PropTypes.string,
|
||||
revision_id: PropTypes.number,
|
||||
building: PropTypes.object,
|
||||
building_like: PropTypes.bool,
|
||||
user: PropTypes.object
|
||||
};
|
||||
constructor(props: Readonly<MapAppProps>) {
|
||||
super(props);
|
||||
|
||||
// set building revision id, default 0
|
||||
const rev = props.building != undefined ? +props.building.revision_id : 0;
|
||||
|
||||
this.state = {
|
||||
category: this.getCategory(props.match.params.category),
|
||||
revision_id: rev,
|
||||
building: props.building,
|
||||
building_like: props.building_like
|
||||
};
|
||||
|
||||
this.selectBuilding = this.selectBuilding.bind(this);
|
||||
this.colourBuilding = this.colourBuilding.bind(this);
|
||||
this.increaseRevision = this.increaseRevision.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props: Readonly<MapAppProps>) {
|
||||
const newCategory = this.getCategory(props.match.params.category);
|
||||
if (newCategory != undefined) {
|
||||
this.setState({ category: newCategory });
|
||||
}
|
||||
}
|
||||
|
||||
getCategory(category: string) {
|
||||
if (category === 'categories') return undefined;
|
||||
|
||||
return category;
|
||||
}
|
||||
|
||||
increaseRevision(revisionId) {
|
||||
revisionId = +revisionId;
|
||||
// bump revision id, only ever increasing
|
||||
if (revisionId > this.state.revision_id) {
|
||||
this.setState({ revision_id: revisionId })
|
||||
}
|
||||
}
|
||||
|
||||
selectBuilding(building) {
|
||||
const mode = this.props.match.params.mode || 'view';
|
||||
const category = this.props.match.params.category || 'age';
|
||||
|
||||
if (building == undefined ||
|
||||
(this.state.building != undefined &&
|
||||
building.building_id === this.state.building.building_id)) {
|
||||
this.setState({ building: undefined });
|
||||
this.props.history.push(`/${mode}/${category}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.increaseRevision(building.revision_id);
|
||||
// get UPRNs and update
|
||||
fetch(`/api/buildings/${building.building_id}/uprns.json`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
}).then(
|
||||
res => res.json()
|
||||
).then((res) => {
|
||||
if (res.error) {
|
||||
console.error(res);
|
||||
} else {
|
||||
building.uprns = res.uprns;
|
||||
this.setState({ building: building });
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error(err)
|
||||
this.setState({ building: building });
|
||||
});
|
||||
|
||||
// get if liked and update
|
||||
fetch(`/api/buildings/${building.building_id}/like.json`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
}).then(
|
||||
res => res.json()
|
||||
).then((res) => {
|
||||
if (res.error) {
|
||||
console.error(res);
|
||||
} else {
|
||||
this.setState({ building_like: res.like });
|
||||
this.props.history.push(`/${mode}/${category}/${building.building_id}`);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error(err)
|
||||
this.setState({ building_like: false });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Colour building
|
||||
*
|
||||
* Used in multi-edit mode to colour buildings on map click
|
||||
*
|
||||
* Pulls data from URL to form update
|
||||
*
|
||||
* @param {object} building
|
||||
*/
|
||||
colourBuilding(building) {
|
||||
const cat = this.props.match.params.category;
|
||||
const q = parse(window.location.search);
|
||||
const data = (cat === 'like') ? { like: true } : JSON.parse(q.data as string); // TODO: verify what happens if data is string[]
|
||||
if (cat === 'like') {
|
||||
this.likeBuilding(building.building_id)
|
||||
} else {
|
||||
this.updateBuilding(building.building_id, data)
|
||||
}
|
||||
}
|
||||
|
||||
likeBuilding(buildingId) {
|
||||
fetch(`/api/buildings/${buildingId}/like.json`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({ like: true })
|
||||
}).then(
|
||||
res => res.json()
|
||||
).then(function (res) {
|
||||
if (res.error) {
|
||||
console.error({ error: res.error })
|
||||
} else {
|
||||
this.increaseRevision(res.revision_id);
|
||||
}
|
||||
}.bind(this)).catch(
|
||||
(err) => console.error({ error: err })
|
||||
);
|
||||
}
|
||||
|
||||
updateBuilding(buildingId, data) {
|
||||
fetch(`/api/buildings/${buildingId}.json`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
}).then(
|
||||
res => res.json()
|
||||
).then(res => {
|
||||
if (res.error) {
|
||||
console.error({ error: res.error })
|
||||
} else {
|
||||
this.increaseRevision(res.revision_id);
|
||||
}
|
||||
}).catch(
|
||||
(err) => console.error({ error: err })
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const mode = this.props.match.params.mode || 'basic';
|
||||
|
||||
let category = this.state.category || 'age';
|
||||
|
||||
const building_id = this.state.building && this.state.building.building_id;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<Welcome />
|
||||
</Route>
|
||||
<Route exact path="/:mode/categories/:building?">
|
||||
<Sidebar>
|
||||
<Categories mode={mode} building_id={building_id} />
|
||||
</Sidebar>
|
||||
</Route>
|
||||
<Route exact path="/multi-edit/:cat" render={(props) => (
|
||||
<MultiEdit
|
||||
{...props}
|
||||
user={this.props.user}
|
||||
/>
|
||||
)} />
|
||||
<Route exact path="/:mode/:cat/:building?">
|
||||
<Sidebar>
|
||||
<BuildingView
|
||||
mode={mode}
|
||||
cat={category}
|
||||
building={this.state.building}
|
||||
building_like={this.state.building_like}
|
||||
selectBuilding={this.selectBuilding}
|
||||
user={this.props.user}
|
||||
/>
|
||||
</Sidebar>
|
||||
</Route>
|
||||
<Route exact path="/(view|edit|multi-edit)">
|
||||
<Redirect to="/view/categories" />
|
||||
</Route>
|
||||
</Switch>
|
||||
<ColouringMap
|
||||
building={this.state.building}
|
||||
mode={mode}
|
||||
category={category}
|
||||
revision_id={this.state.revision_id}
|
||||
selectBuilding={this.selectBuilding}
|
||||
colourBuilding={this.colourBuilding}
|
||||
/>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MapApp;
|
@ -14,6 +14,15 @@ import ThemeSwitcher from './theme-switcher';
|
||||
|
||||
const OS_API_KEY = 'NVUxtY5r8eA6eIfwrPTAGKrAAsoeI9E9';
|
||||
|
||||
interface ColouringMapProps {
|
||||
building: any;
|
||||
mode: 'basic' | 'view' | 'edit' | 'multi-edit';
|
||||
category: string;
|
||||
revision_id: number;
|
||||
selectBuilding: any;
|
||||
colourBuilding: any;
|
||||
}
|
||||
|
||||
interface ColouringMapState {
|
||||
theme: 'light' | 'night';
|
||||
lat: number;
|
||||
@ -23,14 +32,14 @@ interface ColouringMapState {
|
||||
/**
|
||||
* Map area
|
||||
*/
|
||||
class ColouringMap extends Component<any, ColouringMapState> { // TODO: add proper types
|
||||
class ColouringMap extends Component<ColouringMapProps, ColouringMapState> { // TODO: add proper types
|
||||
static propTypes = { // TODO: generate propTypes from TS
|
||||
building: PropTypes.object,
|
||||
mode: PropTypes.string,
|
||||
category: PropTypes.string,
|
||||
revision_id: PropTypes.number,
|
||||
selectBuilding: PropTypes.func,
|
||||
colourBuilding: PropTypes.func,
|
||||
match: PropTypes.object,
|
||||
history: PropTypes.object
|
||||
colourBuilding: PropTypes.func
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
@ -44,7 +53,6 @@ class ColouringMap extends Component<any, ColouringMapState> { // TODO: add prop
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
this.handleLocate = this.handleLocate.bind(this);
|
||||
this.themeSwitch = this.themeSwitch.bind(this);
|
||||
this.getMode = this.getMode.bind(this);
|
||||
}
|
||||
|
||||
handleLocate(lat, lng, zoom){
|
||||
@ -52,21 +60,13 @@ class ColouringMap extends Component<any, ColouringMapState> { // TODO: add prop
|
||||
lat: lat,
|
||||
lng: lng,
|
||||
zoom: zoom
|
||||
})
|
||||
}
|
||||
|
||||
getMode() {
|
||||
const isEdit = this.props.match.url.match('edit')
|
||||
const isMulti = this.props.match.url.match('multi')
|
||||
return isEdit? (isMulti? 'multi' : 'edit') : 'view';
|
||||
});
|
||||
}
|
||||
|
||||
handleClick(e) {
|
||||
const mode = this.getMode()
|
||||
const lat = e.latlng.lat
|
||||
const lng = e.latlng.lng
|
||||
const newCat = parseCategoryURL(this.props.match.url);
|
||||
const mapCat = newCat || 'age';
|
||||
const mode = this.props.mode;
|
||||
const lat = e.latlng.lat;
|
||||
const lng = e.latlng.lng;
|
||||
fetch(
|
||||
'/api/buildings/locate?lat='+lat+'&lng='+lng
|
||||
).then(
|
||||
@ -74,17 +74,15 @@ class ColouringMap extends Component<any, ColouringMapState> { // TODO: add prop
|
||||
).then(function(data){
|
||||
if (data && data.length){
|
||||
const building = data[0];
|
||||
if (mode === 'multi') {
|
||||
if (mode === 'multi-edit') {
|
||||
// colour building directly
|
||||
this.props.colourBuilding(building);
|
||||
} else {
|
||||
this.props.selectBuilding(building);
|
||||
this.props.history.push(`/${mode}/${mapCat}/building/${building.building_id}.html`);
|
||||
}
|
||||
} else {
|
||||
// deselect but keep/return to expected colour theme
|
||||
this.props.selectBuilding(undefined);
|
||||
this.props.history.push(`/${mode}/${mapCat}.html`);
|
||||
}
|
||||
}.bind(this)).catch(
|
||||
(err) => console.error(err)
|
||||
@ -101,46 +99,49 @@ class ColouringMap extends Component<any, ColouringMapState> { // TODO: add prop
|
||||
const position: LatLngExpression = [this.state.lat, this.state.lng];
|
||||
|
||||
// baselayer
|
||||
const key = OS_API_KEY
|
||||
const tilematrixSet = 'EPSG:3857'
|
||||
const key = OS_API_KEY;
|
||||
const tilematrixSet = 'EPSG:3857';
|
||||
const layer = (this.state.theme === 'light')? 'Light 3857' : 'Night 3857';
|
||||
const url = `https://api2.ordnancesurvey.co.uk/mapping_api/v1/service/zxy/${tilematrixSet}/${layer}/{z}/{x}/{y}.png?key=${key}`
|
||||
const attribution = 'Building attribute data is © Colouring London contributors. Maps contain OS data © Crown copyright: OS Maps baselayers and building outlines.'
|
||||
const baseUrl = `https://api2.ordnancesurvey.co.uk/mapping_api/v1/service/zxy/${tilematrixSet}/${layer}/{z}/{x}/{y}.png?key=${key}`;
|
||||
const attribution = 'Building attribute data is © Colouring London contributors. Maps contain OS data © Crown copyright: OS Maps baselayers and building outlines.';
|
||||
const baseLayer = <TileLayer
|
||||
url={baseUrl}
|
||||
attribution={attribution}
|
||||
/>;
|
||||
|
||||
const buildingsBaseUrl = `/tiles/base_${this.state.theme}/{z}/{x}/{y}.png`;
|
||||
const buildingBaseLayer = <TileLayer url={buildingsBaseUrl} minZoom={14} />;
|
||||
|
||||
// colour-data tiles
|
||||
const isBuilding = /building/.test(this.props.match.url);
|
||||
const isEdit = /edit/.test(this.props.match.url);
|
||||
const cat = parseCategoryURL(this.props.match.url);
|
||||
const cat = this.props.category;
|
||||
const tilesetByCat = {
|
||||
age: 'date_year',
|
||||
size: 'size_storeys',
|
||||
location: 'location',
|
||||
like: 'likes',
|
||||
planning: 'conservation_area',
|
||||
}
|
||||
};
|
||||
const tileset = tilesetByCat[cat];
|
||||
// pick revision id to bust browser cache
|
||||
const rev = this.props.revision_id;
|
||||
const dataLayer = tileset?
|
||||
const dataLayer = tileset != undefined ?
|
||||
<TileLayer
|
||||
key={tileset}
|
||||
url={`/tiles/${tileset}/{z}/{x}/{y}.png?rev=${rev}`}
|
||||
minZoom={9} />
|
||||
minZoom={9}
|
||||
/>
|
||||
: null;
|
||||
|
||||
// highlight
|
||||
const geometryId = (this.props.building) ? this.props.building.geometry_id : undefined;
|
||||
const highlight = `/tiles/highlight/{z}/{x}/{y}.png?highlight=${geometryId}`
|
||||
const highlightLayer = (isBuilding && this.props.building) ?
|
||||
const highlightLayer = this.props.building != undefined ?
|
||||
<TileLayer
|
||||
key={this.props.building.building_id}
|
||||
url={highlight}
|
||||
minZoom={14} />
|
||||
url={`/tiles/highlight/{z}/{x}/{y}.png?highlight=${this.props.building.geometry_id}`}
|
||||
minZoom={14}
|
||||
/>
|
||||
: null;
|
||||
|
||||
const baseUrl = (this.state.theme === 'light')?
|
||||
'/tiles/base_light/{z}/{x}/{y}.png'
|
||||
: '/tiles/base_night/{z}/{x}/{y}.png'
|
||||
const isEdit = ['edit', 'multi-edit'].includes(this.props.mode);
|
||||
|
||||
return (
|
||||
<div className="map-container">
|
||||
@ -154,23 +155,23 @@ class ColouringMap extends Component<any, ColouringMapState> { // TODO: add prop
|
||||
attributionControl={false}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<TileLayer url={url} attribution={attribution} />
|
||||
<TileLayer url={baseUrl} minZoom={14} />
|
||||
{ baseLayer }
|
||||
{ buildingBaseLayer }
|
||||
{ dataLayer }
|
||||
{ highlightLayer }
|
||||
<ZoomControl position="topright" />
|
||||
<AttributionControl prefix="" />
|
||||
<AttributionControl />
|
||||
</Map>
|
||||
{
|
||||
!isBuilding && this.props.match.url !== '/'? (
|
||||
<div className="map-notice">
|
||||
<HelpIcon /> {isEdit? 'Click a building to edit' : 'Click a building for details'}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
{
|
||||
this.props.match.url !== '/'? (
|
||||
this.props.mode !== 'basic'? (
|
||||
<Fragment>
|
||||
{
|
||||
this.props.building == undefined ?
|
||||
<div className="map-notice">
|
||||
<HelpIcon /> {isEdit ? 'Click a building to edit' : 'Click a building for details'}
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
<Legend slug={cat} />
|
||||
<ThemeSwitcher onSubmit={this.themeSwitch} currentTheme={this.state.theme} />
|
||||
<SearchBox onLocate={this.handleLocate} />
|
||||
|
Loading…
Reference in New Issue
Block a user