forked from devgru's block: Simple stream + interpolation, layout offset & axes
forked from anonymous's block: Simple stream + interpolation, layout offset & axes
| license: mit |
forked from devgru's block: Simple stream + interpolation, layout offset & axes
forked from anonymous's block: Simple stream + interpolation, layout offset & axes
| <!DOCTYPE html> | |
| <meta charset='utf-8'> | |
| <style> | |
| body { font: 10px sans-serif; } | |
| p { font: 12px helvetica; } | |
| .axis path, .axis line { | |
| fill: none; | |
| stroke: #000; | |
| stroke-width: 2px; | |
| shape-rendering: crispEdges; | |
| } | |
| </style> | |
| <body> | |
| <script src='http://d3js.org/d3.v4.js'></script> | |
| <script src='http://d3js.org/colorbrewer.v1.js'></script> | |
| <script> | |
| var parse = d3.timeParse('%m/%d/%y') | |
| var margin = {top: 20, right: 40, bottom: 30, left: 30} | |
| var width = 600 - margin.left - margin.right | |
| var height = 400 - margin.top - margin.bottom | |
| var x = d3.scaleTime().range([0, width]) | |
| var y = d3.scaleLinear().range([height - 10, 0]) | |
| var color = d3.scaleOrdinal().range(colorbrewer['Blues'][6]) | |
| var xAxis = d3.axisBottom() | |
| .scale(x) | |
| var yAxis = d3.axisLeft() | |
| .scale(y) | |
| var yAxis2 = d3.axisRight() | |
| .scale(y) | |
| var area = d3.area() | |
| .curve(d3.curveCardinalOpen) | |
| .x(function(d) { return x(d.date) }) | |
| .y0(function(d) { return y(d.coords[0]) }) | |
| .y1(function(d) { return y(d.coords[1]) }) | |
| var svg = d3.select('body') | |
| .append('svg') | |
| .attr('width', width + margin.left + margin.right) | |
| .attr('height', height + margin.top + margin.bottom) | |
| .append('g') | |
| .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') | |
| function prepareData(data) { | |
| var nestedByDate = d3.nest() | |
| .key(function(d) { return d.date }) | |
| .entries(data); | |
| var nestedByKey = d3.nest() | |
| .key(function(d) { return d.key }) | |
| .entries(data); | |
| var keys = nestedByKey.map(function(d) { return d.key }); | |
| var stack = d3.stack() | |
| .offset(d3.stackOffsetSilhouette) // wiggle | |
| .value(function(d, k) { | |
| return d.values.filter(function(d) { | |
| return d.key == k; | |
| })[0].value | |
| }) | |
| .keys(keys) | |
| var result = stack(nestedByDate) | |
| nestedByKey.forEach(function(d, i) { | |
| d.values.forEach(function(v, j) { | |
| v.coords = result[i][j] | |
| }) | |
| }); | |
| return nestedByKey; | |
| } | |
| d3.csv('https://d3.devg.ru/data/stream.csv', function(d) { | |
| d.date = parse(d.date) | |
| d.value = Number(d.value) | |
| return d | |
| }, function (data) { | |
| var layers = prepareData(data) | |
| x.domain(d3.extent(data, function (d) { return d.date })) | |
| y.domain([ | |
| d3.min(data, function (d) { return d.coords[0] }), | |
| d3.max(data, function (d) { return d.coords[1] }) | |
| ]) | |
| svg.selectAll('.layer') | |
| .data(layers) | |
| .enter().append('path') | |
| .attr('class', 'layer') | |
| .attr('d', function (d) { | |
| return area(d.values) }) | |
| .style('fill', function (d, i) { return color(i) }) | |
| svg.append('g') | |
| .attr('class', 'x axis') | |
| .attr('transform', 'translate(0,' + height + ')') | |
| .call(xAxis) | |
| svg.append('g') | |
| .attr('class', 'y axis') | |
| .attr('transform', 'translate(' + width + ', 0)') | |
| .call(yAxis2) | |
| svg.append('g') | |
| .attr('class', 'y axis') | |
| .call(yAxis) | |
| }) | |
| </script> |