Skip to content
This repository has been archived by the owner on Aug 4, 2020. It is now read-only.

Add "live" chart to homepage #97

Merged
merged 1 commit into from
Aug 19, 2016
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"sinon": "^1.17.2",
"sinon-chai": "^2.8.0",
"victory": "*",
"victory-chart": "^10.3.0",
"victory-examples": "*"
}
}
15 changes: 13 additions & 2 deletions src/screens/home/components/benefits.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Demo from "./demo";
import DemoFlexible from "./demo-flexible";
import DemoNative from "./demo-native";
import DemoSharedEvents from "./demo-shared-events";
import DemoLiveChart from "./demo-live-chart";

class Benefits extends React.Component {
getStyles() {
Expand Down Expand Up @@ -41,7 +42,7 @@ class Benefits extends React.Component {
},
flexItem: {
flex: "1 0 auto",
margin: `${VictorySettings.gutter * 2}px 3vw 0`,
margin: `${VictorySettings.gutter * 2}px 1vw 0`,
minWidth: "360px",
textAlign: "center"
},
Expand Down Expand Up @@ -83,7 +84,7 @@ class Benefits extends React.Component {
</p>
</div>
<div style={styles.flexItem}>
<DemoSharedEvents />
<DemoSharedEvents/>
<p>
<a
href="https://github.com/FormidableLabs/victory-examples/blob/master/src/components/shared-events.js"
Expand All @@ -92,6 +93,16 @@ class Benefits extends React.Component {
</a>
</p>
</div>
<div style={styles.flexItem}>
<DemoLiveChart/>
<p>
<a
href="https://github.com/FormidableLabs/victory-docs/blob/master/src/screens/home/components/livechart.js"
>
<span style={styles.smallCaps}>View source</span>&nbsp;<Icon glyph="external-link" />
</a>
</p>
</div>
</div>

{/* Friendly */}
Expand Down
86 changes: 86 additions & 0 deletions src/screens/home/components/demo-live-chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React from "react";
import { last, mean } from "lodash";
import LiveChart from "./livechart";

export default class DemoLiveChart extends React.Component {
constructor(props) {
super(props);
this.period = 2000;
this.domain = [54.6, 55.25];
this.maxPoints = 30;
this.state = {
data: this.getInitialData()
};
}

nextPoint(previous = null) {
const [low, high] = this.domain;
const newPoint = low + Math.random() * (high - low);
return previous ? mean([previous, newPoint]) : newPoint;
}

getInitialData() {
return [
{x: 0, y: this.domain[0] + 0.05},
{x: 1, y: this.domain[0] + 0.15}
];
}

getNewData() {
const data = this.state.data;

if (data.length !== this.maxPoints) {
// add one
const lastPoint = last(data);
data.push(
{y: this.nextPoint(lastPoint.y), x: lastPoint.x + 1}
);
return data;
} else {
return this.getInitialData();
}
}

componentDidMount() {
this.setStateInterval = setInterval(() => {
this.setState({ // eslint-disable-line react/no-did-mount-set-state
data: this.getNewData()
});
}, this.period);
}

componentWillUnmount() {
clearInterval(this.setStateInterval);
}

getStyles() {
return {
parent: {
display: "block",
boxSizing: "border-box",
margin: "0 auto",
padding: 0,
width: "auto",
height: "100%",
maxHeight: "280px"
}
};
}

render() {
const styles = this.getStyles();
return (
<svg
viewBox="0 0 450 350"
className="fancyBorder"
style={styles.parent}
>
<LiveChart
data={this.state.data}
period={this.period}
domain={this.domain}
/>
</svg>
);
}
}
78 changes: 78 additions & 0 deletions src/screens/home/components/livechart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from "react";
import { round } from "lodash";
import { VictoryAxis, VictoryChart, VictoryLine, VictoryScatter } from "victory-chart";

const leftPad = (str, len, ch) => {
str = String(str);
let i = -1;
if (!ch && ch !== 0) {
ch = " ";
}
len -= str.length;
while (++i < len) {
str = ch + str;
}
return str;
};

const start = Date.now();

const makeDate = (period, count) => {
const date = new Date(start + count * period);
const hours = leftPad(date.getHours(), 2, 0);
const minutes = leftPad(date.getMinutes(), 2, 0);
const seconds = leftPad(date.getSeconds(), 2, 0);
return `${hours}:${minutes}:${seconds}`;
};

const LiveChart = ({data, period, domain}) => (
<VictoryChart
animate={{ duration: 1000 }}
Copy link
Contributor

Choose a reason for hiding this comment

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

If this code is editable you might want to express this animation duration in terms of props.duration

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, you're right. Or rename props.duration. That name is kind of misleading at this point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

✅ cleared this up

padding={{
left: 80,
right: 50,
top: 20,
bottom: 30
}}
>
<VictoryAxis
tickFormat={makeDate.bind(null, period)}
tickCount={3}
style={{
ticks: {stroke: "black", strokeWidth: 3}
}}
/>
<VictoryAxis dependentAxis
label="Price"
tickCount={4}
tickFormat={(y) => round(y, 2)}
domain={domain}
style={{
axisLabel: {
padding: 50
},
ticks: {stroke: "black", strokeWidth: 3}
}}
/>
<VictoryLine
data={data}
interpolation="monotoneX"
style={{
data: { strokeWidth: 1 }
}}
/>
<VictoryScatter
data={data}
size={5}
style={{
data: {
fill: "black",
stroke: "white",
strokeWidth: 3
}
}}
/>
</VictoryChart>
);

export default LiveChart;