2016-09-12 19:44:28 +02:00
|
|
|
import React from 'react'
|
|
|
|
import Immutable from 'immutable'
|
2016-12-17 17:40:44 +01:00
|
|
|
import color from 'color'
|
|
|
|
|
2016-09-12 19:44:28 +02:00
|
|
|
import GlSpec from 'mapbox-gl-style-spec/reference/latest.min.js'
|
|
|
|
import NumberField from './number'
|
|
|
|
import EnumField from './enum'
|
2016-12-18 20:08:20 +01:00
|
|
|
import BooleanField from './boolean'
|
2016-09-12 19:47:28 +02:00
|
|
|
import ColorField from './color'
|
2016-09-12 19:54:02 +02:00
|
|
|
import StringField from './string'
|
2016-12-17 17:40:44 +01:00
|
|
|
import inputStyle from './input.js'
|
|
|
|
import theme from '../theme.js'
|
2016-09-12 19:44:28 +02:00
|
|
|
|
2016-12-17 17:40:44 +01:00
|
|
|
function isZoomField(value) {
|
|
|
|
return Immutable.Map.isMap(value)
|
|
|
|
}
|
|
|
|
|
|
|
|
const specFieldProps = {
|
|
|
|
onChange: React.PropTypes.func.isRequired,
|
|
|
|
fieldName: React.PropTypes.string.isRequired,
|
|
|
|
fieldSpec: React.PropTypes.object.isRequired,
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Supports displaying spec field for zoom function objects
|
|
|
|
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
|
|
|
|
*/
|
|
|
|
class ZoomSpecField extends React.Component {
|
|
|
|
static propTypes = {
|
|
|
|
...specFieldProps,
|
|
|
|
value: React.PropTypes.oneOfType([
|
2016-09-12 19:44:28 +02:00
|
|
|
React.PropTypes.object,
|
|
|
|
React.PropTypes.string,
|
|
|
|
React.PropTypes.number,
|
2016-12-18 20:08:20 +01:00
|
|
|
React.PropTypes.bool,
|
2016-12-17 17:40:44 +01:00
|
|
|
]),
|
2016-09-12 19:44:28 +02:00
|
|
|
}
|
|
|
|
|
2016-12-17 17:40:44 +01:00
|
|
|
render() {
|
|
|
|
if(isZoomField(this.props.value)) {
|
|
|
|
const zoomFields = this.props.value.get('stops').map(stop => {
|
|
|
|
const zoomLevel = stop.get(0)
|
|
|
|
const value = stop.get(1)
|
2016-09-12 20:10:49 +02:00
|
|
|
|
2016-12-17 17:40:44 +01:00
|
|
|
return <div key={zoomLevel}>
|
|
|
|
<b><span style={inputStyle.label}>Zoom Level {zoomLevel}</span></b>
|
|
|
|
<SpecField {...this.props} value={value} />
|
|
|
|
</div>
|
|
|
|
}).toSeq()
|
|
|
|
return <div style={{
|
|
|
|
border: 1,
|
|
|
|
borderStyle: 'solid',
|
2016-12-19 15:09:03 +01:00
|
|
|
borderColor: color(theme.colors.gray).lighten(0.1).string(),
|
2016-12-17 17:40:44 +01:00
|
|
|
padding: theme.scale[1],
|
|
|
|
}}>
|
|
|
|
{zoomFields}
|
|
|
|
</div>
|
|
|
|
} else {
|
|
|
|
return <SpecField {...this.props} />
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-17 20:36:43 +01:00
|
|
|
function labelFromFieldName(fieldName) {
|
|
|
|
let label = fieldName.split('-').slice(1).join(' ')
|
|
|
|
if(label.length > 0) {
|
|
|
|
label = label.charAt(0).toUpperCase() + label.slice(1);
|
|
|
|
}
|
|
|
|
return label
|
|
|
|
}
|
|
|
|
|
2016-12-17 17:40:44 +01:00
|
|
|
/** Display any field from the Mapbox GL style spec and
|
|
|
|
* choose the correct field component based on the @{fieldSpec}
|
|
|
|
* to display @{value}. */
|
|
|
|
class SpecField extends React.Component {
|
|
|
|
static propTypes = {
|
|
|
|
...specFieldProps,
|
|
|
|
value: React.PropTypes.oneOfType([
|
|
|
|
React.PropTypes.string,
|
|
|
|
React.PropTypes.number,
|
|
|
|
]),
|
|
|
|
}
|
|
|
|
|
|
|
|
onValueChanged(property, value) {
|
|
|
|
return this.props.onChange(property, value)
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2016-12-17 20:36:43 +01:00
|
|
|
const label = labelFromFieldName(this.props.fieldName)
|
2016-12-17 17:40:44 +01:00
|
|
|
switch(this.props.fieldSpec.type) {
|
|
|
|
case 'number': return (
|
|
|
|
<NumberField
|
|
|
|
onChange={this.onValueChanged.bind(this, this.props.fieldName)}
|
|
|
|
value={this.props.value}
|
2016-12-17 20:36:43 +01:00
|
|
|
name={label}
|
2016-12-17 17:40:44 +01:00
|
|
|
default={this.props.fieldSpec.default}
|
|
|
|
min={this.props.fieldSpec.min}
|
|
|
|
max={this.props.fieldSpec.max}
|
|
|
|
unit={this.props.fieldSpec.unit}
|
|
|
|
doc={this.props.fieldSpec.doc}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
case 'enum': return (
|
|
|
|
<EnumField
|
|
|
|
onChange={this.onValueChanged.bind(this, this.props.fieldName)}
|
|
|
|
value={this.props.value}
|
2016-12-17 20:36:43 +01:00
|
|
|
name={label}
|
2016-12-19 12:59:04 +01:00
|
|
|
allowedValues={Object.keys(this.props.fieldSpec.values)}
|
2016-12-17 17:40:44 +01:00
|
|
|
doc={this.props.fieldSpec.doc}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
case 'string': return (
|
|
|
|
<StringField
|
|
|
|
onChange={this.onValueChanged.bind(this, this.props.fieldName)}
|
|
|
|
value={this.props.value}
|
2016-12-17 20:36:43 +01:00
|
|
|
name={label}
|
2016-12-17 17:40:44 +01:00
|
|
|
doc={this.props.fieldSpec.doc}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
case 'color': return (
|
|
|
|
<ColorField
|
|
|
|
onChange={this.onValueChanged.bind(this, this.props.fieldName)}
|
|
|
|
value={this.props.value}
|
2016-12-17 20:36:43 +01:00
|
|
|
name={label}
|
2016-12-18 20:08:20 +01:00
|
|
|
doc={this.props.fieldSpec.doc}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
case 'boolean': return (
|
|
|
|
<BooleanField
|
|
|
|
onChange={this.onValueChanged.bind(this, this.props.fieldName)}
|
|
|
|
value={this.props.value}
|
|
|
|
name={label}
|
2016-12-17 17:40:44 +01:00
|
|
|
doc={this.props.fieldSpec.doc}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
default: return null
|
|
|
|
}
|
|
|
|
}
|
2016-09-12 19:44:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export class PropertyGroup extends React.Component {
|
2016-12-17 17:40:44 +01:00
|
|
|
static propTypes = {
|
2016-09-12 20:10:49 +02:00
|
|
|
onChange: React.PropTypes.func.isRequired,
|
2016-12-17 17:40:44 +01:00
|
|
|
properties: React.PropTypes.instanceOf(Immutable.Map).isRequired,
|
|
|
|
layerType: React.PropTypes.oneOf(['fill', 'background', 'line', 'symbol']).isRequired,
|
|
|
|
groupType: React.PropTypes.oneOf(['paint', 'layout']).isRequired,
|
2016-09-12 19:44:28 +02:00
|
|
|
}
|
|
|
|
|
2016-12-17 17:40:44 +01:00
|
|
|
render() {
|
|
|
|
const layerTypeSpec = GlSpec[this.props.groupType + "_" + this.props.layerType]
|
2016-12-17 20:36:43 +01:00
|
|
|
const specFields = Object.keys(layerTypeSpec).filter(propName => propName !== 'visibility').map(propName => {
|
2016-12-17 17:40:44 +01:00
|
|
|
const fieldSpec = layerTypeSpec[propName]
|
|
|
|
const propValue = this.props.properties.get(propName)
|
|
|
|
return <ZoomSpecField
|
|
|
|
onChange={this.props.onChange}
|
|
|
|
key={propName}
|
|
|
|
value={propValue}
|
|
|
|
fieldName={propName}
|
|
|
|
fieldSpec={fieldSpec}
|
|
|
|
/>
|
|
|
|
})
|
|
|
|
return <div>
|
|
|
|
{specFields}
|
|
|
|
</div>
|
|
|
|
}
|
2016-09-12 19:44:28 +02:00
|
|
|
}
|