Built with blockbuilder.org
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
function tooltip(text, chart) {
return (selection) => {
function mouseover(d) {
const path = d3.select(this);
path.classed('highlighted', true);
const mouse = d3.mouse(chart.node());
const tool = chart.append('g')
.attr('id', 'tooltip')
.attr('transform', `translate(${mouse[0] + 5},${mouse[1] + 10})`);
const textNode = tool.append('text')
.text(text(d))
.attr('fill', 'black')
.node();
tool.append('rect')
.attr('height', textNode.getBBox().height)
.attr('width', textNode.getBBox().width)
.style('fill', 'rgba(255, 255, 255, 0.6)')
.attr('transform', 'translate(0, -16)');
tool.select('text')
.remove();
tool.append('text').text(text(d));
}
function mousemove() {
const mouse = d3.mouse(chart.node());
d3.select('#tooltip')
.attr('transform', `translate(${mouse[0] + 15},${mouse[1] + 20})`);
}
function mouseout() {
const path = d3.select(this);
path.classed('highlighted', false);
d3.select('#tooltip').remove();
}
selection.on('mouseover.tooltip', mouseover)
.on('mousemove.tooltip', mousemove)
.on('mouseout.tooltip', mouseout);
};
}
const protoChart = {
width: window.innerWidth,
height: window.innerHeight,
margin: {
left: 10,
right: 10,
top: 10,
bottom: 10,
},
};
function chartFactory(opts, proto = protoChart) {
const chart = Object.assign({}, proto, opts);
chart.svg = d3.select('body')
.append('svg')
.attr('id', chart.id || 'chart')
.attr('width', chart.width - chart.margin.right)
.attr('height', chart.height - chart.margin.bottom);
chart.container = chart.svg.append('g')
.attr('id', 'container')
.attr('transform', `translate(${chart.margin.left}, ${chart.margin.top})`);
return chart;
}
const westerosChart = chartFactory({
margin: { left: 50, right: 50, top: 50, bottom: 50 },
padding: { left: 10, right: 10, top: 10, bottom: 10 },
});
westerosChart.init = function initChart(chartType, dataUri, ...args) {
fetch(dataUri)
.then(res => res.json())
.then(data => this[chartType].call(this, data, ...args));
this.innerHeight = this.height - this.margin.top - this.margin.bottom - this.padding.top - this.padding.bottom;
this.innerWidth = this.width - this.margin.left - this.margin.right - this.padding.left - this.padding.right;
};
westerosChart.histogram = function(_data) {
const data = _data.data.map(d =>
Object.assign(d, { death: (d.death.season * 100) + d.death.episode }))
.sort((a, b) => a.death - b.death);
const episodesPerSeason = 10;
const totalSeasons = 6;
const allEpisodes = d3.range(1, totalSeasons + 1).reduce((episodes, s) =>
episodes.concat(d3.range(1, episodesPerSeason + 1).map(e => (s * 100) + e)), []);
console.dir(allEpisodes);
const x = d3.scaleBand()
.range([0, this.innerWidth])
.domain(allEpisodes)
.paddingOuter(0)
.paddingInner(0.25);
const histogram = d3.histogram()
.value(d => d.death)
.thresholds(x.domain());
const bins = histogram(data);
const y = d3.scaleLinear()
.domain([0, d3.max(bins, d => d.length)])
.range([this.innerHeight - 10, 0]);
const bar = this.container.selectAll('.bar')
.data(bins)
.enter()
.append('rect')
.attr('x', d => x(d.x0))
.attr('y', d => y(d.length))
.attr('fill', 'steelblue')
.attr('width', () => x.bandwidth())
.attr('height', d => this.innerHeight - 10 - y(d.length));
const xAxis = this.container.append('g')
.attr('class', 'axis x')
.attr('transform', `translate(0, ${this.innerHeight - 10})`)
.call(d3.axisBottom(x).tickFormat(d => `S${(d - (d % 100)) / 100}E${d % 100}`));
xAxis.selectAll('text')
.each(function (d, i) {
const yVal = d3.select(this).attr('y');
d3.select(this).attr('y', i % 2 ? yVal : (yVal * 2) + 2)
});
xAxis.selectAll('line')
.each(function (d, i) {
const y2 = d3.select(this).attr('y2');
d3.select(this).attr('y2', i % 2 ? y2 : y2 * 2)
});
bar.call(tooltip((d) => `${d.x0}: ${d.length} deaths`, this.container));
d3.select('body').append('p').text(JSON.stringify(bins.map(d => ({start: d.x0, end: d.x1}))));
};
const dataEndpoint = 'https://gist.githubusercontent.com/aendrew/980c3e4b3d0a1ec4b32f734631c29d44/raw/9d91d30ba36fc7244b6cc2cf028d96ae6056628a/GoT-deaths-by-season.json';
westerosChart.init('histogram', dataEndpoint)
</script>
</body>
https://d3js.org/d3.v4.min.js