D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
aendra-rininsland
Full window
Github gist
Ordinal histogram
Built with
blockbuilder.org
<!DOCTYPE html> <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