Skip to content

Commit d0dbdd6

Browse files
authored
Merge pull request #625 from plotly/s-m-colors
ColorPicker => MultiColorPicker
2 parents d5f0795 + 4987554 commit d0dbdd6

File tree

5 files changed

+219
-101
lines changed

5 files changed

+219
-101
lines changed

src/components/fields/MarkerColor.js

Lines changed: 27 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import Field from './Field';
22
import PropTypes from 'prop-types';
33
import React, {Component, Fragment} from 'react';
4-
import {adjustColorscale, connectToContainer} from 'lib';
4+
import {connectToContainer} from 'lib';
55
import RadioBlocks from '../widgets/RadioBlocks';
6-
import Color from './Color';
6+
import MultiColorPicker from './MultiColorPicker';
77
import Colorscale from './Colorscale';
88
import Numeric from './Numeric';
99
import Radio from './Radio';
@@ -37,14 +37,16 @@ class UnconnectedMarkerColor extends Component {
3737
constant: type === 'constant' ? props.fullValue : COLORS.mutedBlue,
3838
variable: type === 'variable' ? props.fullValue : null,
3939
},
40-
constantSelectedOption:
40+
selectedConstantColorOption:
4141
type === 'constant' && props.multiValued ? 'multiple' : 'single',
4242
};
4343

4444
this.setType = this.setType.bind(this);
45-
this.setValue = this.setValue.bind(this);
45+
this.setColor = this.setColor.bind(this);
4646
this.setColorScale = this.setColorScale.bind(this);
47-
this.setColors = this.setColors.bind(this);
47+
this.onConstantColorOptionChange = this.onConstantColorOptionChange.bind(
48+
this
49+
);
4850
}
4951

5052
setType(type) {
@@ -67,7 +69,7 @@ class UnconnectedMarkerColor extends Component {
6769
}
6870
}
6971

