mirror of
https://github.com/a-nyx/maputnik-with-pmtiles.git
synced 2024-12-26 18:50:38 +01:00
LayerEditor keeps layer as own state
This commit is contained in:
parent
ca04f60393
commit
3cf8a6939d
4 changed files with 119 additions and 51 deletions
26
src/app.jsx
26
src/app.jsx
|
@ -4,17 +4,21 @@ import { Drawer, Container, Block, Fixed } from 'rebass'
|
|||
import {Map} from './map.jsx'
|
||||
import {Toolbar} from './toolbar.jsx'
|
||||
import { LayerEditor } from './layers.jsx'
|
||||
import { StyleManager } from './style.js'
|
||||
|
||||
import theme from './theme.js'
|
||||
import layout from './layout.scss'
|
||||
import 'react-virtualized/styles.css';
|
||||
import 'react-virtualized/styles.css'
|
||||
|
||||
export class WorkspaceDrawer extends React.Component {
|
||||
static propTypes = {
|
||||
styleManager: React.PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
let editor = null
|
||||
|
||||
if(this.props.mapStyle) {
|
||||
editor = <LayerEditor layers={this.props.mapStyle.layers}/>
|
||||
if(this.props.styleManager.mapStyle) {
|
||||
editor = <LayerEditor styleManager={this.props.styleManager}/>
|
||||
}
|
||||
|
||||
return <div style={{
|
||||
|
@ -40,14 +44,13 @@ export default class App extends React.Component {
|
|||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.updateStyle = this.updateStyle.bind(this);
|
||||
this.state = {
|
||||
mapStyle: null
|
||||
styleManager: new StyleManager(),
|
||||
}
|
||||
}
|
||||
|
||||
updateStyle(newStyle) {
|
||||
this.setState({ mapStyle: newStyle })
|
||||
onStyleUpload(newStyle) {
|
||||
this.setState({ styleManager: new StyleManager(newStyle) })
|
||||
}
|
||||
|
||||
getChildContext () {
|
||||
|
@ -60,12 +63,11 @@ export default class App extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
console.log(this.state.mapStyle)
|
||||
return <div style={{ fontFamily: theme.fontFamily, color: theme.color }}>
|
||||
<Toolbar onStyleUpload={this.updateStyle} />
|
||||
<WorkspaceDrawer mapStyle={this.state.mapStyle} />
|
||||
<Toolbar onStyleUpload={this.onStyleUpload.bind(this)} />
|
||||
<WorkspaceDrawer styleManager={this.state.styleManager}/>
|
||||
<div className={layout.map}>
|
||||
<Map mapStyle={this.state.mapStyle} />
|
||||
<Map styleManager={this.state.styleManager} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
@ -8,17 +8,25 @@ import theme from './theme.js'
|
|||
import scrollbars from './scrollbars.scss'
|
||||
|
||||
export class FillLayer extends React.Component {
|
||||
static propTypes = {
|
||||
layer: React.PropTypes.object.isRequired,
|
||||
onPaintChanged: React.PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
onPaintChanged(property, e) {
|
||||
this.props.onPaintChanged(property, e.target.value)
|
||||
}
|
||||
|
||||
render() {
|
||||
const paint = this.props.layer.paint
|
||||
return <div>
|
||||
<Input name="fill-color" label="Fill color" onChange={this.props.changePaint} value={this.props.paint["fill-color"]} />
|
||||
<Input name="fill-outline-color" label="Fill outline color" onChange={this.props.changePaint} value={this.props.paint["fill-outline-color"]} />
|
||||
<Input name="fill-translate" label="Fill translate" onChange={this.props.changePaint} value={this.props.paint["fill-translate"]} />
|
||||
<Input name="fill-translate-anchor" label="Fill translate anchor" onChange={this.props.changePaint} value={this.props.paint["fill-translate-anchor"]} />
|
||||
<Checkbox name="fill-antialias" label="Antialias" onChange={this.props.changePaint} checked={this.props.paint["fill-antialias"]} />
|
||||
<Input name="fill-opacity" label="Opacity" onChange={this.props.changePaint} value={this.props.paint["fill-opacity"]} />
|
||||
<Input name="fill-color" label="Fill color" onChange={this.onPaintChanged.bind(this, "fill-color")} value={paint["fill-color"]} />
|
||||
<Input name="fill-outline-color" label="Fill outline color" onChange={this.onPaintChanged.bind(this, "fill-outline-color")} value={paint["fill-outline-color"]} />
|
||||
<Input name="fill-translate" label="Fill translate" onChange={this.onPaintChanged.bind(this, "fill-translate")} value={paint["fill-translate"]} />
|
||||
<Input name="fill-translate-anchor" label="Fill translate anchor" onChange={this.onPaintChanged.bind(this, "fill-translate-anchor")} value={paint["fill-translate-anchor"]} />
|
||||
<Checkbox name="fill-antialias" label="Antialias" onChange={this.onPaintChanged.bind(this, "fill-antialias")} checked={paint["fill-antialias"]} />
|
||||
<Input name="fill-opacity" label="Opacity" onChange={this.onPaintChanged.bind(this, "fill-opacity")} value={paint["fill-opacity"]} />
|
||||
</div>
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,16 +42,30 @@ export class SymbolLayer extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export class NoLayer extends React.Component {
|
||||
render() {
|
||||
return <div></div>
|
||||
}
|
||||
}
|
||||
|
||||
export class LayerPanel extends React.Component {
|
||||
static propTypes = {
|
||||
layer: React.PropTypes.object.isRequired,
|
||||
styleManager: React.PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
static childContextTypes = {
|
||||
reactIconBase: React.PropTypes.object
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.toggleLayer = this.toggleLayer.bind(this);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,18 +78,38 @@ export class LayerPanel extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
onPaintChanged(property, newValue) {
|
||||
let layer = this.state.layer
|
||||
layer.paint[property] = newValue;
|
||||
|
||||
this.props.styleManager.changeStyle({
|
||||
command: 'setPaintProperty',
|
||||
args: [layer.id, property, newValue]
|
||||
})
|
||||
|
||||
this.setState({ layer });
|
||||
}
|
||||
|
||||
toggleLayer() {
|
||||
this.setState({isOpened: !this.state.isOpened})
|
||||
}
|
||||
|
||||
render() {
|
||||
let layer = <FillLayer paint={this.props.layer.paint}/>
|
||||
if (this.props.layer.type === "line") {
|
||||
layer = <LineLayer />
|
||||
} else if (this.props.layer.type === "symbol") {
|
||||
layer = <SymbolLayer />
|
||||
layerFromType(type) {
|
||||
if (type === "fill") {
|
||||
return <FillLayer layer={this.state.layer} onPaintChanged={this.onPaintChanged.bind(this)} />
|
||||
}
|
||||
|
||||
if (type === "line") {
|
||||
return <LineLayer />
|
||||
}
|
||||
|
||||
if (type === "symbol") {
|
||||
return <SymbolLayer />
|
||||
}
|
||||
return <NoLayer />
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div style={{
|
||||
padding: theme.scale[0],
|
||||
borderBottom: 1,
|
||||
|
@ -77,9 +119,9 @@ export class LayerPanel extends React.Component {
|
|||
borderStyle: "solid",
|
||||
borderColor: theme.borderColor,
|
||||
}}>
|
||||
<Toolbar onClick={this.toggleLayer}>
|
||||
<Toolbar onClick={this.toggleLayer.bind(this)}>
|
||||
<NavItem>
|
||||
#{this.props.layer.id}
|
||||
#{this.state.layer.id}
|
||||
</NavItem>
|
||||
<Space auto x={1} />
|
||||
<NavItem>
|
||||
|
@ -91,7 +133,7 @@ export class LayerPanel extends React.Component {
|
|||
</Toolbar>
|
||||
<Collapse isOpened={this.state.isOpened}>
|
||||
<div style={{padding: theme.scale[2], paddingRight: 0}}>
|
||||
{layer}
|
||||
{this.layerFromType(this.state.layer.type)}
|
||||
</div>
|
||||
</Collapse>
|
||||
</div>
|
||||
|
@ -99,10 +141,16 @@ export class LayerPanel extends React.Component {
|
|||
}
|
||||
|
||||
export class LayerEditor extends React.Component {
|
||||
static propTypes = {
|
||||
styleManager: React.PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
const layerPanels = this.props.layers.map(layer => {
|
||||
return <LayerPanel key={layer.id} layer={layer} />
|
||||
const layers = this.props.styleManager.layers()
|
||||
const layerPanels = layers.map(layer => {
|
||||
return <LayerPanel key={layer.id} layer={layer} styleManager={this.props.styleManager} />
|
||||
});
|
||||
|
||||
return <div>
|
||||
<Toolbar style={{marginRight: 20}}>
|
||||
<NavItem>
|
||||
|
|
22
src/map.jsx
22
src/map.jsx
|
@ -4,14 +4,29 @@ import ReactMapboxGl, { ZoomControl } from "react-mapbox-gl"
|
|||
import theme from './theme.js'
|
||||
|
||||
export class Map extends React.Component {
|
||||
static propTypes = {
|
||||
styleManager: React.PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(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() {
|
||||
if (this.props.mapStyle) {
|
||||
if (this.props.styleManager.mapStyle) {
|
||||
return <ReactMapboxGl
|
||||
style={this.props.mapStyle}
|
||||
onStyleLoad={this.onMapLoaded.bind(this)}
|
||||
style={this.props.styleManager.mapStyle}
|
||||
accessToken="pk.eyJ1IjoibW9yZ2Vua2FmZmVlIiwiYSI6IjIzcmN0NlkifQ.0LRTNgCc-envt9d5MzR75w">
|
||||
<ZoomControl/>
|
||||
</ReactMapboxGl>
|
||||
|
@ -19,4 +34,3 @@ export class Map extends React.Component {
|
|||
return <div style={{backgroundColor: theme.colors.black}}/>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
32
src/style.js
32
src/style.js
|
@ -1,27 +1,31 @@
|
|||
import React from 'react';
|
||||
|
||||
// A wrapper around Mapbox GL style
|
||||
export class Style {
|
||||
constructor() {
|
||||
this.styleHistory = [];
|
||||
this.renderers = [];
|
||||
// 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;
|
||||
}
|
||||
|
||||
load(style) {
|
||||
this.currentStyle = style;
|
||||
onStyleChange(cb) {
|
||||
this.subscribers.push(cb);
|
||||
}
|
||||
|
||||
onRender(cb) {
|
||||
this.renderers.push(cb);
|
||||
changeStyle(command) {
|
||||
this.commandHistory.push(command)
|
||||
this.subscribers.forEach(f => f(command))
|
||||
console.log(command)
|
||||
}
|
||||
|
||||
update(style) {
|
||||
this.styleHistory.push(this.currentStyle);
|
||||
this.currentStyle = style;
|
||||
this.renderers.forEach(r => r(this.currentStyle))
|
||||
layer(layerId) {
|
||||
console.log(this.mapStyle)
|
||||
return this.mapStyle.layers[layerId]
|
||||
}
|
||||
|
||||
layers() {
|
||||
return this.currentStyle.layers;
|
||||
if(this.mapStyle) return this.mapStyle.layers
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue