Skip to content

Commit 2ac28a3

Browse files
Merge pull request #586 from plotly/marker-size-multivalue
Marker size multivalue
2 parents 5f283d8 + d847a50 commit 2ac28a3

File tree

6 files changed

+63
-28
lines changed

6 files changed

+63
-28
lines changed

src/components/fields/Field.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Field extends Component {
2424
children,
2525
label,
2626
multiValued,
27+
suppressMultiValuedMessage,
2728
units,
2829
extraComponent,
2930
} = this.props;
@@ -68,7 +69,7 @@ class Field extends Component {
6869
) : null}
6970
<div className={fieldClass}>
7071
{children}
71-
{multiValued ? (
72+
{multiValued && !suppressMultiValuedMessage ? (
7273
<MenuPanel label={getMultiValueText('title', _)} ownline question>
7374
<div className="info__title">{getMultiValueText('title', _)}</div>
7475
<div className="info__text">{getMultiValueText('text', _)}</div>
@@ -94,6 +95,7 @@ Field.propTypes = {
9495
label: PropTypes.any,
9596
units: PropTypes.string,
9697
multiValued: PropTypes.bool,
98+
suppressMultiValuedMessage: PropTypes.bool,
9799
children: PropTypes.node,
98100
extraComponent: PropTypes.any,
99101
};

src/components/fields/MarkerSize.js

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,27 @@ import {connectToContainer} from 'lib';
55
import RadioBlocks from '../widgets/RadioBlocks';
66
import Numeric from './Numeric';
77
import DataSelector from './DataSelector';
8-
9-
const getType = value => (Array.isArray(value) ? 'variable' : 'constant');
8+
import {MULTI_VALUED} from 'lib/constants';
109

1110
class UnconnectedMarkerSize extends Component {
1211
constructor(props, context) {
1312
super(props, context);
1413

15-
const type = getType(props.fullValue);
14+
let type = null;
15+
if (
16+
!props.container.marker ||
17+
(props.container.marker && !props.container.marker.sizesrc)
18+
) {
19+
type = 'constant';
20+
} else if (
21+
props.container.marker &&
22+
Array.isArray(props.container.marker.size) &&
23+
props.fullContainer.marker &&
24+
Array.isArray(props.fullContainer.marker.size)
25+
) {
26+
type = 'variable';
27+
}
28+
1629
this.state = {
1730
type,
1831
value: {
@@ -30,6 +43,11 @@ class UnconnectedMarkerSize extends Component {
3043
this.props.updatePlot(this.state.value[type]);
3144
if (type === 'constant') {
3245
this.context.updateContainer({['marker.sizesrc']: null});
46+
} else {
47+
this.context.updateContainer({
48+
['marker.size']: null,
49+
['marker.sizesrc']: null,
50+
});
3351
}
3452
}
3553

@@ -45,32 +63,37 @@ class UnconnectedMarkerSize extends Component {
4563
}
4664

4765
render() {
48-
const {attr} = this.props;
66+
const {attr, fullValue} = this.props;
4967
const {localize: _} = this.context;
68+
const {type, value} = this.state;
5069
const options = [
5170
{label: _('Constant'), value: 'constant'},
5271
{label: _('Variable'), value: 'variable'},
5372
];
73+
const multiValued =
74+
this.props.multiValued ||
75+
(Array.isArray(fullValue) && fullValue.includes(MULTI_VALUED));
5476

5577
return (
5678
<div>
57-
<Field {...this.props} attr={attr}>
79+
<Field {...this.props} multiValued={multiValued} attr={attr}>
5880
<RadioBlocks
5981
options={options}
60-
activeOption={this.state.type}
82+
activeOption={type}
6183
onOptionChange={this.setType}
6284
/>
63-
{this.state.type === 'constant' ? (
85+
{type === 'constant' ? (
6486
<Numeric
87+
suppressMultiValuedMessage
6588
attr="marker.size"
6689
updatePlot={this.setValue}
67-
fullValue={this.state.value.constant}
90+
fullValue={value.constant}
6891
/>
69-
) : (
92+
) : multiValued ? null : (
7093
<DataSelector
94+
suppressMultiValuedMessage
7195
attr="marker.size"
7296
updatePlot={this.setValue}
73-
fullValue={this.state.value.variable}
7497
/>
7598
)}
7699
</Field>

src/components/widgets/EditableText.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ EditableText.propTypes = {
104104
text: PropTypes.any,
105105

106106
// Input properties
107-
placeholder: PropTypes.string,
107+
placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
108108
className: PropTypes.string,
109109
disable: PropTypes.bool,
110110
autoFocus: PropTypes.bool,

src/components/widgets/NumericInput.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ export default class NumericInput extends Component {
8686
let valueUpdate;
8787
if (isNumeric(value)) {
8888
if (direction === 'increase') {
89-
valueUpdate = value + step;
89+
valueUpdate = parseFloat(value) + step;
9090
} else {
91-
valueUpdate = value - step;
91+
valueUpdate = parseFloat(value) - step;
9292
}
9393
} else {
9494
// if we are multi-valued and the user is incrementing or decrementing
@@ -138,7 +138,7 @@ export default class NumericInput extends Component {
138138
min={this.props.min}
139139
max={this.props.max}
140140
step={this.props.step}
141-
value={this.state.value}
141+
value={parseFloat(this.state.value)}
142142
onChange={this.updateValue}
143143
tooltip={false}
144144
/>
@@ -172,7 +172,7 @@ NumericInput.propTypes = {
172172
max: PropTypes.number,
173173
min: PropTypes.number,
174174
onUpdate: PropTypes.func.isRequired,
175-
placeholder: PropTypes.string,
175+
placeholder: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
176176
showArrows: PropTypes.bool,
177177
showSlider: PropTypes.bool,
178178
step: PropTypes.number,

src/lib/connectTraceToPlot.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,25 @@ export default function connectTraceToPlot(WrappedComponent) {
7575
};
7676

7777
if (traceIndexes.length > 1) {
78-
const multiValuedContainer = deepCopyPublic(fullTrace);
78+
const multiValuedFullContainer = deepCopyPublic(fullTrace);
7979
fullData.forEach(t =>
80+
Object.keys(t).forEach(key =>
81+
setMultiValuedContainer(multiValuedFullContainer, t, key, {
82+
searchArrays: true,
83+
})
84+
)
85+
);
86+
const multiValuedContainer = deepCopyPublic(trace);
87+
data.forEach(t =>
8088
Object.keys(t).forEach(key =>
8189
setMultiValuedContainer(multiValuedContainer, t, key, {
8290
searchArrays: true,
8391
})
8492
)
8593
);
86-
this.childContext.fullContainer = multiValuedContainer;
94+
this.childContext.fullContainer = multiValuedFullContainer;
8795
this.childContext.defaultContainer = fullTrace;
88-
this.childContext.container = {};
96+
this.childContext.container = multiValuedContainer;
8997
}
9098

9199
if (trace && fullTrace) {

src/lib/multiValues.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@ function deepCopyPublic(value) {
1717
}
1818

1919
function setMultiValuedContainer(intoObj, fromObj, key, config = {}) {
20-
var intoVal = intoObj[key],
21-
fromVal = fromObj[key];
22-
23-
var searchArrays = config.searchArrays;
20+
const intoVal = intoObj[key];
21+
const fromVal = fromObj[key];
2422

2523
// don't merge private attrs
2624
if (
@@ -51,20 +49,24 @@ function setMultiValuedContainer(intoObj, fromObj, key, config = {}) {
5149
} else if (Array.isArray(intoVal)) {
5250
// in data, other arrays are data, which we don't care about
5351
// for styling purposes
54-
if (!searchArrays) {
52+
if (!config.searchArrays) {
5553
return;
5654
}
57-
// in layout though, we need to recurse into arrays
58-
for (var i = 0; i < fromVal.length; i++) {
59-
setMultiValuedContainer(intoVal, fromVal, i, searchArrays);
55+
if (!Array.isArray(fromVal)) {
56+
intoObj[key] = MULTI_VALUED;
57+
} else {
58+
// in layout though, we need to recurse into arrays
59+
for (let i = 0; i < fromVal.length; i++) {
60+
setMultiValuedContainer(intoVal, fromVal, i, config);
61+
}
6062
}
6163
} else if (isPlainObject(fromVal)) {
6264
// recurse into objects
6365
if (!isPlainObject(intoVal)) {
6466
throw new Error('tried to merge object into non-object: ' + key);
6567
}
6668
Object.keys(fromVal).forEach(function(key2) {
67-
setMultiValuedContainer(intoVal, fromVal, key2, searchArrays);
69+
setMultiValuedContainer(intoVal, fromVal, key2, config);
6870
});
6971
} else if (isPlainObject(intoVal)) {
7072
throw new Error('tried to merge non-object into object: ' + key);

0 commit comments

Comments
 (0)