70-
setValue(inputValue) {
72+
setColor(inputValue) {
7173
const {type} = this.state;
7274

7375
this.setState(
@@ -99,88 +101,32 @@ class UnconnectedMarkerColor extends Component {
99101
);
100102
}
101103

102-
setColors(colorscale, colorscaleType) {
103-
const numberOfTraces = this.context.traceIndexes.length;
104-
const colors = colorscale.map(c => c[1]);
105-
106-
let adjustedColors = colors;
107-
108-
if (colorscaleType !== 'categorical') {
109-
adjustedColors = adjustColorscale(colors, numberOfTraces, colorscaleType);
110-
}
111-
112-
if (
113-
adjustedColors.every(c => c === adjustedColors[0]) ||
114-
colorscaleType === 'categorical'
115-
) {
116-
adjustedColors = adjustColorscale(
117-
colors,
118-
numberOfTraces,
119-
colorscaleType,
120-
{repeat: true}
121-
);
122-
}
123-
124-
const updates = adjustedColors.map(color => ({
125-
['marker.color']: color,
126-
}));
127-
104+
onConstantColorOptionChange(value) {
128105
this.setState({
129-
colorscale: adjustedColors,
106+
selectedConstantColorOption: value,
130107
});
131-
132-
this.context.updateContainer(updates);
133108
}
134109

135110
renderConstantControls() {
136111
const _ = this.context.localize;
137-
const constantOptions = [
138-
{label: _('Single'), value: 'single'},
139-
{label: _('Multiple'), value: 'multiple'},
140-
];
141-
142-
if (this.context.traceIndexes.length > 1) {
143-
return (
144-
<div className="markercolor-constantcontrols__container">
145-
<RadioBlocks
146-
options={constantOptions}
147-
activeOption={this.state.constantSelectedOption}
148-
onOptionChange={value =>
149-
this.setState({constantSelectedOption: value})
150-
}
151-
/>
152-
<Info>
153-
{this.state.constantSelectedOption === 'single'
154-
? _('All traces will be colored in the the same color.')
155-
: _(
156-
'Each trace will be colored according to the selected colorscale.'
157-
)}
158-
</Info>
159-
{this.state.constantSelectedOption === 'single' ? (
160-
<Color
161-
attr="marker.color"
162-
updatePlot={this.setValue}
163-
fullValue={this.state.value.constant}
164-
/>
165-
) : (
166-
<Colorscale
167-
suppressMultiValuedMessage
168-
attr="marker.color"
169-
updatePlot={this.setColors}
170-
colorscale={this.state.colorscale}
171-
initialCategory={'categorical'}
172-
/>
173-
)}
174-
</div>
175-
);
176-
}
177-
178112
return (
179-
<Color
180-
attr="marker.color"
181-
updatePlot={this.setValue}
182-
fullValue={this.state.value.constant}
183-
/>
113+
<div className="markercolor-constantcontrols__container">
114+
<MultiColorPicker
115+
attr="marker.color"
116+
multiColorMessage={_(
117+
'Each trace will be colored according to the selected colorscale.'
118+
)}
119+
singleColorMessage={_(
120+
'All traces will be colored in the the same color.'
121+
)}
122+
setColor={this.setColor}
123+
setColorScale={this.setColorScale}
124+
onConstantColorOptionChange={this.onConstantColorOptionChange}
125+
parentSelectedConstantColorOption={
126+
this.state.selectedConstantColorOption
127+
}
128+
/>
129+
</div>
184130
);
185131
}
186132

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import React, {Component} from 'react';
2+
import Color from './Color';
3+
import Colorscale from './Colorscale';
4+
import Info from './Info';
5+
import Field from './Field';
6+
import RadioBlocks from '../widgets/RadioBlocks';
7+
import PropTypes from 'prop-types';
8+
import {adjustColorscale, connectToContainer} from 'lib';
9+
10+
class UnconnectedMultiColorPicker extends Component {
11+
constructor(props, context) {
12+
super(props, context);
13+
this.state = {
14+
selectedConstantColorOption:
15+
context.traceIndexes.length > 1 &&
16+
props.fullValue.every(v => v[1] === props.fullValue[0][1])
17+
? 'single'
18+
: 'multiple',
19+
};
20+
this.setColor = this.setColor.bind(this);
21+
this.setColors = this.setColors.bind(this);
22+
}
23+
24+
setColor(color) {
25+
this.props.updatePlot(color);
26+
}
27+
28+
setColors(colorscale, colorscaleType) {
29+
const numberOfTraces = this.context.traceIndexes.length;
30+
const colors = colorscale.map(c => c[1]);
31+
32+
let adjustedColors = colors;
33+
34+
if (colorscaleType !== 'categorical') {
35+
adjustedColors = adjustColorscale(colors, numberOfTraces, colorscaleType);
36+
}
37+
38+
if (
39+
adjustedColors.every(c => c === adjustedColors[0]) ||
40+
colorscaleType === 'categorical'
41+
) {
42+
adjustedColors = adjustColorscale(
43+
colors,
44+
numberOfTraces,
45+
colorscaleType,
46+
{repeat: true}
47+
);
48+
}
49+
50+
const updates = adjustedColors.map(color => ({
51+
[this.props.attr]: color,
52+
}));
53+
54+
this.context.updateContainer(updates);
55+
}
56+
57+
render() {
58+
const _ = this.context.localize;
59+
const constantOptions = [
60+
{label: _('Single'), value: 'single'},
61+
{label: _('Multiple'), value: 'multiple'},
62+
];
63+
const selectedConstantColorOption = this.props
64+
.parentSelectedConstantColorOption
65+
? this.props.parentSelectedConstantColorOption
66+
: this.state.selectedConstantColorOption;
67+
68+
const multiMessage = this.props.multiColorMessage
69+
? this.props.multiColorMessage
70+
: _('Each will be colored according to the selected colors.');
71+
72+
const singleMessage = this.props.singleColorMessage
73+
? this.props.singleColorMessage
74+
: _('All will be colored in the same color.');
75+
76+
if (this.context.traceIndexes.length > 1) {
77+
return (
78+
<Field {...this.props} suppressMultiValuedMessage>
79+
<RadioBlocks
80+
options={constantOptions}
81+
activeOption={
82+
this.props.parentSelectedConstantColorOption
83+
? this.props.parentSelectedConstantColorOption
84+
: this.state.selectedConstantColorOption
85+
}
86+
onOptionChange={
87+
this.props.onConstantColorOptionChange
88+
? this.props.onConstantColorOptionChange
89+
: value => this.setState({selectedConstantColorOption: value})
90+
}
91+
/>
92+
<Info>
93+
{selectedConstantColorOption === 'single'
94+
? singleMessage
95+
: multiMessage}
96+
</Info>
97+
{selectedConstantColorOption === 'single' ? (
98+
<Color
99+
attr={this.props.attr}
100+
updatePlot={
101+
this.props.setColor ? this.props.setColor : this.setColor
102+
}
103+
/>
104+
) : (
105+
<Colorscale
106+
suppressMultiValuedMessage
107+
attr={this.props.attr}
108+
updatePlot={this.setColors}
109+
fullValue={this.props.fullValue}
110+
initialCategory={'categorical'}
111+
/>
112+
)}
113+
</Field>
114+
);
115+
}
116+
117+
return (
118+
<Color
119+
attr={this.props.attr}
120+
updatePlot={this.props.setColor ? this.props.setColor : this.setColor}
121+
label={this.props.label}
122+
/>
123+
);
124+
}
125+
}
126+
127+
UnconnectedMultiColorPicker.propTypes = {
128+
multiColorMessage: PropTypes.string,
129+
singleColorMessage: PropTypes.string,
130+
updatePlot: PropTypes.func,
131+
attr: PropTypes.string,
132+
parentSelectedConstantColorOption: PropTypes.string,
133+
onConstantColorOptionChange: PropTypes.func,
134+
messageKeyWordSingle: PropTypes.string,
135+
messageKeyWordPlural: PropTypes.string,
136+
...Field.propTypes,
137+
};
138+
139+
UnconnectedMultiColorPicker.contextTypes = {
140+
localize: PropTypes.func,
141+
updateContainer: PropTypes.func,
142+
traceIndexes: PropTypes.array,
143+
fullData: PropTypes.array,
144+
};
145+
146+
export default connectToContainer(UnconnectedMultiColorPicker, {
147+
modifyPlotProps(props, context, plotProps) {
148+
if (plotProps.isVisible) {
149+
plotProps.fullValue = context.traceIndexes
150+
.map(index => {
151+
const trace = context.fullData.filter(
152+
trace => trace.index === index
153+
)[0];
154+
155+
const properties = props.attr.split('.');
156+
let value = trace;
157+
158+
properties.forEach(prop => {
159+
value = value[prop];
160+
});
161+
162+
return value;
163+
})
164+
.map(c => [0, c]);
165+
}
166+
},
167+
});

src/components/fields/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {FilterOperation, FilterValue} from './FilterOperation';
2222
import MarkerSize from './MarkerSize';
2323
import MarkerColor from './MarkerColor';
2424
import VisibilitySelect from './VisibilitySelect';
25+
import MultiColorPicker from './MultiColorPicker';
26+
2527
import {
2628
AnnotationArrowRef,
2729
AnnotationRef,
@@ -91,5 +93,6 @@ export {
9193
TextPosition,
9294
MarkerSize,
9395
MarkerColor,
96+
MultiColorPicker,
9497
VisibilitySelect,
9598
};

src/components/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
TextPosition,
4545
MarkerSize,
4646
MarkerColor,
47+
MultiColorPicker,
4748
VisibilitySelect,
4849
} from './fields';
4950

@@ -144,5 +145,6 @@ export {
144145
TextPosition,
145146
MarkerSize,
146147
MarkerColor,
148+
MultiColorPicker,
147149
VisibilitySelect,
148150
};

0 commit comments

Comments
 (0)