From 29a0ef0d1cad638d4fd1b6c1825ef8b271785266 Mon Sep 17 00:00:00 2001 From: orangemug Date: Sun, 16 Feb 2020 18:11:47 +0000 Subject: [PATCH] Change to always attempt rendering of map state, even if broken, allowing the user to fix style issues step-by-step. --- src/components/App.jsx | 117 +++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/src/components/App.jsx b/src/components/App.jsx index bb9f9ec..aacfec3 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -3,6 +3,7 @@ import React from 'react' import cloneDeep from 'lodash.clonedeep' import clamp from 'lodash.clamp' import get from 'lodash.get' +import {unset} from 'lodash' import {arrayMove} from 'react-sortable-hoc' import url from 'url' @@ -97,7 +98,7 @@ export default class App extends React.Component { port = window.location.port } this.styleStore = new ApiStyleStore({ - onLocalStyleChange: mapStyle => this.onStyleChanged(mapStyle, false), + onLocalStyleChange: mapStyle => this.onStyleChanged(mapStyle, {save: false}), port: port, host: params.get("localhost") }) @@ -207,7 +208,6 @@ export default class App extends React.Component { errors: [], infos: [], mapStyle: style.emptyStyle, - dirtyMapStyle: style.emptyStyle, selectedLayerIndex: 0, sources: {}, vectorLayers: {}, @@ -280,7 +280,7 @@ export default class App extends React.Component { } updateFonts(urlTemplate) { - const metadata = this.state.dirtyMapStyle.metadata || {} + const metadata = this.state.mapStyle.metadata || {} const accessToken = metadata['maputnik:openmaptiles_access_token'] || tokens.openmaptiles let glyphUrl = (typeof urlTemplate === 'string')? urlTemplate.replace('{key}', accessToken): urlTemplate; @@ -316,7 +316,12 @@ export default class App extends React.Component { this.onStyleChanged(changedStyle) } - onStyleChanged = (newStyle, save=true) => { + onStyleChanged = (newStyle, opts={}) => { + opts = { + save: true, + addRevision: true, + ...opts, + }; const errors = validate(newStyle, latest) || []; const mappedErrors = errors.map(error => { @@ -343,68 +348,63 @@ export default class App extends React.Component { } }) - if(errors.length === 0) { + let dirtyMapStyle = undefined; + if (errors.length > 0) { + dirtyMapStyle = cloneDeep(newStyle); - if(newStyle.glyphs !== this.state.dirtyMapStyle.glyphs) { - this.updateFonts(newStyle.glyphs) - } - if(newStyle.sprite !== this.state.dirtyMapStyle.sprite) { - this.updateIcons(newStyle.sprite) - } - - this.revisionStore.addRevision(newStyle) - if(save) this.saveStyle(newStyle) - this.setState({ - dirtyMapStyle: newStyle, - mapStyle: newStyle, - errors: [], - }) - } else { - this.setState({ - dirtyMapStyle: newStyle, - errors: mappedErrors, - }) + errors.forEach(error => { + const {message} = error; + const objPath = message.split(":")[0]; + unset(dirtyMapStyle, objPath); + }); } + if(newStyle.glyphs !== this.state.mapStyle.glyphs) { + this.updateFonts(newStyle.glyphs) + } + if(newStyle.sprite !== this.state.mapStyle.sprite) { + this.updateIcons(newStyle.sprite) + } + + if (opts.addRevision) { + this.revisionStore.addRevision(newStyle); + } + if (opts.save) { + this.saveStyle(newStyle); + } + + this.setState({ + mapStyle: newStyle, + dirtyMapStyle: dirtyMapStyle, + errors: mappedErrors, + }) + this.fetchSources(); } onUndo = () => { let activeStyle; + activeStyle = this.revisionStore.undo() - // Check our dirty style state first, otherwise just undo to that state. - if (isEqual(this.state.mapStyle, this.state.dirtyMapStyle)) { - activeStyle = this.revisionStore.undo() - } - else { - activeStyle = this.state.mapStyle; - } - - const messages = undoMessages(this.state.dirtyMapStyle, activeStyle) - this.saveStyle(activeStyle) + const messages = undoMessages(this.state.mapStyle, activeStyle) + this.onStyleChanged(activeStyle, {addRevision: false}); this.setState({ infos: messages, - mapStyle: activeStyle, - dirtyMapStyle: activeStyle, - errors: [], }) } onRedo = () => { const activeStyle = this.revisionStore.redo() - const messages = redoMessages(this.state.dirtyMapStyle, activeStyle) - this.saveStyle(activeStyle) + const messages = redoMessages(this.state.mapStyle, activeStyle) + this.onStyleChanged(activeStyle, {addRevision: false}); this.setState({ infos: messages, - mapStyle: activeStyle, - dirtyMapStyle: activeStyle, - errors: [], }) } onMoveLayer = (move) => { let { oldIndex, newIndex } = move; - let layers = this.state.dirtyMapStyle.layers; + let layers = this.state.mapStyle.layers; oldIndex = clamp(oldIndex, 0, layers.length-1); newIndex = clamp(newIndex, 0, layers.length-1); if(oldIndex === newIndex) return; @@ -422,14 +422,14 @@ export default class App extends React.Component { onLayersChange = (changedLayers) => { const changedStyle = { - ...this.state.dirtyMapStyle, + ...this.state.mapStyle, layers: changedLayers } this.onStyleChanged(changedStyle) } onLayerDestroy = (layerId) => { - let layers = this.state.dirtyMapStyle.layers; + let layers = this.state.mapStyle.layers; const remainingLayers = layers.slice(0); const idx = style.indexOfLayer(remainingLayers, layerId) remainingLayers.splice(idx, 1); @@ -448,7 +448,7 @@ export default class App extends React.Component { } onLayerVisibilityToggle = (layerId) => { - let layers = this.state.dirtyMapStyle.layers; + let layers = this.state.mapStyle.layers; const changedLayers = layers.slice(0) const idx = style.indexOfLayer(changedLayers, layerId) @@ -463,7 +463,7 @@ export default class App extends React.Component { onLayerIdChange = (oldId, newId) => { - const changedLayers = this.state.dirtyMapStyle.layers.slice(0) + const changedLayers = this.state.mapStyle.layers.slice(0) const idx = style.indexOfLayer(changedLayers, oldId) changedLayers[idx] = { @@ -476,7 +476,7 @@ export default class App extends React.Component { onLayerChanged = (layer) => { console.log("test: onLayerChanged", layer); - const changedLayers = this.state.dirtyMapStyle.layers.slice(0) + const changedLayers = this.state.mapStyle.layers.slice(0) const idx = style.indexOfLayer(changedLayers, layer.id) changedLayers[idx] = layer @@ -513,7 +513,7 @@ export default class App extends React.Component { fetchSources() { const sourceList = {...this.state.sources}; - for(let [key, val] of Object.entries(this.state.dirtyMapStyle.sources)) { + for(let [key, val] of Object.entries(this.state.mapStyle.sources)) { if(sourceList.hasOwnProperty(key)) { continue; } @@ -586,10 +586,11 @@ export default class App extends React.Component { } mapRenderer() { + const {mapStyle, dirtyMapStyle} = this.state; const metadata = this.state.mapStyle.metadata || {}; const mapProps = { - mapStyle: this.state.mapStyle, + mapStyle: (dirtyMapStyle || mapStyle), replaceAccessTokens: (mapStyle) => { return style.replaceAccessTokens(mapStyle, { allowFallback: true @@ -637,7 +638,7 @@ export default class App extends React.Component { } onLayerSelect = (layerId) => { - const idx = style.indexOfLayer(this.state.dirtyMapStyle.layers, layerId) + const idx = style.indexOfLayer(this.state.mapStyle.layers, layerId) this.setState({ selectedLayerIndex: idx }) } @@ -677,14 +678,14 @@ export default class App extends React.Component { } render() { - const layers = this.state.dirtyMapStyle.layers || [] + const layers = this.state.mapStyle.layers || [] const selectedLayer = layers.length > 0 ? layers[this.state.selectedLayerIndex] : null - const metadata = this.state.dirtyMapStyle.metadata || {} + const metadata = this.state.mapStyle.metadata || {} const toolbar =