diff --git a/src/components/App.jsx b/src/components/App.jsx index 29d5305..e3ddf0d 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -10,6 +10,7 @@ import Toolbar from './Toolbar' import AppLayout from './AppLayout' import MessagePanel from './MessagePanel' +import { downloadGlyphsMetadata, downloadSpriteMetadata } from '../libs/metadata' import GlSpec from 'mapbox-gl-style-spec/reference/latest.js' import validateStyleMin from 'mapbox-gl-style-spec/lib/validate_style.min' import formatStyle from 'mapbox-gl-style-spec/lib/format' @@ -21,6 +22,18 @@ import { ApiStyleStore } from '../libs/apistore' import { RevisionStore } from '../libs/revisions' import LayerWatcher from '../libs/layerwatcher' +function updateRootSpec(spec, fieldName, newValues) { + return { + ...spec, + $root: { + ...spec.$root, + [fieldName]: { + ...spec.$root[fieldName], + values: newValues + } + } + } +} export default class App extends React.Component { constructor(props) { @@ -52,6 +65,7 @@ export default class App extends React.Component { sources: {}, vectorLayers: {}, inspectModeEnabled: false, + spec: GlSpec, } this.layerWatcher = new LayerWatcher({ @@ -85,7 +99,26 @@ export default class App extends React.Component { this.styleStore.save(snapshotStyle) } + updateFonts(urlTemplate) { + downloadGlyphsMetadata(urlTemplate, fonts => { + this.setState({ spec: updateRootSpec(this.state.spec, 'glyphs', fonts)}) + }) + } + + updateIcons(baseUrl) { + downloadSpriteMetadata(baseUrl, icons => { + this.setState({ spec: updateRootSpec(this.state.spec, 'sprite', icons)}) + }) + } + onStyleChanged(newStyle, save=true) { + if(newStyle.glyphs !== this.state.mapStyle.glyphs) { + this.updateFonts(newStyle.glyphs) + } + if(newStyle.sprite !== this.state.mapStyle.sprite) { + this.updateIcons(newStyle.sprite) + } + const errors = validateStyleMin(newStyle, GlSpec) if(errors.length === 0) { this.revisionStore.addRevision(newStyle) @@ -212,6 +245,7 @@ export default class App extends React.Component { layer={selectedLayer} sources={this.state.sources} vectorLayers={this.state.vectorLayers} + spec={this.state.spec} onLayerChanged={this.onLayerChanged.bind(this)} onLayerIdChange={this.onLayerIdChange.bind(this)} /> : null diff --git a/src/components/fields/PropertyGroup.jsx b/src/components/fields/PropertyGroup.jsx index 2a074b9..90b7b33 100644 --- a/src/components/fields/PropertyGroup.jsx +++ b/src/components/fields/PropertyGroup.jsx @@ -1,20 +1,34 @@ import React from 'react' -import GlSpec from 'mapbox-gl-style-spec/reference/latest.js' import ZoomSpecField from './ZoomSpecField' import colors from '../../config/colors' import { margins } from '../../config/scales' +const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image'] + /** Extract field spec by {@fieldName} from the {@layerType} in the * style specification from either the paint or layout group */ -function getFieldSpec(layerType, fieldName) { - const groupName = getGroupName(layerType, fieldName) - const group = GlSpec[groupName + '_' + layerType] - return group[fieldName] +function getFieldSpec(spec, layerType, fieldName) { + const groupName = getGroupName(spec, layerType, fieldName) + const group = spec[groupName + '_' + layerType] + const fieldSpec = group[fieldName] + if(iconProperties.indexOf(fieldName) >= 0) { + return { + ...fieldSpec, + values: spec.$root.sprite.values + } + } + if(fieldName === 'text-font') { + return { + ...fieldSpec, + values: spec.$root.glyphs.values + } + } + return fieldSpec } -function getGroupName(layerType, fieldName) { - const paint = GlSpec['paint_' + layerType] || {} +function getGroupName(spec, layerType, fieldName) { + const paint = spec['paint_' + layerType] || {} if (fieldName in paint) { return 'paint' } else { @@ -27,16 +41,17 @@ export default class PropertyGroup extends React.Component { layer: React.PropTypes.object.isRequired, groupFields: React.PropTypes.array.isRequired, onChange: React.PropTypes.func.isRequired, + spec: React.PropTypes.object.isRequired, } onPropertyChange(property, newValue) { - const group = getGroupName(this.props.layer.type, property) + const group = getGroupName(this.props.spec, this.props.layer.type, property) this.props.onChange(group , property, newValue) } render() { const fields = this.props.groupFields.map(fieldName => { - const fieldSpec = getFieldSpec(this.props.layer.type, fieldName) + const fieldSpec = getFieldSpec(this.props.spec, this.props.layer.type, fieldName) const paint = this.props.layer.paint || {} const layout = this.props.layer.layout || {} diff --git a/src/components/fields/SpecField.jsx b/src/components/fields/SpecField.jsx index 47e1c70..f51d43f 100644 --- a/src/components/fields/SpecField.jsx +++ b/src/components/fields/SpecField.jsx @@ -1,7 +1,6 @@ import React from 'react' import color from 'color' -import GlSpec from 'mapbox-gl-style-spec/reference/latest.min.js' import ColorField from './ColorField' import NumberInput from '../inputs/NumberInput' import CheckboxInput from '../inputs/CheckboxInput' @@ -10,8 +9,10 @@ import SelectInput from '../inputs/SelectInput' import MultiButtonInput from '../inputs/MultiButtonInput' import ArrayInput from '../inputs/ArrayInput' import FontInput from '../inputs/FontInput' +import IconInput from '../inputs/IconInput' import capitalize from 'lodash.capitalize' +const iconProperties = ['background-pattern', 'fill-pattern', 'line-pattern', 'fill-extrusion-pattern', 'icon-image'] import input from '../../config/input.js' @@ -78,11 +79,17 @@ export default class SpecField extends React.Component { options={options} /> } - case 'string': return ( - - ) + case 'string': + if(iconProperties.indexOf(this.props.fieldName) >= 0) { + return + } else { + return + } case 'color': return ( } else { return [f, f])} + options={this.props.fonts.map(f => [f, f])} onChange={this.changeFont.bind(this, i)} wrapperStyle={{ display: 'block', diff --git a/src/components/layers/LayerEditor.jsx b/src/components/layers/LayerEditor.jsx index 1897c02..138ef06 100644 --- a/src/components/layers/LayerEditor.jsx +++ b/src/components/layers/LayerEditor.jsx @@ -1,6 +1,5 @@ import React from 'react' -import GlSpec from 'mapbox-gl-style-spec/reference/latest.js' import JSONEditor from './JSONEditor' import FilterEditor from '../filter/FilterEditor' import PropertyGroup from '../fields/PropertyGroup' @@ -47,6 +46,7 @@ export default class LayerEditor extends React.Component { layer: React.PropTypes.object.isRequired, sources: React.PropTypes.object, vectorLayers: React.PropTypes.object, + spec: React.PropTypes.object.isRequired, onLayerChanged: React.PropTypes.func, onLayerIdChange: React.PropTypes.func, } @@ -146,6 +146,7 @@ export default class LayerEditor extends React.Component { case 'properties': return case 'jsoneditor': return