Skip to content

Transforms #437

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 27, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 27 additions & 17 deletions dev/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'react-select/dist/react-select.css';
import brace from 'brace'; // eslint-disable-line no-unused-vars
import AceEditor from 'react-ace';
import Select from 'react-select';
import PlotlyEditor, {DefaultEditor, Panel} from '../src';
import PlotlyEditor, {DefaultEditor, Panel, GraphTransformsPanel} from '../src';
import Inspector from 'react-inspector';
import 'brace/mode/json';
import 'brace/theme/textmate';
Expand All @@ -15,13 +15,21 @@ import 'brace/theme/textmate';
import ACCESS_TOKENS from '../accessTokens';

const dataSources = {
ints: [1, 2, 3, 4, 5], // eslint-disable-line no-magic-numbers
'jagged ints': [2, 1, 3, 5, 4], // eslint-disable-line no-magic-numbers
ints: [1, 2, 3, 4, 5, 6], // eslint-disable-line no-magic-numbers
'jagged ints': [2, 1, 3, 5, 4, 6], // eslint-disable-line no-magic-numbers
'toggle ints': [1, -1, 1, -1, 1, -1], // eslint-disable-line no-magic-numbers
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

helpful for aggregations and splits

'big ints': [1000, 10100, 10000, 20000, 100000], // eslint-disable-line no-magic-numbers
dates: ['2010-01-01', '2010-07-01', '2011-01-01', '2011-07-01', '2012-01-01'],
months: ['January', 'February', 'March', 'April', 'May'],
colors: ['red', 'orange', 'yellow', 'green', 'blue'],
justblue: ['blue'],
dates: [
'2010-01-01',
'2010-07-01',
'2011-01-01',
'2011-07-01',
'2012-01-01',
'2012-06-01',
],
months: ['January', 'February', 'March', 'April', 'May', 'June'],
colors: ['red', 'orange', 'yellow', 'green', 'blue', 'indigo'],
'blue and red': ['blue', 'red'],
};
const dataSourceOptions = Object.keys(dataSources).map(name => ({
value: name,
Expand Down Expand Up @@ -56,13 +64,14 @@ class App extends Component {
}

loadMock(mockIndex) {
fetch(
'https://api.github.com/repos/plotly/plotly.js/contents/test/image/mocks/' +
this.state.mocks[mockIndex],
{
headers: new Headers({Accept: 'application/vnd.github.v3.raw'}),
}
)
const mockName = this.state.mocks[mockIndex];
const prefix =
mockName[0] === '/'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this allows us to add local mocks on top of the remote ones.

? ''
: 'https://api.github.com/repos/plotly/plotly.js/contents/test/image/mocks/';
fetch(prefix + mockName, {
headers: new Headers({Accept: 'application/vnd.github.v3.raw'}),
})
.then(response => response.json())
.then(figure => {
const {data, layout, frames} = figure;
Expand Down Expand Up @@ -109,6 +118,7 @@ class App extends Component {
advancedTraceTypeSelector
>
<DefaultEditor>
<GraphTransformsPanel group="Dev" name="Transforms" />
<Panel group="Dev" name="JSON">
<div className="mocks">
<Select
Expand All @@ -126,14 +136,13 @@ class App extends Component {
placeholder={'Search for a mock'}
/>
</div>
<br />
<button
className="devbtn"
onClick={this.loadJSON}
style={{background: this.state.json_error ? 'pink' : 'white'}}
>
Save
</button>
<br />
<AceEditor
mode="json"
theme="textmate"
Expand All @@ -152,10 +161,12 @@ class App extends Component {
exec: this.loadJSON,
},
]}
editorProps={{$blockScrolling: true}}
/>
</Panel>
<Panel group="Dev" name="Inspector">
<button
className="devbtn"
onClick={() => {
const gd = document.getElementById('gd') || {};
this.setState({
Expand All @@ -168,7 +179,6 @@ class App extends Component {
>
Refresh
</button>
<br />
<div style={{height: '80vh'}}>
<Inspector
data={{_full: this.state.full}}
Expand Down
1 change: 1 addition & 0 deletions dev/mocks.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[
"/mocks/aggregate.json",
"0.json",
"1.json",
"10.json",
Expand Down
44 changes: 44 additions & 0 deletions dev/mocks/aggregate.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"data": [
{
"type": "scatter",
"x": [
"Moe",
"Larry",
"Curly",
"Moe",
"Larry",
"Curly",
"Moe",
"Larry",
"Curly",
"Moe",
"Larry",
"Curly"
],
"y": [1, 6, 2, 8, 2, 9, 4, 5, 1, 5, 2, 8],
"mode": "markers",
"transforms": [
{
"enabled" :true,
"type": "aggregate",
"groups": [
"Moe",
"Larry",
"Curly",
"Moe",
"Larry",
"Curly",
"Moe",
"Larry",
"Curly",
"Moe",
"Larry",
"Curly"
],
"aggregations": [{"target": "y", "func": "avg", "enabled": true}]
}
]
}
]
}
5 changes: 5 additions & 0 deletions dev/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ body {
.mocks * {
z-index: 100;
}

.devbtn {
margin: 10px;
background: white;
}
18 changes: 18 additions & 0 deletions src/EditorControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,24 @@ class EditorControls extends Component {
}
break;

case EDITOR_ACTIONS.DELETE_TRANSFORM:
if (isNumeric(payload.transformIndex)) {
for (let i = 0; i < graphDiv.data.length; i++) {
if ((graphDiv.data[i].uid === payload.traceUid) !== -1) {
graphDiv.data[i].transforms.splice(payload.transformIndex, 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!== -1
....
I don't get it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoops, nice catch, that's me refactoring badly

if (this.props.onUpdate) {
this.props.onUpdate(
graphDiv.data,
Object.assign({}, graphDiv.layout),
graphDiv._transitionData._frames
);
}
break;
}
}
}
break;

default:
throw new Error('must specify an action type to handleEditorUpdate');
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/containers/ModalBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import classnames from 'classnames';

export default class ModalBox extends Component {
render() {
const {backgroundDark, children, onClose} = this.props;
const {backgroundDark, children, onClose, relative} = this.props;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hack for PanelHeader modal styling

const modalboxClass = classnames('modalbox', {
'modalbox--dark': backgroundDark,
'modalbox--relative': relative,
});
return (
<div className={modalboxClass}>
Expand All @@ -19,6 +20,7 @@ export default class ModalBox extends Component {

ModalBox.propTypes = {
backgroundDark: PropTypes.bool,
relative: PropTypes.bool,
children: PropTypes.node,
onClose: PropTypes.func,
};
35 changes: 33 additions & 2 deletions src/components/containers/PanelHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@ import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {PlusIcon, ResizeUpIcon, ResizeDownIcon} from 'plotly-icons';
import {localize} from 'lib';
import ModalBox from './ModalBox';

class PanelHeader extends Component {
constructor() {
super();
this.state = {addPanelOpen: false};

this.togglePanel = this.togglePanel.bind(this);
}

togglePanel() {
this.setState({addPanelOpen: !this.state.addPanelOpen});
}

render() {
const {
children,
Expand Down Expand Up @@ -43,10 +55,29 @@ class PanelHeader extends Component {
<Button
variant="primary"
className="js-add-button"
onClick={() => addAction.handler(this.context)}
onClick={
Array.isArray(addAction.handler)
? this.togglePanel
: () => addAction.handler(this.context)
}
icon={icon}
label={addAction.label}
/>{' '}
/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this allows for dropdowns on +... needs better styling!

Copy link
Member

@bpostlethwaite bpostlethwaite Mar 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make an issue for this with a screenshot so @aulneau can apply his magic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes once merged

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{this.state.addPanelOpen && (
<ModalBox onClose={this.togglePanel} relative>
{addAction.handler.map(({label, handler}) => (
<p
key={label}
onClick={() => {
handler(this.context);
this.togglePanel();
}}
>
{label}
</p>
))}
</ModalBox>
)}
</div>
) : null}
</div>
Expand Down
9 changes: 6 additions & 3 deletions src/components/containers/RangeSelectorAccordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class RangeSelectorAccordion extends Component {
<RangeSelectorFold
key={i}
rangeselectorIndex={i}
buttonIndex={i}
name={btn.label}
canDelete={true}
>
Expand All @@ -40,11 +39,15 @@ class RangeSelectorAccordion extends Component {
handler: context => {
const {fullContainer, updateContainer} = context;
if (updateContainer) {
const shapeIndex = Array.isArray(fullContainer.rangeselector.buttons)
const rangeselectorIndex = Array.isArray(
fullContainer.rangeselector.buttons
)
? fullContainer.rangeselector.buttons.length
: 0;

updateContainer({[`rangeselector.buttons[${shapeIndex}]`]: {}});
updateContainer({
[`rangeselector.buttons[${rangeselectorIndex}]`]: {},
});
}
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/containers/Section.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class Section extends Component {
}
return (
<div className="section">
<SectionHeader name={this.props.name} />
{this.props.name && <SectionHeader name={this.props.name} />}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this turns Section into a slim container if no name is provided.

{this.children}
</div>
);
Expand Down
66 changes: 66 additions & 0 deletions src/components/containers/TransformAccordion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import Fold from './Fold';
import Panel from './Panel';
import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {connectTransformToTrace, localize} from 'lib';

const TransformFold = connectTransformToTrace(Fold);

class TransformAccordion extends Component {
render() {
const {fullContainer: {transforms = []}} = this.context;
const {children, localize: _} = this.props;

const transformTypes = [
{label: _('Filter'), type: 'filter'},
{label: _('Split'), type: 'groupby'},
{label: _('Aggregate'), type: 'aggregate'},
];

const filteredTransforms = transforms.filter(({type}) => Boolean(type));
const content =
filteredTransforms.length &&
filteredTransforms.map((tr, i) => (
<TransformFold
key={i}
transformIndex={i}
name={transformTypes.filter(({type}) => type === tr.type)[0].label}
canDelete={true}
>
{children}
</TransformFold>
));

const addAction = {
label: _('Transform'),
handler: transformTypes.map(({label, type}) => {
return {
label,
handler: context => {
const {fullContainer, updateContainer} = context;
if (updateContainer) {
const transformIndex = Array.isArray(fullContainer.transforms)
? fullContainer.transforms.length
: 0;
const key = `transforms[${transformIndex}]`;
updateContainer({[key]: {type}});
}
},
};
}),
};

return <Panel addAction={addAction}>{content ? content : null}</Panel>;
}
}

TransformAccordion.contextTypes = {
fullContainer: PropTypes.object,
};

TransformAccordion.propTypes = {
children: PropTypes.node,
localize: PropTypes.func,
};

export default localize(TransformAccordion);
2 changes: 2 additions & 0 deletions src/components/containers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import MenuPanel from './MenuPanel';
import Panel from './Panel';
import Section from './Section';
import TraceAccordion from './TraceAccordion';
import TransformAccordion from './TransformAccordion';
import TraceMarkerSection from './TraceMarkerSection';
import {LayoutPanel, TraceTypeSection} from './derived';
import TraceRequiredPanel from './TraceRequiredPanel';
Expand All @@ -30,6 +31,7 @@ export {
Panel,
Section,
TraceAccordion,
TransformAccordion,
TraceMarkerSection,
TraceRequiredPanel,
LayoutPanel,
Expand Down
Loading