diff --git a/examples/simple/src/App.js b/examples/simple/src/App.js index 0e2789476..5cd3f80f0 100644 --- a/examples/simple/src/App.js +++ b/examples/simple/src/App.js @@ -24,7 +24,7 @@ class App extends Component { // overwritten with a full DOM node that contains data, layout, _fullData, // _fullLayout etc in handlePlotUpdate() const graphDiv = { - data: [{type: 'scatter', xsrc: 'col1', ysrc: 'col2'}], + data: [{type: 'scatter', xsrc: 'col1', ysrc: 'col2', mode: 'markers'}], layout: {title: 'Room readings'}, }; diff --git a/package.json b/package.json index 8d5bc65f2..51b15cbb4 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "raf": "^3.4.0", "react-color": "^2.13.8", "react-select": "^1.0.0-rc.10", + "react-tabs": "^2.0.0", "tinycolor2": "^1.4.1" }, "browserify-global-shim": { diff --git a/src/DefaultEditor.js b/src/DefaultEditor.js index 461310717..32ca03b95 100644 --- a/src/DefaultEditor.js +++ b/src/DefaultEditor.js @@ -74,7 +74,7 @@ class DefaultEditor extends Component { - +
diff --git a/src/PlotlyEditor.js b/src/PlotlyEditor.js index 080072870..88f676170 100644 --- a/src/PlotlyEditor.js +++ b/src/PlotlyEditor.js @@ -93,7 +93,7 @@ class PlotlyEditor extends Component { if (this.props.onAddTrace) { this.props.onAddTrace(payload); } - graphDiv.data.push({x: [], y: []}); + graphDiv.data.push({x: [], y: [], type: 'scatter', mode: 'markers'}); if (this.props.onUpdate) { this.props.onUpdate(); } diff --git a/src/components/containers/TraceAccordion.js b/src/components/containers/TraceAccordion.js index 15eccf125..854c13dbb 100644 --- a/src/components/containers/TraceAccordion.js +++ b/src/components/containers/TraceAccordion.js @@ -2,14 +2,14 @@ import Fold from './Fold'; import PropTypes from 'prop-types'; import React, {Component} from 'react'; import {EDITOR_ACTIONS} from '../../lib/constants'; -import {connectTraceToPlot} from '../../lib'; +import {connectTraceToPlot, plotlyToCustom} from '../../lib'; +import {Tab, Tabs, TabList, TabPanel} from 'react-tabs'; const TraceFold = connectTraceToPlot(Fold); export default class TraceAccordion extends Component { constructor(props) { super(props); - this.addTrace = this.addTrace.bind(this); } @@ -23,24 +23,69 @@ export default class TraceAccordion extends Component { render() { const data = this.context.data || []; + const fullData = this.context.fullData || []; + const {canGroup, canAdd} = this.props; + const individualPanel = data.map((d, i) => ( + + {this.props.children} + + )); + let content = individualPanel; + + if (canGroup && data.length > 1) { + const groupedTraces = data.reduce((allTraces, next, index) => { + const traceType = plotlyToCustom( + fullData.filter(trace => trace.index === index)[0] + ); + if (allTraces[traceType]) { + allTraces[traceType].push(index); + } else { + allTraces[traceType] = [index]; + } + return allTraces; + }, {}); + + const groupedPanel = Object.keys(groupedTraces).map( + (traceType, index) => { + return ( + + {this.props.children} + + ); + } + ); + + content = ( + + + Grouped + Individual + + {groupedPanel} + {individualPanel} + + ); + } + return (
- {this.props.canAdd ? ( + {canAdd ? ( ) : null} - {data.map((d, i) => ( - - {this.props.children} - - ))} + {content}
); } } TraceAccordion.contextTypes = { + fullData: PropTypes.array, data: PropTypes.array, onUpdate: PropTypes.func, }; @@ -48,4 +93,5 @@ TraceAccordion.contextTypes = { TraceAccordion.propTypes = { children: PropTypes.node, canAdd: PropTypes.bool, + canGroup: PropTypes.bool, }; diff --git a/src/components/fields/Field.js b/src/components/fields/Field.js index e4df74e71..5464c5fd5 100644 --- a/src/components/fields/Field.js +++ b/src/components/fields/Field.js @@ -6,17 +6,6 @@ import {bem, localize} from '../../lib'; import {getMultiValueText} from '../../lib/constants'; class Field extends Component { - renderPostfix() { - if (!this.props.units) { - return null; - } - return ( -
-
{this.props.units}
-
- ); - } - render() { const { center, diff --git a/src/components/fields/TraceSelector.js b/src/components/fields/TraceSelector.js index 02336222e..f002b4e9a 100644 --- a/src/components/fields/TraceSelector.js +++ b/src/components/fields/TraceSelector.js @@ -1,8 +1,7 @@ import {UnconnectedDropdown} from './Dropdown'; import PropTypes from 'prop-types'; import React, {Component} from 'react'; -import nestedProperty from 'plotly.js/src/lib/nested_property'; -import {connectToContainer} from '../../lib'; +import {connectToContainer, customToPlotly, plotlyToCustom} from '../../lib'; function computeTraceOptionsFromSchema(schema) { const capitalize = s => s.charAt(0).toUpperCase() + s.substring(1); @@ -62,18 +61,7 @@ class TraceSelector extends Component { this.traceOptions = [{label: 'Scatter', value: 'scatter'}]; } - // If we used fullData mode or fill it may be undefined if the fullTrace - // is not visible and therefore does not have these values computed. - const mode = nestedProperty(props.container, 'mode').get(); - const fill = nestedProperty(props.container, 'fill').get(); - const fullValue = props.fullValue; - if (fullValue === 'scatter' && this.fillTypes.includes(fill)) { - this.fullValue = 'area'; - } else if (fullValue === 'scatter' && mode === 'lines') { - this.fullValue = 'line'; - } else { - this.fullValue = fullValue; - } + this.fullValue = plotlyToCustom(props.fullContainer); } componentWillReceiveProps(nextProps, nextContext) { @@ -81,16 +69,7 @@ class TraceSelector extends Component { } updatePlot(value) { - let update; - if (value === 'line') { - update = {type: 'scatter', mode: 'lines', fill: 'none'}; - } else if (value === 'scatter') { - update = {type: 'scatter', mode: 'markers', fill: 'none'}; - } else if (value === 'area') { - update = {type: 'scatter', fill: 'tozeroy'}; - } else { - update = {type: value}; - } + const update = customToPlotly(value); if (this.props.updateContainer) { this.props.updateContainer(update); @@ -114,7 +93,7 @@ TraceSelector.contextTypes = { TraceSelector.propTypes = { getValObject: PropTypes.func, - container: PropTypes.object.isRequired, + fullContainer: PropTypes.object.isRequired, fullValue: PropTypes.any.isRequired, updateContainer: PropTypes.func, }; diff --git a/src/lib/connectTraceToPlot.js b/src/lib/connectTraceToPlot.js index 536081dad..4d002e66f 100644 --- a/src/lib/connectTraceToPlot.js +++ b/src/lib/connectTraceToPlot.js @@ -19,11 +19,14 @@ export default function connectTraceToPlot(WrappedComponent) { } setLocals(props, context) { - const {traceIndex} = props; + const {traceIndexes} = props; const {data, fullData, plotly} = context; - const trace = data[traceIndex] || {}; - const fullTraceIndex = findFullTraceIndex(fullData, traceIndex); + const trace = traceIndexes.length === 1 ? data[traceIndexes[0]] : {}; + const fullTraceIndex = + traceIndexes.length === 1 + ? findFullTraceIndex(fullData, traceIndexes[0]) + : findFullTraceIndex(fullData, 0); const fullTrace = fullData[fullTraceIndex] || {}; let getValObject; @@ -55,7 +58,7 @@ export default function connectTraceToPlot(WrappedComponent) { type: EDITOR_ACTIONS.UPDATE_TRACES, payload: { update, - traceIndexes: [this.props.traceIndex], + traceIndexes: this.props.traceIndexes, }, }); } @@ -65,7 +68,7 @@ export default function connectTraceToPlot(WrappedComponent) { if (this.context.onUpdate) { this.context.onUpdate({ type: EDITOR_ACTIONS.DELETE_TRACE, - payload: {traceIndexes: [this.props.traceIndex]}, + payload: {traceIndexes: this.props.traceIndexes}, }); } } @@ -80,7 +83,7 @@ export default function connectTraceToPlot(WrappedComponent) { )}`; TraceConnectedComponent.propTypes = { - traceIndex: PropTypes.number.isRequired, + traceIndexes: PropTypes.array, }; TraceConnectedComponent.contextTypes = { diff --git a/src/lib/index.js b/src/lib/index.js index 438c93e1d..5679e6735 100644 --- a/src/lib/index.js +++ b/src/lib/index.js @@ -10,6 +10,7 @@ import localize, {localizeString} from './localize'; import tinyColor from 'tinycolor2'; import unpackPlotProps from './unpackPlotProps'; import walkObject, {isPlainObject} from './walkObject'; +import {customToPlotly, plotlyToCustom} from './customTraceType'; function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); @@ -33,14 +34,16 @@ export { connectLayoutToPlot, connectToContainer, connectTraceToPlot, + customToPlotly, dereference, + findFullTraceIndex, getDisplayName, getLayoutContext, - findFullTraceIndex, icon, isPlainObject, localize, localizeString, + plotlyToCustom, unpackPlotProps, walkObject, };