diff --git a/package.json b/package.json index 6be26d1..3a8ccd5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "dependencies": { "color": "^1.0.3", "file-saver": "^1.3.2", + "lodash.clonedeep": "^4.5.0", "lodash.throttle": "^4.1.1", "lodash.topairs": "^4.3.0", "mapbox-gl": "mapbox/mapbox-gl-js#6c24b9621d2aa770eda67fb5638b4d78087b5624", diff --git a/src/components/App.jsx b/src/components/App.jsx index 34dde60..3bf9e11 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -75,12 +75,12 @@ export default class App extends React.Component { this.setState({ accessToken: newToken }) } - onLayersChanged(changedLayers) { + onLayersChange(changedLayers) { const changedStyle = { ...this.state.mapStyle, - layers: [changedLayers] + layers: changedLayers } - this.setState({ mapStyle: newStyle }) + this.setState({ mapStyle: changedStyle }) } onLayerChanged(layer) { @@ -112,14 +112,9 @@ export default class App extends React.Component { } } - onLayerSelected(layerId) { - const layers = this.state.mapStyle.layers - for (let i = 0; i < layers.length; i++) { - if(layers[i].id === layerId) { - this.setState({ selectedLayerIndex: i }) - break - } - } + onLayerSelect(layerId) { + const idx = style.indexOfLayer(this.state.mapStyle.layers, layerId) + this.setState({ selectedLayerIndex: idx }) } render() { @@ -135,17 +130,17 @@ export default class App extends React.Component { /> const layerList = const layerEditor = selectedLayer ? : null return {}, + onLayerSelect: () => {}, } constructor(props) { @@ -33,9 +35,34 @@ class LayerListContainer extends React.Component { this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this); } - onLayerDestroyed(deletedLayer) { - const remainingLayers = this.props.layers.delete(deletedLayer.id) - this.props.onLayersChanged(remainingLayers) + onLayerDestroy(layerId) { + const remainingLayers = this.props.layers.slice(0) + const idx = style.indexOfLayer(remainingLayers, layerId) + remainingLayers.splice(idx, 1); + this.props.onLayersChange(remainingLayers) + } + + onLayerCopy(layerId) { + const changedLayers = this.props.layers.slice(0) + const idx = style.indexOfLayer(changedLayers, layerId) + + const clonedLayer = cloneDeep(changedLayers[idx]) + clonedLayer.id = clonedLayer.id + "-copy" + changedLayers.splice(idx, 0, clonedLayer) + this.props.onLayersChange(changedLayers) + } + + onLayerVisibilityToggle(layerId) { + const changedLayers = this.props.layers.slice(0) + const idx = style.indexOfLayer(changedLayers, layerId) + + const layer = { ...changedLayers[idx] } + const changedLayout = 'layout' in layer ? {...layer.layout} : {} + changedLayout.visibility = changedLayout.visibility === 'none' ? 'visible' : 'none' + + layer.layout = changedLayout + changedLayers[idx] = layer + this.props.onLayersChange(changedLayers) } render() { @@ -46,8 +73,12 @@ class LayerListContainer extends React.Component { key={layerId} layerId={layerId} layerType={layer.type} + visibility={(layer.layout || {}).visibility} isSelected={index === this.props.selectedLayerIndex} - onLayerSelected={this.props.onLayerSelected} + onLayerSelect={this.props.onLayerSelect} + onLayerDestroy={this.onLayerDestroy.bind(this)} + onLayerCopy={this.onLayerCopy.bind(this)} + onLayerVisibilityToggle={this.onLayerVisibilityToggle.bind(this)} /> }) return @@ -71,7 +102,7 @@ export default class LayerList extends React.Component { if(oldIndex === newIndex) return let layers = this.props.layers.slice(0) layers = arrayMove(layers, oldIndex, newIndex) - this.props.onLayersChanged(layers) + this.props.onLayersChange(layers) } render() { diff --git a/src/components/layers/LayerListItem.jsx b/src/components/layers/LayerListItem.jsx index 0b0a489..d8ea0f5 100644 --- a/src/components/layers/LayerListItem.jsx +++ b/src/components/layers/LayerListItem.jsx @@ -35,6 +35,7 @@ class IconAction extends React.Component { static propTypes = { action: React.PropTypes.string.isRequired, active: React.PropTypes.bool, + onClick: React.PropTypes.func.isRequired, } constructor(props) { @@ -44,12 +45,19 @@ class IconAction extends React.Component { renderIcon() { const iconStyle = { - fill: this.props.active ? (this.state.hover ? colors.lowgray : colors.midgray) : colors.gray, + fill: colors.gray + } + + if(this.props.active) { + iconStyle.fill = colors.midgray + } + if(this.state.hover) { + iconStyle.fill = colors.lowgray } switch(this.props.action) { case 'copy': return - case 'show': return + case 'show': return case 'hide': return case 'delete': return default: return null @@ -57,17 +65,18 @@ class IconAction extends React.Component { } render() { - return
this.setState({hover: true})} onMouseOut={e => this.setState({hover: false})} > {this.renderIcon()} -
+ } } @@ -77,18 +86,20 @@ class LayerListItem extends React.Component { layerId: React.PropTypes.string.isRequired, layerType: React.PropTypes.string.isRequired, isSelected: React.PropTypes.bool, - visibility: React.PropTypes.bool, + visibility: React.PropTypes.string, - onLayerSelected: React.PropTypes.func.isRequired, - onLayerDestroyed: React.PropTypes.func, - onLayerVisibilityToggled: React.PropTypes.func, + onLayerSelect: React.PropTypes.func.isRequired, + onLayerCopy: React.PropTypes.func, + onLayerDestroy: React.PropTypes.func, + onLayerVisibilityToggle: React.PropTypes.func, } static defaultProps = { isSelected: false, - visibility: true, - onLayerDestroyed: () => {}, - onLayerVisibilityToggled: () => {}, + visibility: 'visible', + onLayerCopy: () => {}, + onLayerDestroy: () => {}, + onLayerVisibilityToggle: () => {}, } static childContextTypes = { @@ -143,7 +154,7 @@ class LayerListItem extends React.Component { return
  • this.props.onLayerSelected(this.props.layerId)} + onClick={e => this.props.onLayerSelect(this.props.layerId)} onMouseOver={e => this.setState({hover: true})} onMouseOut={e => this.setState({hover: false})} style={itemStyle}> @@ -161,15 +172,16 @@ class LayerListItem extends React.Component { this.props.onLayerDestroyed(this.props.layerId)} + onClick={e => this.props.onLayerDestroy(this.props.layerId)} /> this.props.onLayerVisibilityToggled(this.props.layerId)} + onClick={e => this.props.onLayerCopy(this.props.layerId)} /> this.props.onLayerVisibilityToggled(this.props.layerId)} + active={this.state.hover || this.props.isSelected || this.props.visibility === 'none'} + action={this.props.visibility === 'visible' ? 'hide' : 'show'} + onClick={e => this.props.onLayerVisibilityToggle(this.props.layerId)} />
  • diff --git a/src/libs/style.js b/src/libs/style.js index 9d5b803..b865ae3 100644 --- a/src/libs/style.js +++ b/src/libs/style.js @@ -24,7 +24,17 @@ function ensureMetadataExists(style) { return ensureHasId(ensureHasTimestamp(style)) } +function indexOfLayer(layers, layerId) { + for (let i = 0; i < layers.length; i++) { + if(layers[i].id === layerId) { + return i + } + } + return null +} + export default { ensureMetadataExists, emptyStyle, + indexOfLayer, }