Skip to content

Commit 274df5d

Browse files
Merge pull request #87 from plotly/CanvasSize
Canvas size
2 parents d022316 + 35784a4 commit 274df5d

19 files changed

+296
-124
lines changed

src/DefaultEditor.js

+70-46
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
33
import {
44
AxesSelector,
55
AxesRange,
6+
CanvasSize,
67
ColorPicker,
78
DataSelector,
89
Dropdown,
@@ -17,6 +18,7 @@ import {
1718
MenuPanel,
1819
SymbolSelector,
1920
TraceAccordion,
21+
TraceMarkerSection,
2022
TraceSelector,
2123
} from './components';
2224
import {DEFAULT_FONTS} from './constants';
@@ -26,32 +28,6 @@ const LayoutPanel = connectLayoutToPlot(Panel);
2628
const AxesFold = connectAxesToLayout(Fold);
2729

2830
class DefaultEditor extends Component {
29-
constructor(props, context) {
30-
super(props, context);
31-
32-
const capitalize = s => s.charAt(0).toUpperCase() + s.substring(1);
33-
34-
// Filter out Polar "area" type as it is fairly broken and we want to present
35-
// scatter with fill as an "area" chart type for convenience.
36-
const traceTypes = Object.keys(context.plotSchema.traces).filter(
37-
t => t !== 'area'
38-
);
39-
40-
const labels = traceTypes.map(capitalize);
41-
this.traceOptions = traceTypes.map((t, i) => ({
42-
label: labels[i],
43-
value: t,
44-
}));
45-
46-
const i = this.traceOptions.findIndex(opt => opt.value === 'scatter');
47-
this.traceOptions.splice(
48-
i + 1,
49-
0,
50-
{label: 'Line', value: 'line'},
51-
{label: 'Area', value: 'area'}
52-
);
53-
}
54-
5531
render() {
5632
const _ = this.props.localize;
5733

@@ -63,7 +39,6 @@ class DefaultEditor extends Component {
6339
label="Plot Type"
6440
attr="type"
6541
clearable={false}
66-
options={this.traceOptions}
6742
show
6843
/>
6944

@@ -115,6 +90,18 @@ class DefaultEditor extends Component {
11590
<Numeric label={_('Opacity')} step={0.1} attr="opacity" />
11691
</Section>
11792

93+
<Section name={_('Text Attributes')}>
94+
<Flaglist
95+
attr="textinfo"
96+
options={[
97+
{label: 'Label', value: 'label'},
98+
{label: 'Text', value: 'text'},
99+
{label: 'Value', value: 'value'},
100+
{label: '%', value: 'percent'},
101+
]}
102+
/>
103+
</Section>
104+
118105
<Section name={_('Display')}>
119106
<Flaglist
120107
attr="mode"
@@ -142,14 +129,21 @@ class DefaultEditor extends Component {
142129
<ColorPicker label={_('Color')} attr="fillcolor" />
143130
</Section>
144131

145-
<Section name={_('Points')}>
132+
<TraceMarkerSection>
133+
<Radio
134+
attr="orientation"
135+
options={[
136+
{label: _('Vertical'), value: 'v'},
137+
{label: _('Horizontal'), value: 'h'},
138+
]}
139+
/>
146140
<ColorPicker label={_('Color')} attr="marker.color" />
147141
<Numeric label={_('Opacity')} step={0.1} attr="marker.opacity" />
148142
<Numeric label={_('Size')} attr="marker.size" />
149143
<SymbolSelector label={_('Symbol')} attr="marker.symbol" />
150144
<Numeric label={_('Border Width')} attr="marker.line.width" />
151145
<ColorPicker label={_('Border Color')} attr="marker.line.color" />
152-
</Section>
146+
</TraceMarkerSection>
153147

154148
<Section name={_('Lines')}>
155149
<Numeric label={_('Width')} step={1.0} attr="line.width" />
@@ -168,12 +162,43 @@ class DefaultEditor extends Component {
168162

169163
<LayoutPanel group="Style" name={_('Layout')}>
170164
<Fold name={_('Canvas')}>
171-
<Numeric
165+
<Radio
166+
attr="autosize"
167+
options={[
168+
{label: _('Auto'), value: true},
169+
{label: _('Custom'), value: false},
170+
]}
171+
/>
172+
<CanvasSize
172173
label={_('Fixed Width')}
173174
step={1}
174175
attr="width"
175176
postfix="px"
176177
/>
178+
<CanvasSize
179+
label={_('Fixed Height')}
180+
step={1}
181+
attr="height"
182+
postfix="px"
183+
/>
184+
<ColorPicker label={_('Color')} attr="paper_bgcolor" />
185+
</Fold>
186+
<Fold name={_('Margins and Padding')}>
187+
<Numeric label={_('Top')} step={1} attr="margin.t" postfix="px" />
188+
<Numeric
189+
label={_('Bottom')}
190+
step={1}
191+
attr="margin.b"
192+
postfix="px"
193+
/>
194+
<Numeric label={_('Left')} step={1} attr="margin.l" postfix="px" />
195+
<Numeric label={_('Right')} step={1} attr="margin.r" postfix="px" />
196+
<Numeric
197+
label={_('Padding')}
198+
step={1}
199+
attr="margin.pad"
200+
postfix="px"
201+
/>
177202
</Fold>
178203
</LayoutPanel>
179204

@@ -212,21 +237,21 @@ class DefaultEditor extends Component {
212237
</Section>
213238
</AxesFold>
214239

215-
<AxesFold name={_('Lines')}>
216-
<AxesSelector />
217-
</AxesFold>
218-
<AxesFold name={_('Tick Labels')}>
219-
<AxesSelector />
220-
</AxesFold>
221-
<AxesFold name={_('Tick Markers')}>
222-
<AxesSelector />
223-
</AxesFold>
224-
<AxesFold name={_('Zoom Interactivity')}>
225-
<AxesSelector />
226-
</AxesFold>
227-
<AxesFold name={_('Layout')}>
228-
<AxesSelector />
229-
</AxesFold>
240+
{/* <AxesFold name={_('Lines')}>
241+
<AxesSelector />
242+
</AxesFold>
243+
<AxesFold name={_('Tick Labels')}>
244+
<AxesSelector />
245+
</AxesFold>
246+
<AxesFold name={_('Tick Markers')}>
247+
<AxesSelector />
248+
</AxesFold>
249+
<AxesFold name={_('Zoom Interactivity')}>
250+
<AxesSelector />
251+
</AxesFold>
252+
<AxesFold name={_('Layout')}>
253+
<AxesSelector />
254+
</AxesFold> */}
230255
</LayoutPanel>
231256

232257
<LayoutPanel group="Style" name={_('Legend')}>
@@ -338,7 +363,6 @@ class DefaultEditor extends Component {
338363

339364
DefaultEditor.contextTypes = {
340365
dataSourceNames: PropTypes.array.isRequired,
341-
plotSchema: PropTypes.object.isRequired,
342366
};
343367

344368
export default localize(DefaultEditor);

src/PlotlyEditor.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ class PlotlyEditor extends Component {
1212
noShame({plotly: this.props.plotly});
1313

1414
// we only need to compute this once.
15-
this.plotSchema = this.props.plotly.PlotSchema.get();
15+
if (this.props.plotly) {
16+
this.plotSchema = this.props.plotly.PlotSchema.get();
17+
}
1618
}
1719

1820
getChildContext() {
@@ -51,7 +53,7 @@ class PlotlyEditor extends Component {
5153

5254
PlotlyEditor.propTypes = {
5355
onUpdate: PropTypes.func,
54-
plotly: PropTypes.object.isRequired,
56+
plotly: PropTypes.object,
5557
graphDiv: PropTypes.object,
5658
locale: PropTypes.string,
5759
dataSources: PropTypes.object,
@@ -72,8 +74,8 @@ PlotlyEditor.childContextTypes = {
7274
layout: PropTypes.object,
7375
locale: PropTypes.string,
7476
onUpdate: PropTypes.func,
75-
plotSchema: PropTypes.object.isRequired,
76-
plotly: PropTypes.object.isRequired,
77+
plotSchema: PropTypes.object,
78+
plotly: PropTypes.object,
7779
};
7880

7981
export default PlotlyEditor;

src/components/containers/Section.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,14 @@ class Section extends Component {
4545
}
4646

4747
const isAttr = Boolean(child.props.attr);
48-
const plotProps = isAttr
49-
? unpackPlotProps(child.props, context, child.type)
50-
: {isVisible: true};
48+
let plotProps;
49+
if (child.plotProps) {
50+
plotProps = child.plotProps;
51+
} else if (isAttr) {
52+
plotProps = unpackPlotProps(child.props, context, child.type);
53+
} else {
54+
plotProps = {isVisible: true};
55+
}
5156
const childProps = Object.assign({plotProps}, child.props);
5257
childProps.key = i;
5358
attrChildren.push(cloneElement(child, childProps));

src/components/containers/TraceAccordion.js

+11-14
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,34 @@ import {connectTraceToPlot} from '../../lib';
77
const TraceFold = connectTraceToPlot(Fold);
88

99
export default class TraceAccordion extends Component {
10-
constructor(props, context) {
10+
constructor(props) {
1111
super(props);
1212

1313
this.addTrace = this.addTrace.bind(this);
14-
this.renderPanel = this.renderPanel.bind(this);
15-
}
16-
17-
renderPanel(d, i) {
18-
return (
19-
<TraceFold key={i} traceIndex={i} name={`Trace ${i}`}>
20-
{this.props.children}
21-
</TraceFold>
22-
);
2314
}
2415

2516
addTrace() {
26-
this.context.onUpdate &&
17+
if (this.context.onUpdate) {
2718
this.context.onUpdate({
2819
type: EDITOR_ACTIONS.ADD_TRACE,
2920
});
21+
}
3022
}
3123

3224
render() {
3325
const data = this.context.data || [];
3426
return (
3527
<div>
36-
{this.props.canAdd && (
28+
{this.props.canAdd ? (
3729
<a href="#" onClick={this.addTrace}>
3830
Add
3931
</a>
40-
)}
41-
{data.map(this.renderPanel)}
32+
) : null}
33+
{data.map((d, i) => (
34+
<TraceFold key={i} traceIndex={i} name={`Trace ${i}`}>
35+
{this.props.children}
36+
</TraceFold>
37+
))}
4238
</div>
4339
);
4440
}
@@ -50,5 +46,6 @@ TraceAccordion.contextTypes = {
5046
};
5147

5248
TraceAccordion.propTypes = {
49+
children: PropTypes.node,
5350
canAdd: PropTypes.bool,
5451
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import Section from './Section';
2+
import React, {Component} from 'react';
3+
import PropTypes from 'prop-types';
4+
import localize from '../../lib/localize';
5+
6+
class TraceMarkerSection extends Component {
7+
constructor(props, context) {
8+
super(props, context);
9+
this.setLocals(context);
10+
}
11+
12+
componentWillReceiveProps(nextProps, nextContext) {
13+
this.setLocals(nextContext);
14+
}
15+
16+
setLocals(context) {
17+
const _ = this.props.localize;
18+
const traceType = context.fullContainer.type;
19+
if (traceType === 'bar') {
20+
this.name = _('Bars');
21+
} else {
22+
this.name = _('Points');
23+
}
24+
}
25+
26+
render() {
27+
return <Section name={this.name}>{this.props.children}</Section>;
28+
}
29+
}
30+
31+
TraceMarkerSection.propTypes = {
32+
children: PropTypes.node,
33+
localize: PropTypes.func,
34+
name: PropTypes.string,
35+
};
36+
37+
TraceMarkerSection.contextTypes = {
38+
fullContainer: PropTypes.object,
39+
};
40+
41+
export default localize(TraceMarkerSection);

src/components/containers/__tests__/Layout-test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import {Fold, Panel, Section} from '..';
33
import NumericInput from '../../widgets/NumericInputStatefulWrapper';
44
import React from 'react';
55
import {EDITOR_ACTIONS} from '../../../constants';
6-
import {TestEditor, fixtures, plotly} from '../../../lib/test-utils';
6+
import {TestEditor, fixtures} from '../../../lib/test-utils';
77
import {connectLayoutToPlot} from '../../../lib';
88
import {mount} from 'enzyme';
99

1010
const Layouts = [Panel, Fold, Section].map(connectLayoutToPlot);
1111
const Editor = props => (
12-
<TestEditor {...{plotly, onUpdate: jest.fn(), ...props}} />
12+
<TestEditor {...{onUpdate: jest.fn(), ...props}} />
1313
);
1414

1515
Layouts.forEach(Layout => {

0 commit comments

Comments
 (0)