Skip to content

Instantly share code, notes, and snippets.

@shimizu
Last active March 5, 2018 03:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shimizu/9f5668fe0a7eae02bca555286bfb6bce to your computer and use it in GitHub Desktop.
Save shimizu/9f5668fe0a7eae02bca555286bfb6bce to your computer and use it in GitHub Desktop.
D3 v4 - CSS 3D Line Chart
license: mit
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>CSS 3D Line Chart</title>
<style>
html, body {
width: 100%;
height:100%;
}
#chart {
width: 980px;
height:500px;
transform: perspective( 600px ) rotateY( 45deg );
}
</style>
</head>
<body>
<svg id="chart"></svg>
<script src="//unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="//unpkg.com/d3@4.12.2/build/d3.min.js"></script>
<script type="text/babel">
const width = 980;
const height = 400;
const margin = {top:50, left:100, bottom:20, right:0 };
const pw = width - (margin.left + margin.right);
const ph = height - (margin.top + margin.bottom);
//各種レイヤー要素を追加
const svg = d3.select('#chart')
const stage = svg.append("g")
const gridLayer = stage.append("g").classed("gridLayer", true)
.attr("transform", `translate(${margin.left}, ${margin.top})`)
const axisLayer = stage.append("g").classed("axisLayer", true)
.attr("transform", `translate(${margin.left}, ${margin.top})`)
const lineLayer = stage.append("g").classed("lineLayer", true)
.attr("transform", `translate(${margin.left}, ${margin.top})`)
//ランダムにデータセットを作る
const indexSeries = d3.range(30).map(d => {
return {x:d, y:Math.floor(Math.random()*5200)+1}
})
//スケール設定
const xScale = d3.scaleLinear().domain([0, d3.max(indexSeries, d => d.x )]).range([0, pw])
const yScale = d3.scaleLinear().domain([0, d3.max(indexSeries, d => d.y )]).range([ph, 0])
//ライン生成関数を用意
const lineFunction = d3.line()
.x(d => xScale(d.x) )
.y(d => yScale(d.y) )
//ステージを奥に向かって進むようにアニメーション
stage.attr("transform", "translate(100, 50)")
.transition()
.duration(6000)
.attr("transform", "translate(-400, 0)")
// svg filter要素を追加
const filter = stage.append("defs").append('filter')
.attr("id", "drop-shadow")
.attr("width", "150%")
.attr("height", "150%")
filter.append('feGaussianBlur')
.attr("in", "SourceAlpha")
.attr("result", "blur")
.attr("stdDeviation", 2)
filter.append('feOffset')
.attr("result", "offsetBlur")
.attr("dx", 4)
.attr("dy", 4)
filter.append('feBlend')
.attr("in", "SourceGraphic")
.attr("in2", "offsetBlur")
.attr("mode", "normal")
// フィルター追加 end
//線グラフ追加
const line = lineLayer.append('path')
.attr("filter", "url(#drop-shadow)");
//線グラフのアニメーション
line.transition()
.duration(6000)
.attr('fill', 'none')
.attr('stroke', 'black')
.attrTween('d', getSmoothInterpolation);
//グリッド追加
const xGrid = gridLayer.append("g")
.attr("transform", `translate(0, ${ph})`)
.call(d3.axisBottom()
.scale(xScale)
.ticks(40)
.tickSize(-ph, 0, 0)
.tickFormat("")
)
xGrid.select(".domain").remove();
xGrid.selectAll(".tick line")
.attr("stroke", "#ccc")
const yGrid = gridLayer.append("g")
.call( d3.axisRight()
.scale(yScale)
.ticks(20)
.tickSize(width-margin.left, 0, 0)
.tickFormat("")
)
yGrid.select(".domain").remove();
yGrid.selectAll(".tick line")
.attr("stroke", "#ccc")
//軸追加
const xAxis = d3.axisBottom().scale(xScale)
const yAxis = d3.axisLeft().scale(yScale)
axisLayer.append("g") // Add the X Axis
.attr("transform", `translate(0, ${ph})`)
.call(xAxis);
axisLayer.append("g") // Add the Y Axis
.call(yAxis);
//パス用のカスタムトランジション
function getSmoothInterpolation() {
const interpolate = d3.scaleLinear()
.domain([0,1])
.range([1, indexSeries.length + 1]);
return function(t) {
const flooredX = Math.floor(interpolate(t));
const interpolatedLine = indexSeries.slice(0, flooredX);
if(flooredX > 0 && flooredX < indexSeries.length) {
const weight = interpolate(t) - flooredX;
const weightedLineAverage = indexSeries[flooredX].y * weight + indexSeries[flooredX-1].y * (1-weight);
interpolatedLine.push({"x":interpolate(t)-1, "y":weightedLineAverage});
}
return lineFunction(interpolatedLine);
}
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment