Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2a5a3ed
create structure for new forked explore view (#1099)
Sep 14, 2016
7c77286
Created store and reducers (#1108)
vera-liu Sep 21, 2016
9931490
do use bootstrap data for now
Sep 23, 2016
7175952
don't deal with bootstrap data for now
Sep 23, 2016
25d70d6
use victory as a base
Sep 26, 2016
085b424
import fake line data, add fake panels, make chart fixed
Sep 26, 2016
03b6316
add fetch support
Sep 26, 2016
c1aed1d
get slice data from json endpoint
Sep 26, 2016
3e4375e
render chart with slicejson
Sep 26, 2016
f3cf9a9
update chart and label demo
Sep 27, 2016
dc9a705
remove fetch config
Sep 29, 2016
e29bca9
remove dummy control panels
Sep 29, 2016
e5cc1c5
should be a func
Sep 29, 2016
fa6a480
make TimeSeriesLineChart
Sep 29, 2016
e036d95
add a comment
Sep 29, 2016
dc1669a
inner height for height
Sep 29, 2016
6741c4e
add line chart, dummy data, v2 query and save bans
Oct 4, 2016
dc9702b
don't need fetch yet
Oct 4, 2016
4bacd74
trailing comma breaks in package json
Oct 4, 2016
65aa771
pass in viz data from props
Oct 4, 2016
445b432
add style sheet
Oct 5, 2016
aa7502b
set height on explore container
Oct 5, 2016
f0a7f10
add legend
Oct 5, 2016
84492bb
make chart responsive to window resize
Oct 5, 2016
ed767f9
can't use head_css in template bc overrides head_css in basic
Oct 5, 2016
76eb092
fix linting
Oct 5, 2016
142ec07
break labelItem into own SFC, make legend SFC
Oct 5, 2016
c716043
add propTypes and fix linter
Oct 6, 2016
6f289a3
Merge branch 'master' into alanna-chart-and-controls
Oct 6, 2016
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
173 changes: 173 additions & 0 deletions caravel/assets/javascripts/components/VictoryTheme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
const { assign } = Object;
Copy link
Contributor

Choose a reason for hiding this comment

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

unrelated question, if we are not using babel-polyfill are we relying on Object.assign coming from chrome / the browser?

Copy link
Author

Choose a reason for hiding this comment

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

we use babel and these presets so Object.assign is polyfilled.

 "babel": "^6.3.26",
    "babel-core": "^6.10.4",
    "babel-loader": "^6.2.4",
    "babel-preset-airbnb": "^2.0.0",
    "babel-preset-react": "^6.11.1",


const A11Y_BABU = '#00A699';
const AXIS_LINE_GRAY = '#484848';

// Colors
const colors = [
'#ffffff',
'#f0f0f0',
'#d9d9d9',
'#bdbdbd',
'#969696',
'#737373',
'#525252',
'#252525',
'#000000',
];

const charcoal = '#484848';

// Typography
const sansSerif = '"Roboto", sans-serif';
const letterSpacing = 'normal';
const fontSize = 8;

// Layout
const baseProps = {
width: 450,
height: 300,
padding: 50,
colorScale: colors,
};

// Labels
const baseLabelStyles = {
fontFamily: sansSerif,
fontSize,
letterSpacing,
padding: 10,
fill: charcoal,
stroke: 'transparent',
};

// Strokes
const strokeLinecap = 'round';
const strokeLinejoin = 'round';

// Create the theme
const theme = {
area: assign({
style: {
data: {
fill: charcoal,
},
labels: baseLabelStyles,
},
}, baseProps),
axis: assign({
style: {
axis: {
fill: 'none',
stroke: AXIS_LINE_GRAY,
strokeWidth: 1,
strokeLinecap,
strokeLinejoin,
},
axisLabel: assign({}, baseLabelStyles, {
padding: 25,
}),
grid: {
fill: 'none',
stroke: 'transparent',
},
ticks: {
fill: 'none',
padding: 10,
size: 1,
stroke: 'transparent',
},
tickLabels: baseLabelStyles,
},
}, baseProps),
bar: assign({
style: {
data: {
fill: A11Y_BABU,
padding: 10,
stroke: 'transparent',
strokeWidth: 0,
width: 8,
},
labels: baseLabelStyles,
},
}, baseProps),
candlestick: assign({
style: {
data: {
stroke: A11Y_BABU,
strokeWidth: 1,
},
labels: assign({}, baseLabelStyles, {
padding: 25,
textAnchor: 'end',
}),
},
candleColors: {
positive: '#ffffff',
negative: charcoal,
},
}, baseProps),
chart: baseProps,
errorbar: assign({
style: {
data: {
fill: 'none',
stroke: charcoal,
strokeWidth: 2,
},
labels: assign({}, baseLabelStyles, {
textAnchor: 'start',
}),
},
}, baseProps),
group: assign({
colorScale: colors,
}, baseProps),
line: assign({
style: {
data: {
fill: 'none',
stroke: A11Y_BABU,
strokeWidth: 2,
},
labels: assign({}, baseLabelStyles, {
textAnchor: 'start',
}),
},
}, baseProps),
pie: {
style: {
data: {
padding: 10,
stroke: 'none',
strokeWidth: 1,
},
labels: assign({}, baseLabelStyles, {
padding: 200,
textAnchor: 'middle',
}),
},
colorScale: colors,
width: 400,
height: 400,
padding: 50,
},
scatter: assign({
style: {
data: {
fill: charcoal,
stroke: 'transparent',
strokeWidth: 0,
},
labels: assign({}, baseLabelStyles, {
textAnchor: 'middle',
}),
},
}, baseProps),
stack: assign({
colorScale: colors,
}, baseProps),
};

export default theme;
72 changes: 64 additions & 8 deletions caravel/assets/javascripts/explorev2/components/ChartContainer.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,67 @@
import React from 'react';
import React, { PropTypes } from 'react';
import { Panel } from 'react-bootstrap';
import TimeSeriesLineChart from './charts/TimeSeriesLineChart';
import moment from 'moment';

const ChartContainer = function () {
return (
<Panel header="Chart title">
chart goes here
</Panel>
);
const propTypes = {
viz: PropTypes.shape({
data: PropTypes.object.isRequired,
form_data: PropTypes.shape({
slice_name: PropTypes.object.isRequired,
}).isRequired,
}).isRequired,
height: PropTypes.number.isRequired,
};
export default ChartContainer;

export default class ChartContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
params: this.getParamsFromUrl(),
data: props.viz.data,
label1: 'Label 1',
};
Copy link
Contributor

Choose a reason for hiding this comment

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

should you add this.getParamsFromUrl = this.getParamsFromUrl.bind(this) + same for formatDates?

Copy link
Author

@ascott ascott Oct 5, 2016

Choose a reason for hiding this comment

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

since getParamsFromUrl and formatDates don't need access to this we don't need to bind this to the methods. typically we would use bind(this) if we were passing a method to an event callback that needed access to the components context.

}

getParamsFromUrl() {
const hash = window.location.search;
Copy link
Contributor

Choose a reason for hiding this comment

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

curious if we've thought about using react router for url state management? I used it in dataportal and liked it.

Copy link
Author

Choose a reason for hiding this comment

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

this is a good suggestion... let's keep it in mind as we continue the refactor

const params = hash.split('?')[1].split('&');
const newParams = {};
params.forEach((p) => {
const value = p.split('=')[1].replace(/\+/g, ' ');
const key = p.split('=')[0];
newParams[key] = value;
});
return newParams;
}

formatDates(values) {
const newValues = values.map(function (val) {
return {
x: moment(new Date(val.x)).format('MMM D'),
Copy link
Contributor

@williaster williaster Oct 5, 2016

Choose a reason for hiding this comment

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

FYI d3 also has really good date formatting utilities, not sure if it'd be more lightweight than moment.

Copy link
Author

Choose a reason for hiding this comment

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

yeah, i'm not sure either.. let's use moment for now and we can change to use d3 time utils in the future if that makes sense

y: val.y,
};
});
return newValues;
}

render() {
return (
<div className="chart-container">
<Panel
style={{ height: this.props.height }}
header={
<div className="panel-title">{this.props.viz.form_data.slice_name}</div>
}
>
<TimeSeriesLineChart
data={this.state.data}
label1="Label 1"
/>
</Panel>
</div>
);
}
}

ChartContainer.propTypes = propTypes;
Original file line number Diff line number Diff line change
@@ -1,26 +1,55 @@
import React from 'react';
import React, { PropTypes } from 'react';
import ChartContainer from './ChartContainer';
import ControlPanelsContainer from './ControlPanelsContainer';
import QueryAndSaveButtons from './QueryAndSaveButtons';

const ExploreViewContainer = function () {
return (
<div className="container-fluid">
<div className="row">
<div className="col-sm-3">
<QueryAndSaveButtons
canAdd="True"
onQuery={() => { console.log('clicked query'); }}
/>
<br /><br />
<ControlPanelsContainer />
</div>
<div className="col-sm-9">
<ChartContainer />
const propTypes = {
data: PropTypes.shape({
viz: PropTypes.object.isRequired,
}).isRequired,
};

export default class ExploreViewContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
height: this.getHeight(),
};
}

getHeight() {
const navHeight = 90;
return `${window.innerHeight - navHeight}px`;
}

render() {
return (
<div
className="container-fluid"
style={{
height: this.state.height,
overflow: 'hidden',
}}
>
<div className="row table-body">
<div className="table-cell col-sm-4">
<QueryAndSaveButtons
canAdd="True"
onQuery={() => {}}
/>
<br /><br />
<ControlPanelsContainer />
</div>
<div className="table-cell col-sm-8">
<ChartContainer
viz={this.props.data.viz}
height={this.state.height}
/>
</div>
</div>
</div>
</div>
);
};
);
}
}

