From 030d469d7c182fdd7503671dbe01fa698521b66f Mon Sep 17 00:00:00 2001 From: orangemug Date: Fri, 17 Nov 2017 17:17:53 +0000 Subject: [PATCH] Broke into smaller parts. --- src/components/fields/FunctionSpecField.jsx | 385 ++----------------- src/components/fields/_DataProperty.jsx | 171 ++++++++ src/components/fields/_DeleteStopButton.jsx | 25 ++ src/components/fields/_FunctionButtons.jsx | 49 +++ src/components/fields/_SpecProperty.jsx | 32 ++ src/components/fields/_ZoomProperty.jsx | 149 +++++++ src/components/fields/_labelFromFieldName.js | 6 + src/components/inputs/InputBlock.jsx | 2 +- 8 files changed, 470 insertions(+), 349 deletions(-) create mode 100644 src/components/fields/_DataProperty.jsx create mode 100644 src/components/fields/_DeleteStopButton.jsx create mode 100644 src/components/fields/_FunctionButtons.jsx create mode 100644 src/components/fields/_SpecProperty.jsx create mode 100644 src/components/fields/_ZoomProperty.jsx create mode 100644 src/components/fields/_labelFromFieldName.js diff --git a/src/components/fields/FunctionSpecField.jsx b/src/components/fields/FunctionSpecField.jsx index d074c892..9772a33d 100644 --- a/src/components/fields/FunctionSpecField.jsx +++ b/src/components/fields/FunctionSpecField.jsx @@ -1,24 +1,10 @@ import React from 'react' -import Color from 'color' - -import Button from '../Button' -import SpecField from './SpecField' -import NumberInput from '../inputs/NumberInput' -import StringInput from '../inputs/StringInput' -import SelectInput from '../inputs/SelectInput' -import DocLabel from './DocLabel' -import InputBlock from '../inputs/InputBlock' - -import AddIcon from 'react-icons/lib/md/add-circle-outline' -import DeleteIcon from 'react-icons/lib/md/delete' -import FunctionIcon from 'react-icons/lib/md/functions' -import MdInsertChart from 'react-icons/lib/md/insert-chart' - import PropTypes from 'prop-types' -import capitalize from 'lodash.capitalize' -import docUid from '../../libs/document-uid' -import sortNumerically from '../../libs/sort-numerically' +import SpecProperty from './_SpecProperty' +import DataProperty from './_DataProperty' +import ZoomProperty from './_ZoomProperty' + function isZoomField(value) { return typeof value === 'object' && value.stops && typeof value.property === 'undefined' @@ -46,70 +32,6 @@ export default class FunctionSpecProperty extends React.Component { ]), } - constructor() { - super() - this.state = { - refs: {} - } - } - - /** - * We cache a reference for each stop by its index. - * - * When the stops are reordered the references are also updated (see this.orderStops) this allows React to use the same key for the element and keep keyboard focus. - */ - setStopRefs(props) { - // This is initialsed below only if required to improved performance. - let newRefs; - - if(props.value && props.value.stops) { - props.value.stops.forEach((val, idx) => { - if(!this.state.refs.hasOwnProperty(idx)) { - if(!newRefs) { - newRefs = {...this.state.refs}; - } - newRefs[idx] = docUid("stop-"); - } - }) - } - - if(newRefs) { - this.setState({ - refs: newRefs - }) - } - } - - componentWillReceiveProps(nextProps) { - this.setStopRefs(nextProps); - } - - // Order the stops altering the refs to reflect their new position. - orderStopsByZoom(stops) { - const mappedWithRef = stops - .map((stop, idx) => { - return { - ref: this.state.refs[idx], - data: stop - } - }) - // Sort by zoom - .sort((a, b) => sortNumerically(a.data[0], b.data[0])); - - // Fetch the new position of the stops - const newRefs = {}; - mappedWithRef - .forEach((stop, idx) =>{ - newRefs[idx] = stop.ref; - }) - - this.setState({ - refs: newRefs - }); - - return mappedWithRef.map((item) => item.data); - } - addStop() { const stops = this.props.value.stops.slice(0) const lastStop = stops[stops.length - 1] @@ -157,25 +79,6 @@ export default class FunctionSpecProperty extends React.Component { this.props.onChange(this.props.fieldName, zoomFunc) } - getFieldFunctionType(fieldSpec) { - if (fieldSpec.function === "interpolated") { - return "exponential" - } - if (fieldSpec.type === "number") { - return "interval" - } - return "categorical" - } - - getDataFunctionTypes(functionType) { - if (functionType === "interpolated") { - return ["categorical", "interval", "exponential"] - } - else { - return ["categorical", "interval"] - } - } - makeDataFunction() { const dataFunc = { property: "", @@ -188,264 +91,50 @@ export default class FunctionSpecProperty extends React.Component { this.props.onChange(this.props.fieldName, dataFunc) } - changeStop(changeIdx, stopData, value) { - const stops = this.props.value.stops.slice(0); - stops[changeIdx] = [stopData, value]; - - const orderedStops = this.orderStopsByZoom(stops); - - const changedValue = { - ...this.props.value, - stops: orderedStops - } - this.props.onChange(this.props.fieldName, changedValue) - } - - changeDataProperty(propName, propVal) { - if (propVal) { - this.props.value[propName] = propVal - } - else { - delete this.props.value[propName] - } - this.props.onChange(this.props.fieldName, this.props.value) - } - - renderDataProperty() { - if (typeof this.props.value.type === "undefined") { - this.props.value.type = this.getFieldFunctionType(this.props.fieldSpec) - } - const dataFields = this.props.value.stops.map((stop, idx) => { - const zoomLevel = stop[0].zoom - const dataLevel = stop[0].value - const value = stop[1] - const deleteStopBtn = - - const dataProps = { - label: "Data value", - value: dataLevel, - onChange: newData => this.changeStop(idx, { zoom: zoomLevel, value: newData }, value) - } - const dataInput = this.props.value.type === "categorical" ? : - - return -
- this.changeStop(idx, {zoom: newZoom, value: dataLevel}, value)} - min={0} - max={22} - /> -
-
- {dataInput} -
-
- this.changeStop(idx, {zoom: zoomLevel, value: dataLevel}, newValue)} - /> -
-
- }) - - return
-
- -
- -
- this.changeDataProperty("property", propVal)} - /> -
-
-
- -
- this.changeDataProperty("type", propVal)} - options={this.getDataFunctionTypes(this.props.fieldSpec.function)} - /> -
-
-
- -
- this.changeDataProperty("default", propVal)} - /> -
-
-
-
- {dataFields} - -
- } - - renderZoomProperty() { - const zoomFields = this.props.value.stops.map((stop, idx) => { - const zoomLevel = stop[0] - const key = this.state.refs[idx]; - const value = stop[1] - const deleteStopBtn= - - return -
-
- this.changeStop(idx, changedStop, value)} - min={0} - max={22} - /> -
-
- this.changeStop(idx, zoomLevel, newValue)} - /> -
-
-
- }) - - return
- {zoomFields} - -
- } - - renderProperty() { - const functionBtn = - return - - - } - render() { const propClass = this.props.fieldSpec.default === this.props.value ? "maputnik-default-property" : "maputnik-modified-property" - let specField + let specField; + if (isZoomField(this.props.value)) { - specField = this.renderZoomProperty() + specField = ( + + ) } else if (isDataField(this.props.value)) { - specField = this.renderDataProperty() + specField = ( + + ) } else { - specField = this.renderProperty() + specField = ( + + ) } + return
{specField}
} } -class MakeFunctionButtons extends React.Component { - static propTypes = { - fieldSpec: PropTypes.object, - onZoomClick: PropTypes.func, - onDataClick: PropTypes.func, - } - - render() { - let makeZoomButton, makeDataButton - if (this.props.fieldSpec['zoom-function']) { - makeZoomButton = - - if (this.props.fieldSpec['property-function'] && ['piecewise-constant', 'interpolated'].indexOf(this.props.fieldSpec['function']) !== -1) { - makeDataButton = - } - return
{makeDataButton}{makeZoomButton}
- } - else { - return null - } - } -} - -class DeleteStopButton extends React.Component { - static propTypes = { - onClick: PropTypes.func, - } - - render() { - return - } -} - -function labelFromFieldName(fieldName) { - let label = fieldName.split('-').slice(1).join(' ') - return capitalize(label) -} diff --git a/src/components/fields/_DataProperty.jsx b/src/components/fields/_DataProperty.jsx new file mode 100644 index 00000000..c13d8285 --- /dev/null +++ b/src/components/fields/_DataProperty.jsx @@ -0,0 +1,171 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import Button from '../Button' +import SpecField from './SpecField' +import NumberInput from '../inputs/NumberInput' +import StringInput from '../inputs/StringInput' +import SelectInput from '../inputs/SelectInput' +import DocLabel from './DocLabel' +import InputBlock from '../inputs/InputBlock' + +import labelFromFieldName from './_labelFromFieldName' +import DeleteStopButton from './_DeleteStopButton' + + +export default class DataProperty extends React.Component { + static propTypes = { + value: PropTypes.oneOfType([ + PropTypes.object, + PropTypes.string, + PropTypes.number, + PropTypes.bool, + PropTypes.array + ]), + } + + getFieldFunctionType(fieldSpec) { + if (fieldSpec.function === "interpolated") { + return "exponential" + } + if (fieldSpec.type === "number") { + return "interval" + } + return "categorical" + } + + getDataFunctionTypes(functionType) { + if (functionType === "interpolated") { + return ["categorical", "interval", "exponential"] + } + else { + return ["categorical", "interval"] + } + } + + + changeStop(changeIdx, stopData, value) { + const stops = this.props.value.stops.slice(0) + stops[changeIdx] = [stopData, value] + const changedValue = { + ...this.props.value, + stops: stops, + } + this.props.onChange(this.props.fieldName, changedValue) + } + + changeDataProperty(propName, propVal) { + if (propVal) { + this.props.value[propName] = propVal + } + else { + delete this.props.value[propName] + } + this.props.onChange(this.props.fieldName, this.props.value) + } + + render() { + if (typeof this.props.value.type === "undefined") { + this.props.value.type = this.getFieldFunctionType(this.props.fieldSpec) + } + + const dataFields = this.props.value.stops.map((stop, idx) => { + const zoomLevel = stop[0].zoom + const dataLevel = stop[0].value + const value = stop[1] + const deleteStopBtn = + + const dataProps = { + label: "Data value", + value: dataLevel, + onChange: newData => this.changeStop(idx, { zoom: zoomLevel, value: newData }, value) + } + + let dataInput; + if(this.props.value.type === "categorical") { + dataInput = + } + else { + dataInput = + } + + return +
+ this.changeStop(idx, {zoom: newZoom, value: dataLevel}, value)} + min={0} + max={22} + /> +
+
+ {dataInput} +
+
+ this.changeStop(idx, {zoom: zoomLevel, value: dataLevel}, newValue)} + /> +
+
+ }) + + return
+
+ +
+ +
+ this.changeDataProperty("property", propVal)} + /> +
+
+
+ +
+ this.changeDataProperty("type", propVal)} + options={this.getDataFunctionTypes(this.props.fieldSpec.function)} + /> +
+
+
+ +
+ this.changeDataProperty("default", propVal)} + /> +
+
+
+
+ {dataFields} + +
+ } +} diff --git a/src/components/fields/_DeleteStopButton.jsx b/src/components/fields/_DeleteStopButton.jsx new file mode 100644 index 00000000..ef64f434 --- /dev/null +++ b/src/components/fields/_DeleteStopButton.jsx @@ -0,0 +1,25 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import DocLabel from './DocLabel' +import Button from '../Button' +import DeleteIcon from 'react-icons/lib/md/delete' + + +export default class DeleteStopButton extends React.Component { + static propTypes = { + onClick: PropTypes.func, + } + + render() { + return + } +} diff --git a/src/components/fields/_FunctionButtons.jsx b/src/components/fields/_FunctionButtons.jsx new file mode 100644 index 00000000..9e663985 --- /dev/null +++ b/src/components/fields/_FunctionButtons.jsx @@ -0,0 +1,49 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import DocLabel from './DocLabel' +import Button from '../Button' +import FunctionIcon from 'react-icons/lib/md/functions' +import MdInsertChart from 'react-icons/lib/md/insert-chart' + + +export default class FunctionButtons extends React.Component { + static propTypes = { + fieldSpec: PropTypes.object, + onZoomClick: PropTypes.func, + onDataClick: PropTypes.func, + } + + render() { + let makeZoomButton, makeDataButton + if (this.props.fieldSpec['zoom-function']) { + makeZoomButton = + + if (this.props.fieldSpec['property-function'] && ['piecewise-constant', 'interpolated'].indexOf(this.props.fieldSpec['function']) !== -1) { + makeDataButton = + } + return
{makeDataButton}{makeZoomButton}
+ } + else { + return null + } + } +} diff --git a/src/components/fields/_SpecProperty.jsx b/src/components/fields/_SpecProperty.jsx new file mode 100644 index 00000000..583bffa7 --- /dev/null +++ b/src/components/fields/_SpecProperty.jsx @@ -0,0 +1,32 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import SpecField from './SpecField' +import FunctionButtons from './_FunctionButtons' +import InputBlock from '../inputs/InputBlock' + +import labelFromFieldName from './_labelFromFieldName' + + +export default class SpecProperty extends React.Component { + static propTypes = { + onZoomClick: PropTypes.func.isRequired, + onDataClick: PropTypes.func.isRequired + } + + render() { + const functionBtn = + + return + + + } +} diff --git a/src/components/fields/_ZoomProperty.jsx b/src/components/fields/_ZoomProperty.jsx new file mode 100644 index 00000000..e670af38 --- /dev/null +++ b/src/components/fields/_ZoomProperty.jsx @@ -0,0 +1,149 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import Button from '../Button' +import SpecField from './SpecField' +import NumberInput from '../inputs/NumberInput' +import InputBlock from '../inputs/InputBlock' + +import DeleteStopButton from './_DeleteStopButton' +import labelFromFieldName from './_labelFromFieldName' + +import docUid from '../../libs/document-uid' +import sortNumerically from '../../libs/sort-numerically' + + +export default class ZoomProperty extends React.Component { + static propTypes = { + } + + + constructor() { + super() + this.state = { + refs: {} + } + } + + componentWillMount() { + this.setState({ + refs: this.setStopRefs(this.props) + }) + } + + /** + * We cache a reference for each stop by its index. + * + * When the stops are reordered the references are also updated (see this.orderStops) this allows React to use the same key for the element and keep keyboard focus. + */ + setStopRefs(props) { + // This is initialsed below only if required to improved performance. + let newRefs; + + if(props.value && props.value.stops) { + props.value.stops.forEach((val, idx) => { + if(!this.state.refs.hasOwnProperty(idx)) { + if(!newRefs) { + newRefs = {...this.state.refs}; + } + newRefs[idx] = docUid("stop-"); + } + }) + } + + return newRefs; + } + + componentWillReceiveProps(nextProps) { + const newRefs = this.setStopRefs(nextProps); + if(newRefs) { + this.setState({ + refs: newRefs + }) + } + } + + // Order the stops altering the refs to reflect their new position. + orderStopsByZoom(stops) { + const mappedWithRef = stops + .map((stop, idx) => { + return { + ref: this.state.refs[idx], + data: stop + } + }) + // Sort by zoom + .sort((a, b) => sortNumerically(a.data[0], b.data[0])); + + // Fetch the new position of the stops + const newRefs = {}; + mappedWithRef + .forEach((stop, idx) =>{ + newRefs[idx] = stop.ref; + }) + + this.setState({ + refs: newRefs + }); + + return mappedWithRef.map((item) => item.data); + } + + changeZoomStop(changeIdx, stopData, value) { + const stops = this.props.value.stops.slice(0); + stops[changeIdx] = [stopData, value]; + + const orderedStops = this.orderStopsByZoom(stops); + + const changedValue = { + ...this.props.value, + stops: orderedStops + } + this.props.onChange(this.props.fieldName, changedValue) + } + + render() { + const zoomFields = this.props.value.stops.map((stop, idx) => { + const zoomLevel = stop[0] + const key = this.state.refs[idx]; + const value = stop[1] + const deleteStopBtn= + + return +
+
+ this.changeZoomStop(idx, changedStop, value)} + min={0} + max={22} + /> +
+
+ this.changeZoomStop(idx, zoomLevel, newValue)} + /> +
+
+
+ }); + + return
+ {zoomFields} + +
+ } +} diff --git a/src/components/fields/_labelFromFieldName.js b/src/components/fields/_labelFromFieldName.js new file mode 100644 index 00000000..fea405f6 --- /dev/null +++ b/src/components/fields/_labelFromFieldName.js @@ -0,0 +1,6 @@ +import capitalize from 'lodash.capitalize' + +export default function labelFromFieldName(fieldName) { + let label = fieldName.split('-').slice(1).join(' ') + return capitalize(label) +} diff --git a/src/components/inputs/InputBlock.jsx b/src/components/inputs/InputBlock.jsx index 37c1d0ab..8fff7670 100644 --- a/src/components/inputs/InputBlock.jsx +++ b/src/components/inputs/InputBlock.jsx @@ -12,7 +12,7 @@ class InputBlock extends React.Component { ]).isRequired, doc: PropTypes.string, action: PropTypes.element, - children: PropTypes.element.isRequired, + children: PropTypes.node.isRequired, style: PropTypes.object, onChange: PropTypes.func, }