Skip to content

Instantly share code, notes, and snippets.

@shimizu
Last active January 23, 2021 20:36
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 shimizu/99bec95ee50425a0f6eee27812e351c7 to your computer and use it in GitHub Desktop.
Save shimizu/99bec95ee50425a0f6eee27812e351c7 to your computer and use it in GitHub Desktop.
React & D3 v4 example - Line Chart

React と D3 ver.4 組み合わせて使うサンプル。

まだ、試行錯誤中。

Made with blockup-react

//todo:後で分割する。
import * as d3 from "d3";
import React, { Component } from "react";
export default function D3blackbox(d3render) {
return class Blackbox extends Component {
componentDidMount() {
d3render.call(this);
}
componentDidUpdate() {
d3render.call(this);
}
render() {
const transform = this.props.transform || "";
return <g transform={transform} ref="anchor" />;
}
};
}
export const XAxis = D3blackbox(function() {
const axis = d3
.axisBottom()
.tickFormat(d => d3.timeFormat("%H:%M %S")(d))
.scale(this.props.xScale);
d3
.select(this.refs.anchor)
.classed("xAxis", true)
.transition()
.call(axis);
});
export const YAxis = D3blackbox(function() {
const axis = d3
.axisLeft()
.tickFormat(d => d)
.scale(this.props.yScale);
d3
.select(this.refs.anchor)
.classed("yAxis", true)
.transition()
.call(axis);
});
export const YGrid = D3blackbox(function() {
const axis = d3
.axisRight()
.tickFormat(d => null)
.scale(this.props.yScale)
.tickSizeOuter(0)
.tickSizeInner(this.props.plotWidth);
d3
.select(this.refs.anchor)
.classed("yGrid", true)
.call(axis);
});
export const Line = D3blackbox(function() {
const path = d3
.line()
.x(d => d.x)
.y(d => d.y);
const parent = d3.select(this.refs.anchor);
const current = parent.selectAll(".valueLine").data([this.props.plotData]);
current.interrupt();
const enter = current
.enter()
.append("path")
.classed("valueLine", true);
const valueLine = current.merge(enter);
current
.transition()
.attr("transform", `translate(${this.props.xSlide}, 0)`)
.on("end", () => {
valueLine.attr("d", path);
current.attr("transform", null);
});
});
import * as d3 from "d3";
/*
export const loadAllData = (callback = () => {} ) => {
const q = d3.queue()
q.defer(d3.tsv, './data.tsv', cast)
q.await((error, data) =>{
callback(data);
})
}
*/
//デモ用ランダムデータ生成function
const MakeData = () => {
const rnd = d3.randomNormal(180, 20);
let data = d3
.range(300)
.map(i => {
return { date: new Date(new Date().getTime() - 1000 * i), value: rnd() };
})
.reverse();
return () => {
data.push({ date: new Date(), value: rnd() });
data.shift();
return data;
};
};
const md = MakeData();
export const loadAllData = (callback = () => {}) => {
callback(md());
};
body,html{width:100%;heigth:100%;padding:0x;margin:0}.axisLaeyr .xAxis .domain,.axisLaeyr .xAxis .tick>line{display:none}.axisLaeyr .yAxis .domain,.axisLaeyr .yAxis .tick>line{display:none}.axisLaeyr .yGrid .domain{display:none}.axisLaeyr .yGrid .tick>line{stroke-dasharray:3}.plotLayer .valueLine{fill:none;stroke-width:1.5;stroke:#00f}.button{width:100%}.button button{display:block;width:100px;height:50px;margin:0 auto}
import React, { Component } from "react";
import * as d3 from "d3";
import { XAxis, YAxis, YGrid, Line } from "./ChartComponents.js";
class LineChart extends Component {
constructor(props) {
super();
}
updateScale(props) {
const data = props.data;
const xScale = d3.scaleTime();
const yScale = d3.scaleLinear().nice();
const xDomain = d3.extent(data, d => d.date);
const yDomain = props.yDomain || [0, d3.max(data, d => props.yFn(d))];
xScale
.domain(xDomain)
.range([0, props.width - (props.margin.left + props.margin.right)]);
yScale
.domain(yDomain)
.range([props.height - (props.margin.top + props.margin.bottom), 0]);
return {xScale, yScale}
}
updatePlotSize(props){
const plotWidth =
props.width - (props.margin.left + props.margin.right);
const plotHeight =
props.height - (props.margin.top + props.margin.bottom);
return {plotWidth, plotHeight}
}
render() {
const {xScale, yScale} = this.updateScale(this.props);
const {plotWidth, plotHeight} = this.updatePlotSize(this.props);
const metaData = {
xScale: xScale,
yScale: yScale,
plotWidth: plotWidth,
plotHeight: plotHeight,
xSlide: -xScale(this.props.xFn(this.props.data[1]))
};
const plotData = {
plotData: this.props.data.map((d, i) => {
return {
id: i,
data: d,
x: xScale(this.props.xFn(d)),
y: yScale(this.props.yFn(d))
};
})
};
return (
<svg width={this.props.width} height={this.props.height}>
<g
className="axisLaeyr"
width={plotWidth}
height={plotHeight}
transform={`translate(${this.props.margin.left}, ${this.props.margin
.top})`}
>
<YGrid {...metaData} />
<XAxis {...metaData} transform={`translate(0,${plotHeight})`} />
<YAxis {...metaData} />
</g>
<g
className="plotLayer"
width={plotWidth}
height={plotHeight}
transform={`translate(${this.props.margin.left}, ${this.props.margin
.top})`}
>
<Line {...metaData} {...plotData} />
</g>
</svg>
);
}
}
export default LineChart;
This file has been truncated, but you can view the full file.
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment