diff --git a/src/EditorControls.js b/src/EditorControls.js
index b8de22231..c70b3fab8 100644
--- a/src/EditorControls.js
+++ b/src/EditorControls.js
@@ -11,6 +11,7 @@ import {
shamefullyAdjustSplitStyleTargetContainers,
shamefullyDeleteRelatedAnalysisTransforms,
shamefullyAdjustSizeref,
+ shamefullyAdjustBinSize,
} from './shame';
import {EDITOR_ACTIONS} from './lib/constants';
import isNumeric from 'fast-isnumeric';
@@ -72,6 +73,7 @@ class EditorControls extends Component {
}
shamefullyAdjustSizeref(graphDiv, payload);
+
shamefullyClearAxisTypes(graphDiv, payload);
shamefullyAdjustAxisRef(graphDiv, payload);
shamefullyAddTableColumns(graphDiv, payload);
@@ -80,6 +82,9 @@ class EditorControls extends Component {
for (let i = 0; i < payload.traceIndexes.length; i++) {
for (const attr in payload.update) {
const traceIndex = payload.traceIndexes[i];
+
+ shamefullyAdjustBinSize(graphDiv, payload, traceIndex);
+
const splitTraceGroup = payload.splitTraceGroup
? payload.splitTraceGroup.toString()
: null;
diff --git a/src/components/fields/NumericOrDate.js b/src/components/fields/NumericOrDate.js
new file mode 100644
index 000000000..cd4fc3706
--- /dev/null
+++ b/src/components/fields/NumericOrDate.js
@@ -0,0 +1,38 @@
+import Field from './Field';
+import {UnconnectedNumeric} from './Numeric';
+import {UnconnectedText} from './Text';
+import PropTypes from 'prop-types';
+import React, {Component} from 'react';
+import {connectToContainer} from 'lib';
+import {isDateTime} from 'plotly.js/src/lib';
+import {isJSDate} from 'plotly.js/src/lib/dates';
+
+export class UnconnectedNumericOrDate extends Component {
+ render() {
+ const fullValueIsDate =
+ typeof this.props.fullValue === 'string' &&
+ (isDateTime(this.props.fullValue) || isJSDate(this.props.fullValue));
+
+ return fullValueIsDate ? (
+
+ ) : (
+
+ );
+ }
+}
+
+UnconnectedNumericOrDate.propTypes = {
+ defaultValue: PropTypes.any,
+ fullValue: PropTypes.any,
+ min: PropTypes.number,
+ max: PropTypes.number,
+ multiValued: PropTypes.bool,
+ hideArrows: PropTypes.bool,
+ showSlider: PropTypes.bool,
+ step: PropTypes.number,
+ fullContainer: PropTypes.object,
+ updatePlot: PropTypes.func,
+ ...Field.propTypes,
+};
+
+export default connectToContainer(UnconnectedNumericOrDate);
diff --git a/src/components/fields/derived.js b/src/components/fields/derived.js
index fb6848e58..caea04091 100644
--- a/src/components/fields/derived.js
+++ b/src/components/fields/derived.js
@@ -3,6 +3,7 @@ import {UnconnectedDropdown} from './Dropdown';
import {UnconnectedDropdownCustom} from './DropdownCustom';
import {UnconnectedFlaglist} from './Flaglist';
import {UnconnectedNumeric} from './Numeric';
+import {UnconnectedNumericOrDate} from './NumericOrDate';
import {UnconnectedAxisRangeValue} from './AxisRangeValue';
import {UnconnectedRadio} from './Radio';
import Info from './Info';
@@ -432,7 +433,7 @@ export const PositioningRef = connectToContainer(UnconnectedDropdown, {
},
});
-export const PositioningNumeric = connectToContainer(UnconnectedNumeric, {
+export const PositioningNumeric = connectToContainer(UnconnectedNumericOrDate, {
modifyPlotProps: (props, context, plotProps) => {
const {fullContainer, fullValue, updatePlot} = plotProps;
if (
@@ -676,3 +677,15 @@ export const HoverColor = connectToContainer(UnconnectedColorPicker, {
return plotProps;
},
});
+
+export const BinSize = connectToContainer(UnconnectedNumeric, {
+ modifyPlotProps: (props, context, plotProps) => {
+ const {localize: _} = context;
+ if (typeof plotProps.fullValue === 'string' && plotProps.fullValue[0] === 'M') {
+ plotProps.fullValue = plotProps.fullValue.substring(1);
+ plotProps.min = 1;
+ plotProps.max = 12;
+ plotProps.units = parseInt(plotProps.fullValue, 10) === 1 ? _('Month') : _('Months');
+ }
+ },
+});
diff --git a/src/components/fields/index.js b/src/components/fields/index.js
index f075ab544..ad396e65b 100644
--- a/src/components/fields/index.js
+++ b/src/components/fields/index.js
@@ -13,6 +13,7 @@ import Radio from './Radio';
import TextEditor from './TextEditor';
import DataSelector from './DataSelector';
import Numeric from './Numeric';
+import NumericOrDate from './NumericOrDate';
import DualNumeric from './DualNumeric';
import AxisRangeValue from './AxisRangeValue';
import Text from './Text';
@@ -55,6 +56,7 @@ import {
HoveronDropdown,
HovermodeDropdown,
TickFormat,
+ BinSize,
} from './derived';
import {LineDashSelector, LineShapeSelector} from './LineSelectors';
@@ -118,4 +120,6 @@ export {
LocationSelector,
HoveronDropdown,
HovermodeDropdown,
+ BinSize,
+ NumericOrDate,
};
diff --git a/src/components/index.js b/src/components/index.js
index 0f5c5a2ec..28033fa07 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -57,6 +57,7 @@ import {
HoveronDropdown,
HovermodeDropdown,
TickFormat,
+ NumericOrDate,
} from './fields';
import {
@@ -175,4 +176,5 @@ export {
LocationSelector,
HoveronDropdown,
HovermodeDropdown,
+ NumericOrDate,
};
diff --git a/src/default_panels/StyleColorbarsPanel.js b/src/default_panels/StyleColorbarsPanel.js
index ae3527834..cbe7b4c1a 100644
--- a/src/default_panels/StyleColorbarsPanel.js
+++ b/src/default_panels/StyleColorbarsPanel.js
@@ -14,6 +14,7 @@ import {
FontSelector,
ColorPicker,
VisibilitySelect,
+ NumericOrDate,
} from '../components';
export const traceHasColorbar = (trace, fullTrace) =>
@@ -211,7 +212,7 @@ const StyleColorBarsPanel = (props, {localize: _}) => {
label={_('Tick spacing')}
/>
-
+
@@ -239,7 +240,7 @@ const StyleColorBarsPanel = (props, {localize: _}) => {
label={_('Tick spacing')}
/>
-
+
diff --git a/src/default_panels/StyleNotesPanel.js b/src/default_panels/StyleNotesPanel.js
index 1eef7af10..2300ae056 100644
--- a/src/default_panels/StyleNotesPanel.js
+++ b/src/default_panels/StyleNotesPanel.js
@@ -13,6 +13,7 @@ import {
Radio,
TextEditor,
PlotlySection,
+ NumericOrDate,
} from '../components';
const StyleNotesPanel = (props, {localize: _}) => (
@@ -35,8 +36,8 @@ const StyleNotesPanel = (props, {localize: _}) => (
-
-
+
+
(
@@ -193,18 +195,18 @@ const StyleTracesPanel = (props, {localize: _}) => (
/>
-
-
-
+
+
+
-
-
-
+
+
+
-
+
diff --git a/src/shame.js b/src/shame.js
index 14b6fcecd..3bd7fb625 100644
--- a/src/shame.js
+++ b/src/shame.js
@@ -3,6 +3,7 @@
*/
import {getFromId} from 'plotly.js/src/plots/cartesian/axis_ids';
import nestedProperty from 'plotly.js/src/lib/nested_property';
+import {isDateTime} from 'plotly.js/src/lib';
// Temporary fix for:
// https://github.com/plotly/react-chart-editor/issues/103
@@ -212,3 +213,22 @@ export const shamefullyAdjustSizeref = (gd, {update}) => {
update['marker.sizemode'] = 'area';
}
};
+
+export const shamefullyAdjustBinSize = (gd, {update}, traceIndexInDataArray) => {
+ const traceIndexInFullDataArray = gd._fullData.filter(t => t.index === traceIndexInDataArray)[0]
+ ._expandedIndex;
+ const binSizeAttrs = Object.keys(update).filter(attr => attr.includes('bins.size'));
+
+ binSizeAttrs.forEach(attr => {
+ const attrHead = attr.split('.')[0];
+ if (
+ gd._fullData[traceIndexInFullDataArray] &&
+ gd._fullData[traceIndexInFullDataArray][attrHead] &&
+ gd._fullData[traceIndexInFullDataArray][attrHead].start &&
+ isDateTime(gd._fullData[traceIndexInFullDataArray][attrHead].start)
+ ) {
+ const monthNum = update[attr];
+ update[attr] = 'M' + monthNum;
+ }
+ });
+};