export default ExploreViewContainer;
ExploreViewContainer.propTypes = propTypes;
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, { PropTypes } from 'react';
import classnames from 'classnames';

const propTypes = {
canAdd: PropTypes.string.isRequired,
onQuery: PropTypes.func.isRequired,
};

export default function QueryAndSaveBtns({ canAdd, onQuery }) {
const saveClasses = classnames('btn btn-default btn-sm', {
'disabled disabledButton': canAdd !== 'True',
});

return (
<div className="btn-group query-and-save">
<button type="button" className="btn btn-primary btn-sm" onClick={onQuery}>
<i className="fa fa-bolt"></i> Query
</button>
<button
type="button"
className={saveClasses}
data-target="#save_modal"
data-toggle="modal"
>
<i className="fa fa-plus-circle"></i> Save as
</button>
</div>
);
}

QueryAndSaveBtns.propTypes = propTypes;
21 changes: 21 additions & 0 deletions caravel/assets/javascripts/explorev2/components/charts/Legend.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React, { PropTypes } from 'react';
import LegendItem from './LegendItem';

const propTypes = {
data: PropTypes.array.isRequired,
keysToColorsMap: PropTypes.object.isRequired,
};

export default function Legend({ data, keysToColorsMap }) {
const legendEls = data.map((d) => {
const color = keysToColorsMap[d.key] ? keysToColorsMap[d.key] : '#000';
return <LegendItem label={d.key} color={color} key={d.key} />;
});
return (
<ul className="list-unstyled list-inline">
{legendEls}
</ul>
);
}

Legend.propTypes = propTypes;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { PropTypes } from 'react';

const propTypes = {
label: PropTypes.string.isRequired,
color: PropTypes.string.isRequired,
};

export default function LegendItem({ label, color }) {
return (
<li style={{ float: 'left' }} key={label}>
<i className="fa fa-circle" style={{ color }} /> &nbsp;&nbsp;
<span>{label}</span>
</li>
);
}

LegendItem.propTypes = propTypes;
Loading