mirror of
https://github.com/a-nyx/maputnik-with-pmtiles.git
synced 2024-12-27 09:05:25 +01:00
Pass everything down as props
This commit is contained in:
parent
416cf7e0af
commit
b6dff4aa58
8 changed files with 214 additions and 167 deletions
59
src/app.jsx
59
src/app.jsx
|
@ -5,6 +5,7 @@ import { Drawer, Container, Block, Fixed } from 'rebass'
|
||||||
import {Map} from './map.jsx'
|
import {Map} from './map.jsx'
|
||||||
import {Toolbar} from './toolbar.jsx'
|
import {Toolbar} from './toolbar.jsx'
|
||||||
import { StyleManager } from './style.js'
|
import { StyleManager } from './style.js'
|
||||||
|
import { StyleStore } from './stylestore.js'
|
||||||
import { WorkspaceDrawer } from './workspace.jsx'
|
import { WorkspaceDrawer } from './workspace.jsx'
|
||||||
|
|
||||||
import theme from './theme.js'
|
import theme from './theme.js'
|
||||||
|
@ -20,42 +21,40 @@ export default class App extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {
|
this.state = {
|
||||||
styleManager: new StyleManager(),
|
styleStore: new StyleStore(),
|
||||||
workContext: "layers",
|
workContext: "layers",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onStyleDownload() {
|
|
||||||
const mapStyle = this.state.styleManager.exportStyle()
|
|
||||||
const blob = new Blob([mapStyle], {type: "application/json;charset=utf-8"});
|
|
||||||
saveAs(blob, "glstyle.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
onStyleUpload(newStyle) {
|
|
||||||
this.setState({ styleManager: new StyleManager(newStyle) })
|
|
||||||
}
|
|
||||||
|
|
||||||
onOpenSettings() {
|
|
||||||
this.setState({
|
|
||||||
workContext: "settings",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onOpenLayers() {
|
|
||||||
this.setState({
|
|
||||||
workContext: "layers",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getChildContext() {
|
getChildContext() {
|
||||||
return {
|
return {
|
||||||
rebass: theme,
|
rebass: theme,
|
||||||
reactIconBase: {
|
reactIconBase: { size: 20 }
|
||||||
size: 20,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onStyleDownload() {
|
||||||
|
const mapStyle = JSON.stringify(this.state.styleStore.currentStyle, null, 4)
|
||||||
|
const blob = new Blob([mapStyle], {type: "application/json;charset=utf-8"});
|
||||||
|
saveAs(blob, mapStyle.id + ".json");
|
||||||
|
}
|
||||||
|
|
||||||
|
onStyleUpload(newStyle) {
|
||||||
|
this.setState({ styleStore: new StyleStore(newStyle) })
|
||||||
|
}
|
||||||
|
|
||||||
|
onStyleChanged(newStyle) {
|
||||||
|
this.setState({ styleStore: new StyleStore(newStyle) })
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpenSettings() {
|
||||||
|
this.setState({ workContext: "settings", })
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpenLayers() {
|
||||||
|
this.setState({ workContext: "layers", })
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div style={{ fontFamily: theme.fontFamily, color: theme.color, fontWeight: 300 }}>
|
return <div style={{ fontFamily: theme.fontFamily, color: theme.color, fontWeight: 300 }}>
|
||||||
<Toolbar
|
<Toolbar
|
||||||
|
@ -64,9 +63,13 @@ export default class App extends React.Component {
|
||||||
onOpenSettings={this.onOpenSettings.bind(this)}
|
onOpenSettings={this.onOpenSettings.bind(this)}
|
||||||
onOpenLayers={this.onOpenLayers.bind(this)}
|
onOpenLayers={this.onOpenLayers.bind(this)}
|
||||||
/>
|
/>
|
||||||
<WorkspaceDrawer workContext={this.state.workContext} styleManager={this.state.styleManager}/>
|
<WorkspaceDrawer
|
||||||
|
onStyleChanged={this.onStyleChanged.bind(this)}
|
||||||
|
workContext={this.state.workContext}
|
||||||
|
mapStyle={this.state.styleStore.currentStyle}
|
||||||
|
/>
|
||||||
<div className={layout.map}>
|
<div className={layout.map}>
|
||||||
<Map styleManager={this.state.styleManager} />
|
<Map mapStyle={this.state.styleStore.currentStyle} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,8 @@ export class NoLayer extends React.Component {
|
||||||
export class LayerPanel extends React.Component {
|
export class LayerPanel extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
layer: React.PropTypes.object.isRequired,
|
layer: React.PropTypes.object.isRequired,
|
||||||
styleManager: React.PropTypes.object.isRequired,
|
onLayerChanged: React.PropTypes.func.isRequired,
|
||||||
destroyLayer: React.PropTypes.func.isRequired,
|
onLayerDestroyed: React.PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
static childContextTypes = {
|
static childContextTypes = {
|
||||||
|
@ -91,10 +91,6 @@ export class LayerPanel extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
isOpened: false,
|
isOpened: false,
|
||||||
//TODO: Is that bad practice?
|
|
||||||
//however I want to keep the layer state local herere
|
|
||||||
//otherwise the style always would, propagate around?
|
|
||||||
layer: this.props.layer
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,25 +104,15 @@ export class LayerPanel extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onPaintChanged(property, newValue) {
|
onPaintChanged(property, newValue) {
|
||||||
let layer = this.state.layer
|
const layer = this.props.layer
|
||||||
layer.paint[property] = newValue;
|
layer.paint[property] = newValue;
|
||||||
|
this.props.onLayerChanged(layer)
|
||||||
this.props.styleManager.changeStyle({
|
|
||||||
command: 'setPaintProperty',
|
|
||||||
args: [layer.id, property, newValue]
|
|
||||||
})
|
|
||||||
|
|
||||||
this.setState({ layer });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onLayoutChanged(property, newValue) {
|
onLayoutChanged(property, newValue) {
|
||||||
let layer = this.state.layer
|
const layer = this.props.layer
|
||||||
layer.layout[property] = newValue;
|
layer.layout[property] = newValue;
|
||||||
this.props.styleManager.changeStyle({
|
this.props.onLayerChanged(layer)
|
||||||
command: 'setLayoutProperty',
|
|
||||||
args: [layer.id, property, newValue]
|
|
||||||
})
|
|
||||||
this.setState({ layer });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLayer() {
|
toggleLayer() {
|
||||||
|
@ -135,11 +121,17 @@ export class LayerPanel extends React.Component {
|
||||||
|
|
||||||
layerFromType(type) {
|
layerFromType(type) {
|
||||||
if (type === "fill") {
|
if (type === "fill") {
|
||||||
return <FillLayer layer={this.state.layer} onPaintChanged={this.onPaintChanged.bind(this)} />
|
return <FillLayer
|
||||||
|
layer={this.props.layer}
|
||||||
|
onPaintChanged={this.onPaintChanged.bind(this)}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "background") {
|
if (type === "background") {
|
||||||
return <BackgroundLayer layer={this.state.layer} onPaintChanged={this.onPaintChanged.bind(this)} />
|
return <BackgroundLayer
|
||||||
|
layer={this.props.layer}
|
||||||
|
onPaintChanged={this.onPaintChanged.bind(this)}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "line") {
|
if (type === "line") {
|
||||||
|
@ -149,12 +141,12 @@ export class LayerPanel extends React.Component {
|
||||||
if (type === "symbol") {
|
if (type === "symbol") {
|
||||||
return <SymbolLayer />
|
return <SymbolLayer />
|
||||||
}
|
}
|
||||||
|
|
||||||
return <NoLayer />
|
return <NoLayer />
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleVisibility() {
|
toggleVisibility() {
|
||||||
console.log(this.state.layer)
|
if(this.props.layer.layout.visibility === 'none') {
|
||||||
if(this.state.layer.layout.visibility === 'none') {
|
|
||||||
this.onLayoutChanged('visibility', 'visible')
|
this.onLayoutChanged('visibility', 'visible')
|
||||||
} else {
|
} else {
|
||||||
this.onLayoutChanged('visibility', 'none')
|
this.onLayoutChanged('visibility', 'none')
|
||||||
|
@ -163,7 +155,7 @@ export class LayerPanel extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let visibleIcon = <MdVisibilityOff />
|
let visibleIcon = <MdVisibilityOff />
|
||||||
if(this.state.layer.layout && this.state.layer.layout.visibility === 'none') {
|
if(this.props.layer.layout && this.props.layer.layout.visibility === 'none') {
|
||||||
visibleIcon = <MdVisibility />
|
visibleIcon = <MdVisibility />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,23 +167,23 @@ export class LayerPanel extends React.Component {
|
||||||
borderRight: 0,
|
borderRight: 0,
|
||||||
borderStyle: "solid",
|
borderStyle: "solid",
|
||||||
borderColor: theme.borderColor,
|
borderColor: theme.borderColor,
|
||||||
borderLeftColor: this.state.layer.metadata["mapolo:color"],
|
borderLeftColor: this.props.layer.metadata["mapolo:color"],
|
||||||
}}>
|
}}>
|
||||||
<Toolbar onClick={this.toggleLayer.bind(this)}>
|
<Toolbar onClick={this.toggleLayer.bind(this)}>
|
||||||
<NavItem style={{fontWeight: 400}}>
|
<NavItem style={{fontWeight: 400}}>
|
||||||
#{this.state.layer.id}
|
#{this.props.layer.id}
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<Space auto x={1} />
|
<Space auto x={1} />
|
||||||
<NavItem onClick={this.toggleVisibility.bind(this)}>
|
<NavItem onClick={this.toggleVisibility.bind(this)}>
|
||||||
{visibleIcon}
|
{visibleIcon}
|
||||||
</NavItem>
|
</NavItem>
|
||||||
<NavItem onClick={(e) => this.props.destroyLayer(this.state.layer.id)}>
|
<NavItem onClick={(e) => this.props.onLayerDestroyed(this.props.layer)}>
|
||||||
<MdDelete />
|
<MdDelete />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
<Collapse isOpened={this.state.isOpened}>
|
<Collapse isOpened={this.state.isOpened}>
|
||||||
<div style={{padding: theme.scale[2], paddingRight: 0, backgroundColor: theme.colors.black}}>
|
<div style={{padding: theme.scale[2], paddingRight: 0, backgroundColor: theme.colors.black}}>
|
||||||
{this.layerFromType(this.state.layer.type)}
|
{this.layerFromType(this.props.layer.type)}
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</div>
|
</div>
|
||||||
|
@ -200,24 +192,47 @@ export class LayerPanel extends React.Component {
|
||||||
|
|
||||||
export class LayerEditor extends React.Component {
|
export class LayerEditor extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
styleManager: React.PropTypes.object.isRequired
|
layers: React.PropTypes.array.isRequired,
|
||||||
|
onLayersChanged: React.PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyLayer(layerId) {
|
constructor(props) {
|
||||||
this.props.styleManager.changeStyle({
|
super(props)
|
||||||
command: 'removeLayer',
|
}
|
||||||
args: [layerId]
|
|
||||||
})
|
onLayerDestroyed(deletedLayer) {
|
||||||
|
let deleteIdx = -1
|
||||||
|
for (let i = 0; i < this.props.layers.length; i++) {
|
||||||
|
if(this.props.layers[i].id == deletedLayer.id) {
|
||||||
|
deleteIdx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingLayers = this.props.layers
|
||||||
|
const removedLayers = remainingLayers.splice(deleteIdx, 1)
|
||||||
|
this.props.onLayersChanged(remainingLayers)
|
||||||
|
}
|
||||||
|
|
||||||
|
onLayerChanged(changedLayer) {
|
||||||
|
let changedIdx = -1
|
||||||
|
for (let i = 0; i < this.props.layers.length; i++) {
|
||||||
|
if(this.props.layers[i].id == changedLayer.id) {
|
||||||
|
changedIdx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const changedLayers = this.props.layers
|
||||||
|
changedLayers[changedIdx] = changedLayer
|
||||||
|
this.props.onLayersChanged(changedLayers)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const layers = this.props.styleManager.layers()
|
const layerPanels = this.props.layers.map(layer => {
|
||||||
const layerPanels = layers.map(layer => {
|
|
||||||
return <LayerPanel
|
return <LayerPanel
|
||||||
key={layer.id}
|
key={layer.id}
|
||||||
layer={layer}
|
layer={layer}
|
||||||
destroyLayer={this.destroyLayer.bind(this)}
|
onLayerDestroyed={this.onLayerDestroyed.bind(this)}
|
||||||
styleManager={this.props.styleManager}
|
onLayerChanged={this.onLayerChanged.bind(this)}
|
||||||
/>
|
/>
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
30
src/map.jsx
30
src/map.jsx
|
@ -5,32 +5,14 @@ import theme from './theme.js'
|
||||||
|
|
||||||
export class Map extends React.Component {
|
export class Map extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
styleManager: React.PropTypes.object.isRequired
|
mapStyle: React.PropTypes.object.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props)
|
|
||||||
this.map = null
|
|
||||||
}
|
|
||||||
|
|
||||||
onStyleChange(change) {
|
|
||||||
this.map[change.command].apply(this.map, change.args);
|
|
||||||
}
|
|
||||||
|
|
||||||
onMapLoaded(map) {
|
|
||||||
this.map = map;
|
|
||||||
this.props.styleManager.onStyleChange(this.onStyleChange.bind(this))
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.props.styleManager.mapStyle) {
|
return <ReactMapboxGl
|
||||||
return <ReactMapboxGl
|
style={this.props.mapStyle}
|
||||||
onStyleLoad={this.onMapLoaded.bind(this)}
|
accessToken="pk.eyJ1IjoibW9yZ2Vua2FmZmVlIiwiYSI6IjIzcmN0NlkifQ.0LRTNgCc-envt9d5MzR75w">
|
||||||
style={this.props.styleManager.mapStyle}
|
<ZoomControl/>
|
||||||
accessToken="pk.eyJ1IjoibW9yZ2Vua2FmZmVlIiwiYSI6IjIzcmN0NlkifQ.0LRTNgCc-envt9d5MzR75w">
|
</ReactMapboxGl>
|
||||||
<ZoomControl/>
|
|
||||||
</ReactMapboxGl>
|
|
||||||
}
|
|
||||||
return <div style={{backgroundColor: theme.colors.black}}/>
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Heading, Container, Input, Toolbar, NavItem, Space } from 'rebass'
|
||||||
/** Edit global settings within a style such as the name */
|
/** Edit global settings within a style such as the name */
|
||||||
export class SettingsEditor extends React.Component {
|
export class SettingsEditor extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
styleManager: React.PropTypes.object.isRequired
|
mapStyle: React.PropTypes.object.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
|
68
src/style.js
68
src/style.js
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import randomColor from 'randomcolor'
|
import randomColor from 'randomcolor'
|
||||||
|
|
||||||
function assignColorsToLayers(layers) {
|
export function colorizeLayers(layers) {
|
||||||
return layers.map(layer => {
|
return layers.map(layer => {
|
||||||
if(!layer.metadata) {
|
if(!layer.metadata) {
|
||||||
layer.metadata = {}
|
layer.metadata = {}
|
||||||
|
@ -12,69 +12,3 @@ function assignColorsToLayers(layers) {
|
||||||
return layer
|
return layer
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// A wrapper around Mapbox GL style to publish
|
|
||||||
// and subscribe to map changes
|
|
||||||
export class StyleManager {
|
|
||||||
constructor(mapStyle) {
|
|
||||||
this.commandHistory = [];
|
|
||||||
this.subscribers = [];
|
|
||||||
this.mapStyle = mapStyle;
|
|
||||||
|
|
||||||
if(this.mapStyle) {
|
|
||||||
this.mapStyle.layers = assignColorsToLayers(this.mapStyle.layers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onStyleChange(cb) {
|
|
||||||
this.subscribers.push(cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeStyle(change) {
|
|
||||||
this.commandHistory.push(change)
|
|
||||||
this.subscribers.forEach(f => f(change))
|
|
||||||
console.log(change)
|
|
||||||
}
|
|
||||||
|
|
||||||
exportStyle() {
|
|
||||||
return JSON.stringify(this.mapStyle, null, 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
settings() {
|
|
||||||
const { name, sprite, glyphs, owner } = this.mapStyle
|
|
||||||
return { name, sprite, glyphs, owner }
|
|
||||||
}
|
|
||||||
|
|
||||||
set name(val) {
|
|
||||||
this.mapStyle.name = val
|
|
||||||
}
|
|
||||||
|
|
||||||
set owner(val) {
|
|
||||||
this.mapStyle.owner = val
|
|
||||||
}
|
|
||||||
|
|
||||||
set glyphs(val) {
|
|
||||||
this.mapStyle.glyphs = val
|
|
||||||
this.changeStyle({
|
|
||||||
command: 'setStyle',
|
|
||||||
args: [this.mapStyle]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
set sprite(val) {
|
|
||||||
this.mapStyle.sprite = val
|
|
||||||
this.changeStyle({
|
|
||||||
command: 'setStyle',
|
|
||||||
args: [this.mapStyle]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
layer(layerId) {
|
|
||||||
return this.mapStyle.layers[layerId]
|
|
||||||
}
|
|
||||||
|
|
||||||
layers() {
|
|
||||||
if(this.mapStyle) return this.mapStyle.layers
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
100
src/stylestore.js
Normal file
100
src/stylestore.js
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
import { colorizeLayers } from './style.js'
|
||||||
|
|
||||||
|
const emptyStyle = {
|
||||||
|
version: 8,
|
||||||
|
sources: {},
|
||||||
|
layers: []
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manages many possible styles that are stored in the local storage
|
||||||
|
export class StyleStore {
|
||||||
|
// By default the style store will use the last edited style
|
||||||
|
// as current working style if no explicit style is set
|
||||||
|
constructor(mapStyle) {
|
||||||
|
if(mapStyle) {
|
||||||
|
this.load(mapStyle)
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
const latestStyle = this.latestStyle()
|
||||||
|
console.log("Loading latest stlye " + latestStyle.id + " from " + latestStyle.modified)
|
||||||
|
this.load(latestStyle)
|
||||||
|
} catch(err) {
|
||||||
|
console.log(err)
|
||||||
|
this.load(emptyStyle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the last edited style
|
||||||
|
latestStyle() {
|
||||||
|
const styles = this.loadStoredStyles()
|
||||||
|
|
||||||
|
if(styles.length == 0) {
|
||||||
|
throw "No existing style found"
|
||||||
|
}
|
||||||
|
|
||||||
|
let maxStyle = styles[0]
|
||||||
|
styles.forEach(s => {
|
||||||
|
if(s.date > maxStyle.date) {
|
||||||
|
maxStyle = s
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return JSON.parse(window.localStorage.getItem(this.styleKey(maxStyle.styleId, maxStyle.date)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return style ids and dates of all styles stored in local storage
|
||||||
|
loadStoredStyles() {
|
||||||
|
const styles = []
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
const key = localStorage.key(i)
|
||||||
|
if(this.isStyleKey(key)) {
|
||||||
|
styles.push(this.fromKey(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return styles
|
||||||
|
}
|
||||||
|
|
||||||
|
isStyleKey(key) {
|
||||||
|
const parts = key.split(":")
|
||||||
|
return parts.length >= 3 && parts[0] === "mapolo"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load style from local storage by key
|
||||||
|
fromKey(key) {
|
||||||
|
if(!this.isStyleKey(key)) {
|
||||||
|
throw "Key is not a valid style key"
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = key.split(":")
|
||||||
|
const styleId = parts[1]
|
||||||
|
const date = new Date(parts.slice(2).join(":"))
|
||||||
|
return {styleId, date}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate key that identifies the style with a version
|
||||||
|
styleKey(styleId, modifiedDate) {
|
||||||
|
return ["mapolo", styleId, modifiedDate.toJSON()].join(":")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take snapshot of current style and load it
|
||||||
|
backup(mapStyle) {
|
||||||
|
mapStyle.modified = new Date()
|
||||||
|
const key = this.styleKey(mapStyle.id, mapStyle.modified)
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(mapStyle))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a style from external into the store
|
||||||
|
// replacing the previous version
|
||||||
|
load(mapStyle) {
|
||||||
|
if(!("id" in mapStyle)) {
|
||||||
|
mapStyle.id = Math.random().toString(36).substr(2, 9)
|
||||||
|
}
|
||||||
|
if(!("created" in mapStyle)) {
|
||||||
|
mapStyle.created = new Date()
|
||||||
|
}
|
||||||
|
mapStyle.layers = colorizeLayers(mapStyle.layers)
|
||||||
|
this.backup(mapStyle)
|
||||||
|
this.currentStyle = mapStyle
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,23 +3,36 @@ import { LayerEditor } from './layers.jsx'
|
||||||
import { SettingsEditor } from './settings.jsx'
|
import { SettingsEditor } from './settings.jsx'
|
||||||
import theme from './theme.js'
|
import theme from './theme.js'
|
||||||
|
|
||||||
/** The workspace drawer contains the editor components depending on the context
|
/** The workspace drawer contains the editor components depending on the edit
|
||||||
* chosen in the toolbar. */
|
* context chosen in the toolbar. It holds the state of the layers.*/
|
||||||
export class WorkspaceDrawer extends React.Component {
|
export class WorkspaceDrawer extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
mapStyle: React.PropTypes.object.isRequired,
|
||||||
|
onStyleChanged: React.PropTypes.func.isRequired,
|
||||||
workContext: React.PropTypes.oneOf(['layers', 'settings']).isRequired,
|
workContext: React.PropTypes.oneOf(['layers', 'settings']).isRequired,
|
||||||
styleManager: React.PropTypes.object.isRequired
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onLayersChanged(layers) {
|
||||||
|
const changedStyle = this.props.mapStyle
|
||||||
|
changedStyle.layers = layers
|
||||||
|
this.props.onStyleChanged(changedStyle)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let workspaceContent = null
|
let workspaceContent = null
|
||||||
|
|
||||||
if(this.props.workContext === "layers" && this.props.styleManager.mapStyle) {
|
if(this.props.workContext === "layers") {
|
||||||
workspaceContent = <LayerEditor styleManager={this.props.styleManager}/>
|
workspaceContent = <LayerEditor
|
||||||
|
onLayersChanged={this.onLayersChanged.bind(this)}
|
||||||
|
layers={this.props.mapStyle.layers}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.props.workContext === "settings" && this.props.styleManager.mapStyle) {
|
if(this.props.workContext === "settings") {
|
||||||
workspaceContent = <SettingsEditor styleManager={this.props.styleManager}/>
|
workspaceContent = <SettingsEditor
|
||||||
|
onStyleChanged={this.props.onStyleChanged}
|
||||||
|
mapStyle={this.props.mapStyle}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div style={{
|
return <div style={{
|
||||||
|
|
|
@ -58,7 +58,7 @@ module.exports = {
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: './src/template.html',
|
template: './src/template.html',
|
||||||
title: 'Webpack App'
|
title: 'Mapolo'
|
||||||
}),
|
}),
|
||||||
new webpack.optimize.DedupePlugin()
|
new webpack.optimize.DedupePlugin()
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue