Skip to content

Commit be5ce2b

Browse files
authored
Merge pull request #578 from plotly/gl-switch
Gl switch
2 parents bdcd409 + 1a4eef7 commit be5ce2b

File tree

9 files changed

+183
-49
lines changed

9 files changed

+183
-49
lines changed

dev/App.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,18 @@ const config = {mapboxAccessToken: ACCESS_TOKENS.MAPBOX, editable: true};
4444
const traceTypesConfig = {
4545
traces: _ => [
4646
{
47-
value: 'scattergl',
47+
value: 'scatter',
4848
icon: 'scatter',
4949
label: _('Scatter'),
5050
},
51+
{
52+
value: 'line',
53+
label: _('Line'),
54+
},
55+
{
56+
value: 'area',
57+
label: _('Area'),
58+
},
5159
{
5260
value: 'bar',
5361
label: _('Bar'),
@@ -155,6 +163,7 @@ class App extends Component {
155163
debug
156164
advancedTraceTypeSelector
157165
showFieldTooltips
166+
// glByDefault
158167
// traceTypesConfig={traceTypesConfig}
159168
// makeDefaultTrace={() => ({type: 'scattergl', mode: 'markers'})}
160169
>

src/EditorControls.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class EditorControls extends Component {
4949
plotly: this.props.plotly,
5050
traceTypesConfig: this.props.traceTypesConfig,
5151
showFieldTooltips: this.props.showFieldTooltips,
52+
glByDefault: this.props.glByDefault,
53+
mapBoxAccess: this.props.mapBoxAccess,
5254
};
5355
}
5456

@@ -121,7 +123,14 @@ class EditorControls extends Component {
121123

122124
// can't use default prop because plotly.js mutates it:
123125
// https://github.com/plotly/react-chart-editor/issues/509
124-
graphDiv.data.push(this.props.makeDefaultTrace());
126+
graphDiv.data.push(
127+
this.props.makeDefaultTrace
128+
? this.props.makeDefaultTrace()
129+
: {
130+
type: `scatter${this.props.glByDefault ? 'gl' : ''}`,
131+
mode: 'markers',
132+
}
133+
);
125134

126135
if (this.props.afterAddTrace) {
127136
this.props.afterAddTrace(payload);
@@ -308,12 +317,13 @@ EditorControls.propTypes = {
308317
showFieldTooltips: PropTypes.bool,
309318
traceTypesConfig: PropTypes.object,
310319
makeDefaultTrace: PropTypes.func,
320+
glByDefault: PropTypes.bool,
321+
mapBoxAccess: PropTypes.bool,
311322
};
312323

313324
EditorControls.defaultProps = {
314325
showFieldTooltips: false,
315326
locale: 'en',
316-
makeDefaultTrace: () => ({type: 'scatter', mode: 'markers'}),
317327
traceTypesConfig: {
318328
categories: _ => categoryLayout(_),
319329
traces: _ => traceTypes(_),
@@ -346,6 +356,8 @@ EditorControls.childContextTypes = {
346356
plotSchema: PropTypes.object,
347357
traceTypesConfig: PropTypes.object,
348358
showFieldTooltips: PropTypes.bool,
359+
glByDefault: PropTypes.bool,
360+
mapBoxAccess: PropTypes.bool,
349361
};
350362

351363
export default EditorControls;

src/PlotlyEditor.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ class PlotlyEditor extends Component {
2727
showFieldTooltips={this.props.showFieldTooltips}
2828
srcConverters={this.props.srcConverters}
2929
makeDefaultTrace={this.props.makeDefaultTrace}
30+
glByDefault={this.props.glByDefault}
31+
mapBoxAccess={Boolean(
32+
this.props.config && this.props.config.mapboxAccessToken
33+
)}
3034
>
3135
{this.props.children}
3236
</EditorControls>
@@ -77,6 +81,7 @@ PlotlyEditor.propTypes = {
7781
fromSrc: PropTypes.func.isRequired,
7882
}),
7983
makeDefaultTrace: PropTypes.func,
84+
glByDefault: PropTypes.bool,
8085
};
8186

8287
PlotlyEditor.defaultProps = {

src/components/containers/Modal.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,26 @@ const ModalContent = ({children}) => (
2121
);
2222

2323
class Modal extends Component {
24+
constructor(props) {
25+
super(props);
26+
this.escFunction = this.escFunction.bind(this);
27+
}
28+
29+
escFunction(event) {
30+
const escKeyCode = 27;
31+
if (event.keyCode === escKeyCode) {
32+
this.context.handleClose();
33+
}
34+
}
35+
36+
componentDidMount() {
37+
document.addEventListener('keydown', this.escFunction, false);
38+
}
39+
40+
componentWillUnmount() {
41+
document.removeEventListener('keydown', this.escFunction, false);
42+
}
43+
2444
render() {
2545
const {children, title} = this.props;
2646
let classes = 'modal';

src/components/fields/TraceSelector.js

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,24 @@ import {
1010
import TraceTypeSelector, {
1111
TraceTypeSelectorButton,
1212
} from 'components/widgets/TraceTypeSelector';
13+
import RadioBlocks from 'components/widgets/RadioBlocks';
14+
1315
import Field from './Field';
1416

17+
export const glAvailable = type => {
18+
return ['scatter', 'scatterpolar', 'scattergl', 'scatterpolargl'].includes(
19+
type
20+
);
21+
};
22+
1523
class TraceSelector extends Component {
1624
constructor(props, context) {
1725
super(props, context);
1826

1927
this.updatePlot = this.updatePlot.bind(this);
28+
this.setGl = this.setGl.bind(this);
29+
this.glEnabled = this.glEnabled.bind(this);
30+
this.setTraceDefaults = this.setTraceDefaults.bind(this);
2031

2132
this.setTraceDefaults(
2233
props.container,
@@ -26,6 +37,10 @@ class TraceSelector extends Component {
2637
this.setLocals(props, context);
2738
}
2839

40+
glEnabled() {
41+
return this.props.container.type.endsWith('gl') ? 'gl' : '';
42+
}
43+
2944
setLocals(props, context) {
3045
const _ = context.localize;
3146
if (props.traceOptions) {
@@ -46,10 +61,11 @@ class TraceSelector extends Component {
4661
}
4762
}
4863

49-
setTraceDefaults(container, fullContainer, updateContainer) {
64+
setTraceDefaults(container, fullContainer, updateContainer, gl) {
5065
if (container && !container.mode && fullContainer.type === 'scatter') {
5166
updateContainer({
52-
type: 'scatter',
67+
type:
68+
'scatter' + (gl || this.context.glByDefault ? gl : this.glEnabled()),
5369
mode: fullContainer.mode || 'markers',
5470
});
5571
}
@@ -63,29 +79,70 @@ class TraceSelector extends Component {
6379

6480
updatePlot(value) {
6581
const {updateContainer} = this.props;
82+
const {glByDefault} = this.context;
6683
if (updateContainer) {
67-
updateContainer(traceTypeToPlotlyInitFigure(value));
84+
updateContainer(
85+
traceTypeToPlotlyInitFigure(value, this.glEnabled() || glByDefault)
86+
);
6887
}
6988
}
7089

90+
setGl(value) {
91+
const {container, fullContainer, updateContainer} = this.props;
92+
const gl = 'gl';
93+
94+
this.setTraceDefaults(container, fullContainer, updateContainer, value);
95+
96+
const traceType =
97+
this.fullValue.endsWith(gl) && value === ''
98+
? this.fullValue.slice(0, -gl.length)
99+
: this.fullValue;
100+
101+
updateContainer(traceTypeToPlotlyInitFigure(traceType, value));
102+
}
103+
71104
render() {
72105
const props = Object.assign({}, this.props, {
73106
fullValue: this.fullValue,
74107
updatePlot: this.updatePlot,
75108
options: this.traceOptions,
76109
clearable: false,
77110
});
111+
const {localize: _, advancedTraceTypeSelector} = this.context;
112+
113+
const options = [
114+
{label: _('SVG'), value: ''},
115+
{label: _('WebGl'), value: 'gl'},
116+
];
117+
78118
// Check and see if the advanced selector prop is true
79-
const {advancedTraceTypeSelector} = this.context;
80119
if (advancedTraceTypeSelector) {
81120
return (
82-
<Field {...props}>
83-
<TraceTypeSelectorButton
84-
{...props}
85-
traceTypesConfig={this.context.traceTypesConfig}
86-
handleClick={() => this.context.openModal(TraceTypeSelector, props)}
87-
/>
88-
</Field>
121+
<div>
122+
<Field {...props}>
123+
<TraceTypeSelectorButton
124+
{...props}
125+
traceTypesConfig={this.context.traceTypesConfig}
126+
handleClick={() =>
127+
this.context.openModal(TraceTypeSelector, {
128+
...props,
129+
glByDefault: this.context.glByDefault,
130+
})
131+
}
132+
/>
133+
</Field>
134+
{!glAvailable(this.props.container.type) ? (
135+
''
136+
) : (
137+
<Field label={_('Rendering')}>
138+
<RadioBlocks
139+
options={options}
140+
activeOption={this.glEnabled()}
141+
onOptionChange={this.setGl}
142+
/>
143+
</Field>
144+
)}
145+
</div>
89146
);
90147
}
91148

@@ -100,6 +157,7 @@ TraceSelector.contextTypes = {
100157
plotSchema: PropTypes.object,
101158
config: PropTypes.object,
102159
localize: PropTypes.func,
160+
glByDefault: PropTypes.bool,
103161
};
104162

105163
TraceSelector.propTypes = {

src/components/widgets/TraceTypeSelector.js

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, {Component} from 'react';
22
import PropTypes from 'prop-types';
33
import {SearchIcon, ThumnailViewIcon, GraphIcon} from 'plotly-icons';
44
import Modal from 'components/containers/Modal';
5+
import {glAvailable} from 'components/fields/TraceSelector';
56
import {
67
traceTypeToPlotlyInitFigure,
78
renderTraceIcon,
@@ -75,22 +76,39 @@ const Item = ({item, active, handleClick, actions, showActions, complex}) => {
7576

7677
class TraceTypeSelector extends Component {
7778
selectAndClose(value) {
79+
const {
80+
updateContainer,
81+
glByDefault,
82+
fullContainer: {type},
83+
} = this.props;
7884
const computedValue = traceTypeToPlotlyInitFigure(value);
79-
this.props.updateContainer(computedValue);
85+
if (
86+
(type.endsWith('gl') || (!glAvailable(type) && glByDefault)) &&
87+
glAvailable(computedValue.type) &&
88+
!computedValue.type.endsWith('gl')
89+
) {
90+
computedValue.type = computedValue.type + 'gl';
91+
}
92+
updateContainer(computedValue);
8093
this.context.handleClose();
8194
}
8295

8396
renderCategories() {
8497
const {fullValue} = this.props;
8598
const {
8699
traceTypesConfig: {traces, categories, complex},
100+
mapBoxAccess,
87101
localize: _,
88102
} = this.context;
89103

90104
return categories(_).map((category, i) => {
91-
const items = traces(_).filter(
92-
({category: {value}}) => value === category.value
93-
);
105+
let items = traces(_)
106+
.filter(({category: {value}}) => value === category.value)
107+
.filter(i => i.value !== 'scattergl' && i.value !== 'scatterpolargl');
108+
109+
if (!mapBoxAccess) {
110+
items = items.filter(i => i.value !== 'scattermapbox');
111+
}
94112

95113
const MAX_ITEMS = 4;
96114

@@ -207,11 +225,14 @@ export class TraceTypeSelectorButton extends Component {
207225
TraceTypeSelector.propTypes = {
208226
updateContainer: PropTypes.func,
209227
fullValue: PropTypes.string,
228+
fullContainer: PropTypes.object,
229+
glByDefault: PropTypes.bool,
210230
};
211231
TraceTypeSelector.contextTypes = {
212232
traceTypesConfig: PropTypes.object,
213233
handleClose: PropTypes.func,
214234
localize: PropTypes.func,
235+
mapBoxAccess: PropTypes.bool,
215236
};
216237
TraceTypeSelectorButton.propTypes = {
217238
handleClick: PropTypes.func.isRequired,

src/lib/customTraceType.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,37 @@
11
export function plotlyTraceToCustomTrace(trace) {
2-
const type = trace.type || 'scatter';
2+
const gl = 'gl';
3+
const type = trace.type.endsWith(gl)
4+
? trace.type.slice(0, -gl.length)
5+
: trace.type || 'scatter';
6+
37
if (
4-
type === 'scatter' &&
8+
(type === 'scatter' || type === 'scattergl') &&
59
['tozeroy', 'tozerox', 'tonexty', 'tonextx', 'toself', 'tonext'].includes(
610
trace.fill
711
)
812
) {
913
return 'area';
1014
} else if (
11-
type === 'scatter' &&
15+
(type === 'scatter' || type === 'scattergl') &&
1216
(trace.mode === 'lines' || trace.mode === 'lines+markers')
1317
) {
1418
return 'line';
1519
} else if (type === 'scatter3d' && trace.mode === 'lines') {
1620
return 'line3d';
1721
}
18-
return trace.type;
22+
return type;
1923
}
2024

21-
export function traceTypeToPlotlyInitFigure(traceType) {
25+
export function traceTypeToPlotlyInitFigure(traceType, gl = '') {
2226
switch (traceType) {
2327
case 'line':
24-
return {type: 'scatter', mode: 'lines', fill: 'none'};
28+
return {type: 'scatter' + gl, mode: 'lines', fill: 'none'};
2529
case 'scatter':
26-
return {type: 'scatter', mode: 'markers', fill: 'none'};
30+
return {type: 'scatter' + gl, mode: 'markers', fill: 'none'};
2731
case 'area':
28-
return {type: 'scatter', fill: 'tozeroy'};
32+
return {type: 'scatter' + gl, fill: 'tozeroy'};
33+
case 'scatterpolar':
34+
return {type: 'scatterpolar' + gl};
2935
case 'ohlc':
3036
return {
3137
type: 'ohlc',

src/lib/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ function renderTraceIcon(trace, prefix = 'Plot') {
5858
if (!trace) {
5959
return null;
6060
}
61-
const componentName = `${prefix}${pascalCase(trace)}Icon`;
61+
const gl = 'gl';
62+
const componentName = `${prefix}${pascalCase(
63+
trace.endsWith(gl) ? trace.slice(0, -gl.length) : trace
64+
)}Icon`;
6265
return PlotlyIcons[componentName]
6366
? PlotlyIcons[componentName]
6467
: PlotlyIcons.PlotLineIcon;

0 commit comments

Comments
 (0)