|
<!DOCTYPE html> |
|
<meta charset='utf-8'> |
|
<style> |
|
|
|
body { |
|
font: 10px sans-serif; |
|
shape-rendering: crispEdges; |
|
} |
|
|
|
.day { |
|
fill: #fff; |
|
stroke: #ccc; |
|
} |
|
|
|
.month { |
|
fill: none; |
|
stroke: #000; |
|
stroke-width: 2px; |
|
} |
|
|
|
.RdYlGn .q0-11{fill:rgb(165,0,38)} |
|
.RdYlGn .q1-11{fill:rgb(215,48,39)} |
|
.RdYlGn .q2-11{fill:rgb(244,109,67)} |
|
.RdYlGn .q3-11{fill:rgb(253,174,97)} |
|
.RdYlGn .q4-11{fill:rgb(254,224,139)} |
|
.RdYlGn .q5-11{fill:rgb(255,255,191)} |
|
.RdYlGn .q6-11{fill:rgb(217,239,139)} |
|
.RdYlGn .q7-11{fill:rgb(166,217,106)} |
|
.RdYlGn .q8-11{fill:rgb(102,189,99)} |
|
.RdYlGn .q9-11{fill:rgb(26,152,80)} |
|
.RdYlGn .q10-11{fill:rgb(0,104,55)} |
|
|
|
</style> |
|
<body> |
|
<script src='//d3js.org/d3.v4.min.js'></script> |
|
<script src='https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.0/babel.min.js'></script> |
|
<script lang='babel' type='text/babel'> |
|
const width = 960; // cell size |
|
const height = 136; |
|
const cellSize = 17; |
|
const percent = d3.format('.1%'); |
|
const format = d3.timeFormat('%Y-%m-%d'); |
|
|
|
const color = d3.scaleQuantize() |
|
.domain([-.05, .05]) |
|
.range(d3.range(11).map(d => `q${d}-11`)); |
|
|
|
const svg = d3.select('body').selectAll('svg') |
|
.data(d3.range(1990, 2011)) |
|
.enter().append('svg') |
|
.attr('width', width) |
|
.attr('height', height) |
|
.attr('class', 'RdYlGn') |
|
.append('g') |
|
.attr('transform', `translate(${(width - cellSize * 53) / 2},${height - cellSize * 7 - 1})`); |
|
|
|
svg.append('text') |
|
.attr('transform', `translate(-6,${cellSize * 3.5})rotate(-90)`) |
|
.style('text-anchor', 'middle') |
|
.text(d => d); |
|
|
|
const rect = svg.selectAll('.day') |
|
.data(d => d3.timeDays(new Date(d, 0, 1), new Date(d + 1, 0, 1))) |
|
.enter().append('rect') |
|
.attr('class', 'day') |
|
.attr('width', cellSize) |
|
.attr('height', cellSize) |
|
.attr('x', d => d3.timeWeek.count(d3.timeYear(d), d) * cellSize) |
|
.attr('y', d => d.getDay() * cellSize) |
|
.datum(format); |
|
|
|
rect.append('title') |
|
.text(d => d); |
|
|
|
svg.selectAll('.month') |
|
.data(d => d3.timeMonths(new Date(d, 0, 1), new Date(d + 1, 0, 1))) |
|
.enter().append('path') |
|
.attr('class', 'month') |
|
.attr('d', monthPath); |
|
|
|
d3.csv('dji.csv', (error, csv) => { |
|
if (error) throw error; |
|
|
|
const data = d3.nest() |
|
.key(d => d.Date) |
|
.rollup(d => (d[0].Close - d[0].Open) / d[0].Open) |
|
.map(csv); |
|
console.log('data', data) |
|
|
|
rect.filter(d => { |
|
const key = `$${d}`; |
|
return key in data; |
|
}) |
|
.attr('class', d => `day ${color(data['$'+d])}`) |
|
.select('title') |
|
.text(d => `${d}: ${percent(data['$'+d])}`); |
|
}); |
|
|
|
function monthPath(t0) { |
|
const t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0); |
|
const d0 = t0.getDay(); |
|
const w0 = d3.timeWeek.count(d3.timeYear(t0), t0); |
|
const d1 = t1.getDay(); |
|
const w1 = d3.timeWeek.count(d3.timeYear(t1), t1); |
|
return `M${(w0 + 1) * cellSize},${d0 * cellSize}H${w0 * cellSize}V${7 * cellSize}H${w1 * cellSize}V${(d1 + 1) * cellSize}H${(w1 + 1) * cellSize}V${0}H${(w0 + 1) * cellSize}Z`; |
|
} |
|
</script> |