Added support for identity functions.

This commit is contained in:
orangemug 2020-04-12 16:25:32 +01:00
parent 8f722c59de
commit 7cfe0563bc
3 changed files with 176 additions and 106 deletions

View file

@ -6,12 +6,21 @@ import DataProperty from './_DataProperty'
import ZoomProperty from './_ZoomProperty'
import ExpressionProperty from './_ExpressionProperty'
import {function as styleFunction} from '@mapbox/mapbox-gl-style-spec';
import {findDefaultFromSpec} from '../util/spec-helper';
function isLiteralExpression (value) {
return (Array.isArray(value) && value.length === 2 && value[0] === "literal");
}
function isGetExpression (value) {
return (
Array.isArray(value) &&
value.length === 2 &&
value[0] === "get"
);
}
function isZoomField(value) {
return (
typeof(value) === 'object' &&
@ -28,7 +37,15 @@ function isZoomField(value) {
);
}
function isDataField(value) {
function isIdentityProperty (value) {
return (
typeof(value) === 'object' &&
value.type === "identity" &&
value.hasOwnProperty("property")
);
}
function isDataStopProperty (value) {
return (
typeof(value) === 'object' &&
value.stops &&
@ -45,6 +62,13 @@ function isDataField(value) {
);
}
function isDataField(value) {
return (
isIdentityProperty(value) ||
isDataStopProperty(value)
);
}
function isPrimative (value) {
const valid = ["string", "boolean", "number"];
return valid.includes(typeof(value));
@ -78,24 +102,6 @@ function getDataType (value, fieldSpec={}) {
}
}
/**
* If we don't have a default value just make one up
*/
function findDefaultFromSpec (spec) {
if (spec.hasOwnProperty('default')) {
return spec.default;
}
const defaults = {
'color': '#000000',
'string': '',
'boolean': false,
'number': 0,
'array': [],
}
return defaults[spec.type] || '';
}
/** Supports displaying spec field for zoom function objects
* https://www.mapbox.com/mapbox-gl-style-spec/#types-function-zoom-property
@ -206,7 +212,16 @@ export default class FunctionSpecProperty extends React.Component {
undoExpression = () => {
const {value, fieldName} = this.props;
if (isLiteralExpression(value)) {
if (isGetExpression(value)) {
this.props.onChange(fieldName, {
"type": "identity",
"property": value[1]
});
this.setState({
dataType: "value",
});
}
else if (isLiteralExpression(value)) {
this.props.onChange(fieldName, value[1]);
this.setState({
dataType: "value",
@ -217,6 +232,7 @@ export default class FunctionSpecProperty extends React.Component {
canUndo = () => {
const {value, fieldSpec} = this.props;
return (
isGetExpression(value) ||
isLiteralExpression(value) ||
isPrimative(value) ||
(Array.isArray(value) && fieldSpec.type === "array")
@ -230,6 +246,9 @@ export default class FunctionSpecProperty extends React.Component {
if (typeof(value) === "object" && 'stops' in value) {
expression = styleFunction.convertFunction(value, fieldSpec);
}
else if (isIdentityProperty(value)) {
expression = ["get", value.property];
}
else {
expression = ["literal", value || this.props.fieldSpec.default];
}

View file

@ -10,6 +10,7 @@ import DocLabel from './DocLabel'
import InputBlock from '../inputs/InputBlock'
import docUid from '../../libs/document-uid'
import sortNumerically from '../../libs/sort-numerically'
import {findDefaultFromSpec} from '../util/spec-helper';
import labelFromFieldName from './_labelFromFieldName'
import DeleteStopButton from './_DeleteStopButton'
@ -89,10 +90,10 @@ export default class DataProperty extends React.Component {
getDataFunctionTypes(fieldSpec) {
if (fieldSpec.expression.interpolated) {
return ["categorical", "interval", "exponential"]
return ["categorical", "interval", "exponential", "identity"]
}
else {
return ["categorical", "interval"]
return ["categorical", "interval", "identity"]
}
}
@ -122,6 +123,29 @@ export default class DataProperty extends React.Component {
return mappedWithRef.map((item) => item.data);
}
onChange = (fieldName, value) => {
if (value.type === "identity") {
value = {
type: value.type,
property: value.property,
};
}
else {
const stopValue = value.type === 'categorical' ? '' : 0;
value = {
property: "",
type: value.type,
// Default props if they don't already exist.
stops: [
[{zoom: 6, value: stopValue}, findDefaultFromSpec(this.props.fieldSpec)],
[{zoom: 10, value: stopValue}, findDefaultFromSpec(this.props.fieldSpec)]
],
...value,
}
}
this.props.onChange(fieldName, value);
}
changeStop(changeIdx, stopData, value) {
const stops = this.props.value.stops.slice(0)
const changedStop = stopData.zoom === undefined ? stopData.value : stopData
@ -133,7 +157,7 @@ export default class DataProperty extends React.Component {
...this.props.value,
stops: orderedStops,
}
this.props.onChange(this.props.fieldName, changedValue)
this.onChange(this.props.fieldName, changedValue)
}
changeDataProperty(propName, propVal) {
@ -143,7 +167,7 @@ export default class DataProperty extends React.Component {
else {
delete this.props.value[propName]
}
this.props.onChange(this.props.fieldName, this.props.value)
this.onChange(this.props.fieldName, this.props.value)
}
render() {
@ -153,7 +177,9 @@ export default class DataProperty extends React.Component {
this.props.value.type = this.getFieldFunctionType(this.props.fieldSpec)
}
const dataFields = this.props.value.stops.map((stop, idx) => {
let dataFields;
if (this.props.value.stops) {
dataFields = this.props.value.stops.map((stop, idx) => {
const zoomLevel = typeof stop[0] === 'object' ? stop[0].zoom : undefined;
const key = this.state.refs[idx];
const dataLevel = typeof stop[0] === 'object' ? stop[0].value : stop[0];
@ -216,6 +242,7 @@ export default class DataProperty extends React.Component {
</div>
</InputBlock>
})
}
return <div className="maputnik-data-spec-block">
<div className="maputnik-data-spec-property">
@ -223,18 +250,6 @@ export default class DataProperty extends React.Component {
fieldSpec={this.props.fieldSpec}
label={labelFromFieldName(this.props.fieldName)}
>
<div className="maputnik-data-spec-property-group">
<DocLabel
label="Property"
/>
<div className="maputnik-data-spec-property-input">
<StringInput
value={this.props.value.property}
title={"Input a data property to base styles off of."}
onChange={propVal => this.changeDataProperty("property", propVal)}
/>
</div>
</div>
<div className="maputnik-data-spec-property-group">
<DocLabel
label="Type"
@ -248,6 +263,19 @@ export default class DataProperty extends React.Component {
/>
</div>
</div>
<div className="maputnik-data-spec-property-group">
<DocLabel
label="Property"
/>
<div className="maputnik-data-spec-property-input">
<StringInput
value={this.props.value.property}
title={"Input a data property to base styles off of."}
onChange={propVal => this.changeDataProperty("property", propVal)}
/>
</div>
</div>
{dataFields &&
<div className="maputnik-data-spec-property-group">
<DocLabel
label="Default"
@ -261,8 +289,11 @@ export default class DataProperty extends React.Component {
/>
</div>
</div>
}
</InputBlock>
</div>
{dataFields &&
<>
{dataFields}
<Button
className="maputnik-add-stop"
@ -270,6 +301,8 @@ export default class DataProperty extends React.Component {
>
Add stop
</Button>
</>
}
<Button
className="maputnik-add-stop"
onClick={this.props.onExpressionClick.bind(this)}

View file

@ -0,0 +1,18 @@
/**
* If we don't have a default value just make one up
*/
export function findDefaultFromSpec (spec) {
if (spec.hasOwnProperty('default')) {
return spec.default;
}
const defaults = {
'color': '#000000',
'string': '',
'boolean': false,
'number': 0,
'array': [],
}
return defaults[spec.type] || '';
}