Skip to content

Instantly share code, notes, and snippets.

@milroc
Last active June 29, 2016 20:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milroc/aacdb75156d51d9dbe4d to your computer and use it in GitHub Desktop.
Save milroc/aacdb75156d51d9dbe4d to your computer and use it in GitHub Desktop.
A quick React + D3 sparkline

Just a quick example of how I use React + d3 now a days.

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xpa1/t39.3284-6/12512178_218562685145124_130271029_n.js"></script>
<script src="https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-xfa1/t39.3284-6/12512184_1664789273772979_614489084_n.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.js"></script>
</head>
<body>
<div id='example'></div>
<script type="text/babel">
class Sparkline extends React.Component {
constructor(props) {
super(props);
this.xScale = d3.scale.linear();
this.yScale = d3.scale.linear();
this.line = d3.svg.line();
this._updateDataTransforms(props);
}
componentDidMount() {
const self = this;
d3.select(ReactDOM.findDOMNode(this.refs.svg))
.on('mousemove', function() { self._onMouseMove(d3.mouse(this)[0]); })
.on('mouseleave', function() { self._onMouseMove(null); });
}
componentWillReceiveNewProps(newProps) {
this._updateDataTransforms(newProps);
}
_updateDataTransforms(props) {
const {xAccessor, yAccessor, width, height, data} = props;
this.xScale
.domain([0, data.length])
.range([0, width]);
this.yScale
.domain([0, 10])
.range([height, 0]);
this.line
.x((d, i) => this.xScale(xAccessor(d, i)))
.y((d, i) => this.yScale(yAccessor(d, i)));
this.bisectByX = d3.bisector(xAccessor).left;
}
_onMouseMove(xPixelPos) {
const {data, onHover} = this.props;
if (xPixelPos === null) {
onHover(null, null);
}
else {
const xValue = this.xScale.invert(xPixelPos);
const i = this.bisectByX(data, xValue, 1);
onHover(data[i], i);
}
}
render() {
const {data, width, height, xAccessor, hovered} = this.props;
const hoveredRender = (hovered)
? (
<line
x1={this.xScale(xAccessor(hovered))}
x2={this.xScale(xAccessor(hovered))}
y0={0}
y1={height}
style={{strokeWidth: '0.5px', stroke: 'steelblue'}}
/>
)
: null;
return (
<svg width={width} height={height} ref="svg">
<path
style={{fill: 'none', strokeWidth: '0.5px', stroke: 'steelblue'}}
d={this.line(data)}
/>
{hoveredRender}
</svg>
);
}
}
Sparkline.defaultProps = {
xAccessor: ({x}) => x,
yAccessor: ({y}) => y,
};
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
hovered: null,
};
}
render() {
const {data} = this.props;
const {hovered} = this.state;
const value = (hovered)
? hovered.y
: data.reduce((s, {y}) => s + y, 0); // total
return (
<div>
<Sparkline
data={data}
width={100}
height={20}
hovered={hovered}
onHover={(hovered, index) => this.setState({hovered})}
/>
{value}
</div>
);
}
}
let data = [3, 6, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 9, 3, 6, 3, 6, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 9, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 9, 3, 6, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 9];
// Interesting fact: d3.bisect accessors assume your not bisecting by the index.
// Duh...
data = data.map((y, x) => { return {x, y}; });
ReactDOM.render(
<Example data={data} />,
document.getElementById('example')
);
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment