Skip to content

Instantly share code, notes, and snippets.

@micahstubbs
Last active October 16, 2016 07:34
Show Gist options
  • Save micahstubbs/32f369bb437d7c23198b9b9ccc8d4751 to your computer and use it in GitHub Desktop.
Save micahstubbs/32f369bb437d7c23198b9b9ccc8d4751 to your computer and use it in GitHub Desktop.
d3.unconf 2016, v11
license: MIT
border: no
height: 1900
First Name Last Name version first favorite possesivePronoun
Alan McLean v1 Scatter plot d3.timer his
alanna scott v3 Bar chart, Line chart her
Alastair Dant v1 Treemap d3.forceSimulation his
Alex Macy v3 Line chart d3.transition his
Amit Patel v1 N/A d3.behavior.zoom his
Andrew Wong v3 Radial plot d3.scale his
Angela Pablo v2 Scatter plot her
Anna Smylie v3 Bar chart her
Anna Vital v2 Tree d3.line her
Anuja Verma v3 Tree d3.hierarchy her
Bo Ericsson v3 Line chart selection.data his
Brad Lyon v2 Chord diagram d3.selectAll his
Brent Cohn v3 Bar plot d3.forceSimulation his
Brian Bailey v4 Bar chart d3.voronoi his
Casey Haber v3 Bar chart d3.force his
Chris Polis v3 Time series d3.transition his
christophe viau v1 Tooltip d3.axis his
Daniel Overstreet v3 Scatter plot d3.nest his
Daniel Wolfe v3 Map d3.transition his
David Richards v3 Force d3.interpolate his
David Schnurr v3 Charting library d3.voronoi his
David Lin v3 Bar chart selection.data his
Don McCurdy v3 Choropleth d3.voronoi his
Eric Socolofsky v3 Map d3.transition his
Erik Cunningham v3 Scatter plot selection.data his
Erik Hazzard v1 Radar chart d3.voronoi his
Francois Chabbey v3 Bar chart d3.scale his
Marcos Iglesias v3 Bar chart d3.selectAll his
Hourann Bosci v3 Map, Bubble chart d3.scaleOrdinal his
Ian Johnson v1 Bar chart d3.scaleLinear his
Ivy Wang v1 Network graph nest.rollup her
James Womack v3 Scatter plot d3.scale his
James Wenzel v3 Line chart nest.map his
Jamie Popkin v2 Map transform his
Janine Heiser v3 Bar chart d3.selection her
Jay Mahabal v3 Bar chart d3.scale his
Jeff Zerger v2 Map d3.geoProjection his
Jeffrey Catania v2 Line chart d3.voronoi his
Jennifer Lee v3 Bar chart d3.transition her
Jeremy Wong v3 Line Chart d3.geoProjection his
Jeremy Wildfire v2 Bar chart d3.scale his
Jim Vallandingham v2 Bubble chart d3.nest his
Jing Lu v4 Scatter plot d3.brush her
John Schulz v2 Area chart d3.histogram his
John Huynh v3 Scatter plot d3.transition his
Jon Sadka v4 Bar chart d3.transition his
Jon Nguyen v2 Bar chart d3.extent his
Jonathan Nesci v2 Bar chart scale.invert his
Kai Chang v1 Chord diagram d3.interpolateMagma his
Ken Penn v3 Bar chart d3.forceSimulation his
Kerry Rodden v1 Chord diagram d3.scale her
Krist Wongsuphasawat v3 Scatter plot d3.selection, d3.scale his
Kristen Judd v3 Pie chart d3.transition her
Kristin Henry v2 Chloropleth d3.scale her
Leland Lee v3 Bar chart arcTween his
Logan Carter v4 Pie chart, Donut chart d3.pie his
Ludwig Schubert v3 Tree projection.fitSize his
Marie Swarzenski v3 Line chart d3.transition her
Mark Vital v2 Tree d3.line his
Matthew Isanuk v4 Scatter plot d3.scale his
Mauro Perez v3 Sunburst selection.data his
Micah Stubbs v3 Map d3.request his
Michael Freeman v2 Bar chart d3.pack his
Mike Bostock v1 N/A d3.pack his
Minwei Xu v4 bar chart d3.layout.force his
Naoya Kanai v3 bar chart d3.scale his
Noah Veltman v2 Line chart d3.transition his
Patrick Sun v3 Scatter Plot selection.attr his
Paul Rosenzweig v4 Scatter plot d3.selectAll his
Paul Van slembrouck v1 Bar chart d3.scale his
Philippe Rivière v3 Map d3.geoProjection his
Phillip Mispagel v4 Donut chart d3.scale, d3.zoom his
Ramesh Sampath v4 Scatter plot d3.scale his
Ric Cheng v3 Line chart d3.brush his
Robert Crocker v3 Bar chart d3.nest his
Robert Harris v2 Force d3.scale his
Roger Fischer v3 Map d3.geo his
Rumman Chowdhury v3 Line chart d3.voronoi her
Saniya Jesupaul v3 Scatter plot d3.color her
Sara Quigley v2 Circle pack d3.nest her
Sara Schnadt v3 Scatter plot her
Sarah Kwak v4 Donut chart d3.transition her
Seemant Kulleen v3 Donut chart d3.nest his
Shan Carter v2 Bubble chart d3.scaleLinear his
Shelby Sturgis v3 Scatter plot d3.scale his
Shirley Wu v2 Tree d3.forceSimulation her
Siu-Mei Man v4 Bar chart d3.voronoi her
Susie Lu v2 Bar chart d3.nest her
Tarek Rached v2 Bar chart d3.layout.pack his
Tim Hyon Hyon v3 Parallel coordinates d3.scale his
Tony Chu v3 Bubble chart d3.scale his
Toshiyuki Hayashi v3 Network graph selection.enter, selection.exit his
Vasco Asturiano v2 Force selection.data his
Victor Powell v4 Scatter plot d3.geo.path his
Visnu Pitiyanuvath v2 Bar chart d3.nest his
Xianlin Hu v3 Force d3.transition her
Yukiko Steineman v3 Bar chart d3.color her
Zack DeSario v2 Bar chart selection.enter his
var midpoint = -2/3;
var halfSide = Math.sqrt(1 / 3);
var triangle = [
(-halfSide) + ',-1',
(halfSide) + ',-1',
'0,0'
];
var favoritesScale = d3.scaleLinear()
.range([midpoint - .05, -.85]);
var versionsScale = d3.scaleOrdinal()
.range(_.rangeRight(3, 7));
var firstsScale = d3.scaleOrdinal();
var hexScale = 40;
var hexSize = hexScale * 2 / Math.sqrt(3);
d3.csv('data.csv', data => {
/**************************************
** process data and add them to scales as domain
**************************************/
var attendees = _.map(data, d => {
return {
name: d['First Name'],
first: d.first.split(', ')[0],
favorite: d.favorite.split(', ')[0],
version: parseInt(d.version.replace('v', '')),
};
});
var firsts = _.chain(attendees)
.map('first').flatten()
.countBy().toPairs()
.sortBy(d => -d[1])
.map(0).value();
var favorites = _.chain(attendees)
.map('favorite').flatten()
.countBy().value();
var versions = _.chain(attendees)
.map('version').flatten()
.countBy().toPairs()
.sortBy(d => -d[1])
.filter(d => d[1] > 1)
.map(0).value();
// update colors with number of classes
var colors = chroma.cubehelix()
.start(280)
// .rotations(-1 / firsts.length)
.gamma(0.5)
.lightness([0.3, 0.4])
.scale() // convert to chroma.scale
// .correctLightness()
.colors(firsts.length);
firstsScale.domain(firsts).range(colors);
versionsScale.domain(_.range(1, 5));
var maxFavorites = _.max(_.values(favorites));
favoritesScale.domain([1, maxFavorites]);
/**************************************
** legend
**************************************/
var baseLegendData = {
version: 1,
first: 'Bar chart',
favorite: 'd3.scale',
};
var legend = d3.select('#legend');
var annotation = d3.select('#annotation');
// first, the versions
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', hexScale)
// .html('Which version of d3 did you start with?');
var versionsData = _.times(4, i => {
return Object.assign(_.clone(baseLegendData), {
version: i + 1,
legendText: 'd3 v' + (i + 1),
});
});
legend.append('g')
.attr('transform', 'translate(' + [0, 0] + ')')
.call(drawHexagons, versionsData, 4);
// first
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', 5.5 * hexScale)
// .html('Your first d3 project:<br />what type of visualization was it?');
var firstData1 = _.times(4, i => {
var index = !i ? i : i * 4 - 1;
return Object.assign(_.clone(baseLegendData), {
first: firsts[index],
legendText: firsts[index],
});
});
var firstData2 = _.times(3, i => {
var index = (!i ? i : i * 4 - 1) + 14;
return Object.assign(_.clone(baseLegendData), {
first: firsts[index],
legendText: firsts[index],
});
});
legend.append('g')
.attr('transform', 'translate(' + [0, 4 * hexScale] + ')')
.call(drawHexagons, firstData1, 4);
legend.append('g')
.attr('transform', 'translate(' + [1.9 * hexScale, 6.75 * hexScale] + ')')
.call(drawHexagons, firstData2, 3);
// favorites
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', 13.5 * hexScale)
// .html('What is your favorite d3 api function?');
var favoriteNames = ['d3.scale', 'd3.transition', 'd3.forceSimulation', 'd3.hierarchy'];
var favoriteData = _.times(4, i => {
return Object.assign(_.clone(baseLegendData), {
favorite: favoriteNames[i],
legendText: favoriteNames[i],
});
});
legend.append('g')
.attr('transform', 'translate(' + [0, 10.75 * hexScale] + ')')
.call(drawHexagons, favoriteData, 4);
/**************************************
** draw the hexagons
**************************************/
var perRow = 5;
var svg = d3.select('#flowers').append('g')
.call(drawHexagons, attendees, perRow);
function drawHexagons(selection, data, perRow) {
var hex = selection.selectAll('.hex')
.data(data).enter().append('g')
.classed('hex', true)
.attr('transform', (d, i) => {
var row = Math.floor(i / perRow);
var x = (i % perRow * 3.2 + 1.5) * hexSize;
if (row % 2) {
x += 1.6 * hexSize;
}
var y = (row * 1.05 + 2) * hexScale;
d.x = x;
d.y = y;
return 'translate(' + [x, y] + ')scale(' + hexScale + ')';
}).on('mouseenter', mouseenter)
.on('mouseleave', mouseleave);
var triangles = hex.selectAll('triangle')
.data((d, j) => {
return _.times(versionsScale(d.version), i => {
return {
angle: i * 60,
midpoint: favoritesScale(favorites[d.favorite]),
color: firstsScale(d.first),
// color: colors[j],
};
});
}).enter().append('g')
.classed('triangle', true)
.attr('transform', d => 'rotate(' + d.angle + ')');
triangles.append('polygon')
.attr('points', triangle.join(' '))
.attr('fill', d => chroma(d.color).darken(2.5));
// .attr('fill', '#fff');
triangles.selectAll('.subtri')
.data(d => _.times(3, i => {
return Object.assign({
subangle: i * 120,
subcolor: chroma(d.color).saturate(1.5).brighten(i),
}, d);
})).enter().append('polygon')
.classed('subtri', true)
.attr('transform', d => 'rotate(' + d.subangle + ' 0 ' + midpoint + ')')
.attr('points', d => {
return [
(-halfSide) + ',-1',
'0,' + d.midpoint,
halfSide + ',-1'
].join(' ');
}).attr('fill', d => d.subcolor);
// add in text if it's for legend
var fontSize = 14;
hex.filter(d => d.legendText)
.append('text')
.attr('y', 1.25)
.attr('font-size', fontSize / hexScale)
.attr('text-anchor', 'middle')
.attr('dy', '.35em')
.text(d => d.legendText);
}
});
/**************************************
** hover interaction
**************************************/
var hover = d3.select('#hover')
.style('display', 'none');
function mouseenter(d) {
if (!d.name) return;
var html = '<h2>' + d.name + '</h2>';
html += '<p>started with d3.js v' + d.version;
if (d.first) {
html += ' and made a ' + d.first;
}
if (d.favorite) {
html += '. Their favorite d3 function is ' + d.favorite;
}
html += '.';
var x = d.x + hexSize / 2;
var y = d.y + hexSize / 2;
hover.style('display', 'block')
.style('top', y + 'px')
.style('left', x + 'px')
.html(html);
}
function mouseleave() {
hover.style('display', 'none');
}
const midpoint = -2/3;
const halfSide = Math.sqrt(1 / 3);
const triangle = [
`${-halfSide},-1`,
`${halfSide},-1`,
'0,0'
];
const favoritesScale = d3.scaleLinear()
.range([midpoint - .05, -.85]);
const versionsScale = d3.scaleOrdinal()
.range(_.rangeRight(3, 7));
const firstsScale = d3.scaleOrdinal();
const hexScale = 40;
const hexSize = hexScale * 2 / Math.sqrt(3);
d3.csv('data.csv', data => {
/**************************************
** process data and add them to scales as domain
**************************************/
const attendees = _.map(data, d => {
return {
name: d['First Name'],
first: d.first.split(', ')[0],
favorite: d.favorite.split(', ')[0],
version: parseInt(d.version.replace('v', '')),
};
});
const firsts = _.chain(attendees)
.map('first').flatten()
.countBy().toPairs()
.sortBy(d => -d[1])
.map(0).value();
const favorites = _.chain(attendees)
.map('favorite').flatten()
.countBy().value();
const versions = _.chain(attendees)
.map('version').flatten()
.countBy().toPairs()
.sortBy(d => -d[1])
.filter(d => d[1] > 1)
.map(0).value();
// update colors with number of classes
const colors = chroma.cubehelix()
.start(280)
// .rotations(-1 / firsts.length)
.gamma(0.5)
.lightness([0.3, 0.4])
.scale() // convert to chroma.scale
// .correctLightness()
.colors(firsts.length);
firstsScale.domain(firsts).range(colors);
versionsScale.domain(_.range(1, 5));
const maxFavorites = _.max(_.values(favorites));
favoritesScale.domain([1, maxFavorites]);
/**************************************
** legend
**************************************/
const baseLegendData = {
version: 1,
first: 'Bar chart',
favorite: 'd3.scale',
};
const legend = d3.select('#legend');
const annotation = d3.select('#annotation');
// first, the versions
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', hexScale)
// .html('Which version of d3 did you start with?');
const versionsData = _.times(4, i => {
return Object.assign(_.clone(baseLegendData), {
version: i + 1,
legendText: `d3 v${i + 1}`,
});
});
legend.append('g')
.attr('transform', `translate(${[0, 0]})`)
.call(drawHexagons, versionsData, 4);
// first
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', 5.5 * hexScale)
// .html('Your first d3 project:<br />what type of visualization was it?');
const firstData1 = _.times(4, i => {
const index = !i ? i : i * 4 - 1;
return Object.assign(_.clone(baseLegendData), {
first: firsts[index],
legendText: firsts[index],
});
});
const firstData2 = _.times(3, i => {
const index = (!i ? i : i * 4 - 1) + 14;
return Object.assign(_.clone(baseLegendData), {
first: firsts[index],
legendText: firsts[index],
});
});
legend.append('g')
.attr('transform', `translate(${[0, 4 * hexScale]})`)
.call(drawHexagons, firstData1, 4);
legend.append('g')
.attr('transform', `translate(${[1.9 * hexScale, 6.75 * hexScale]})`)
.call(drawHexagons, firstData2, 3);
// favorites
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', 13.5 * hexScale)
// .html('What is your favorite d3 api function?');
const favoriteNames = ['d3.scale', 'd3.transition', 'd3.forceSimulation', 'd3.hierarchy'];
const favoriteData = _.times(4, i => {
return Object.assign(_.clone(baseLegendData), {
favorite: favoriteNames[i],
legendText: favoriteNames[i],
});
});
legend.append('g')
.attr('transform', `translate(${[0, 10.75 * hexScale]})`)
.call(drawHexagons, favoriteData, 4);
/**************************************
** draw the hexagons
**************************************/
const perRow = 5;
const svg = d3.select('#flowers').append('g')
.call(drawHexagons, attendees, perRow);
function drawHexagons(selection, data, perRow) {
const hex = selection.selectAll('.hex')
.data(data).enter().append('g')
.classed('hex', true)
.attr('transform', (d, i) => {
const row = Math.floor(i / perRow);
let x = (i % perRow * 3.2 + 1.5) * hexSize;
if (row % 2) {
x += 1.6 * hexSize;
}
const y = (row * 1.05 + 2) * hexScale;
d.x = x;
d.y = y;
return `translate(${[x, y]})scale(${hexScale})`;
}).on('mouseenter', mouseenter)
.on('mouseleave', mouseleave);
const triangles = hex.selectAll('triangle')
.data((d, j) => {
return _.times(versionsScale(d.version), i => {
return {
angle: i * 60,
midpoint: favoritesScale(favorites[d.favorite]),
color: firstsScale(d.first),
// color: colors[j],
};
});
}).enter().append('g')
.classed('triangle', true)
.attr('transform', d => `rotate(${d.angle})`);
triangles.append('polygon')
.attr('points', triangle.join(' '))
.attr('fill', d => chroma(d.color).darken(2.5));
// .attr('fill', '#fff');
triangles.selectAll('.subtri')
.data(d => _.times(3, i => {
return Object.assign({
subangle: i * 120,
subcolor: chroma(d.color).saturate(1.5).brighten(i),
}, d);
})).enter().append('polygon')
.classed('subtri', true)
.attr('transform', d => `rotate(${d.subangle} 0 ${midpoint})`)
.attr('points', d => {
return [
`${-halfSide},-1`,
`0,${d.midpoint}`,
`${halfSide},-1`
].join(' ');
}).attr('fill', d => d.subcolor);
// add in text if it's for legend
const fontSize = 14;
hex.filter(d => d.legendText)
.append('text')
.attr('y', 1.25)
.attr('font-size', fontSize / hexScale)
.attr('text-anchor', 'middle')
.attr('dy', '.35em')
.text(d => d.legendText);
}
});
/**************************************
** hover interaction
**************************************/
const hover = d3.select('#hover')
.style('display', 'none');
function mouseenter(d) {
if (!d.name) return;
let html = `<h2>${d.name}</h2>`;
html += `<p>started with d3.js v${d.version}`;
if (d.first) {
html += ` and made a ${d.first}`;
}
if (d.favorite) {
html += `. Their favorite d3 function is ${d.favorite}`;
}
html += '.';
const x = d.x + hexSize / 2;
const y = d.y + hexSize / 2;
hover.style('display', 'block')
.style('top', `${y}px`)
.style('left', `${x}px`)
.html(html);
}
function mouseleave() {
hover.style('display', 'none');
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
<script src="https://npmcdn.com/babel-core@5.8.34/browser.min.js"></script>
<script type="text/javascript" src="https://gka.github.io/chroma.js/vendor/chroma-js/chroma.min.js"></script>
<style>
body {
/* background-color: #000; */
font-family: courier;
text-align: center;
}
h1 {
font-size: 36px;
width: 1000px;
padding-top: 40px;
}
#header {
width: 1000px;
/* padding: 40px 0; */
position: relative;
margin: auto;
}
#legend {
width: 580px;
height: 600px;
margin: auto;
}
#annotation {
width: 1000px;
position: absolute;
top: 0;
font-size: 20px;
}
#content {
position: relative;
width: 1000px;
padding-bottom: 100px;
margin: auto;
}
#flowers {
width: 800px;
height: 1000px;
margin: auto;
}
#hover {
position: absolute;
width: 250px;
border: 1px solid #666;
border-radius: 5px;
box-shadow: 0 0 5px #666;
text-align: center;
background-color: #fff;
padding: 10px;
}
</style>
</head>
<body>
<div id='header'>
<h1>d3.unconf 2016</h1>
<p>(Hover for attendee info ✨)</p>
<svg id='legend'></svg>
<div id='annotation'></svg>
</div>
<div id='content'>
<svg id='flowers'></svg>
<div id='hover'></div>
</div>
<script lang="babel" type="text/babel">
const midpoint = -2/3;
const halfSide = Math.sqrt(1 / 3);
const triangle = [
`${-halfSide},-1`,
`${halfSide},-1`,
'0,0'
];
const favoritesScale = d3.scaleLinear()
.range([midpoint - .05, -.85]);
const versionsScale = d3.scaleOrdinal()
.range(_.rangeRight(3, 7));
const firstsScale = d3.scaleOrdinal();
const hexScale = 40;
const hexSize = hexScale * 2 / Math.sqrt(3);
d3.csv('data.csv', data => {
/**************************************
** process data and add them to scales as domain
**************************************/
const attendees = _.map(data, d => {
return {
name: d['First Name'],
first: d.first.split(', ')[0],
favorite: d.favorite.split(', ')[0],
version: parseInt(d.version.replace('v', '')),
possesivePronoun: d.possesivePronoun
};
});
const firsts = _.chain(attendees)
.map('first').flatten()
.countBy().toPairs()
.sortBy(d => -d[1])
.map(0).value();
const favorites = _.chain(attendees)
.map('favorite').flatten()
.countBy().value();
const versions = _.chain(attendees)
.map('version').flatten()
.countBy().toPairs()
.sortBy(d => -d[1])
.filter(d => d[1] > 1)
.map(0).value();
// update colors with number of classes
const colors = chroma.cubehelix()
.start(280)
// .rotations(-1 / firsts.length)
.gamma(0.5)
.lightness([0.3, 0.4])
.scale() // convert to chroma.scale
// .correctLightness()
.colors(firsts.length);
firstsScale.domain(firsts).range(colors);
versionsScale.domain(_.range(1, 5));
const maxFavorites = _.max(_.values(favorites));
favoritesScale.domain([1, maxFavorites]);
/**************************************
** legend
**************************************/
const baseLegendData = {
version: 1,
first: 'Bar chart',
favorite: 'd3.scale',
};
const legend = d3.select('#legend');
const annotation = d3.select('#annotation');
// first, the versions
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', hexScale)
// .html('Which version of d3 did you start with?');
const versionsData = _.times(4, i => {
return Object.assign(_.clone(baseLegendData), {
version: i + 1,
legendText: `d3 v${i + 1}`,
});
});
legend.append('g')
.attr('transform', `translate(${[0, 0]})`)
.call(drawHexagons, versionsData, 4);
// first
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', 5.5 * hexScale)
// .html('Your first d3 project:<br />what type of visualization was it?');
const firstData1 = _.times(4, i => {
const index = !i ? i : i * 4 - 1;
return Object.assign(_.clone(baseLegendData), {
first: firsts[index],
legendText: firsts[index],
});
});
const firstData2 = _.times(3, i => {
const index = (!i ? i : i * 4 - 1) + 14;
return Object.assign(_.clone(baseLegendData), {
first: firsts[index],
legendText: firsts[index],
});
});
legend.append('g')
.attr('transform', `translate(${[0, 4 * hexScale]})`)
.call(drawHexagons, firstData1, 4);
legend.append('g')
.attr('transform', `translate(${[1.9 * hexScale, 6.75 * hexScale]})`)
.call(drawHexagons, firstData2, 3);
// favorites
// annotation.append('div')
// .style('position', 'absolute')
// .style('width', '1000px')
// .style('top', 13.5 * hexScale)
// .html('What is your favorite d3 api function?');
const favoriteNames = ['d3.scale', 'd3.transition', 'd3.forceSimulation', 'd3.hierarchy'];
const favoriteData = _.times(4, i => {
return Object.assign(_.clone(baseLegendData), {
favorite: favoriteNames[i],
legendText: favoriteNames[i],
});
});
legend.append('g')
.attr('transform', `translate(${[0, 10.75 * hexScale]})`)
.call(drawHexagons, favoriteData, 4);
/**************************************
** draw the hexagons
**************************************/
const perRow = 5;
const svg = d3.select('#flowers').append('g')
.call(drawHexagons, attendees, perRow);
function drawHexagons(selection, data, perRow) {
const hex = selection.selectAll('.hex')
.data(data).enter().append('g')
.classed('hex', true)
.attr('transform', (d, i) => {
const row = Math.floor(i / perRow);
let x = (i % perRow * 3.2 + 1.5) * hexSize;
if (row % 2) {
x += 1.6 * hexSize;
}
const y = (row * 1.05 + 2) * hexScale;
d.x = x;
d.y = y;
return `translate(${[x, y]})scale(${hexScale})`;
}).on('mouseenter', mouseenter)
.on('mouseleave', mouseleave);
const triangles = hex.selectAll('triangle')
.data((d, j) => {
return _.times(versionsScale(d.version), i => {
return {
angle: i * 60,
midpoint: favoritesScale(favorites[d.favorite]),
color: firstsScale(d.first),
// color: colors[j],
};
});
}).enter().append('g')
.classed('triangle', true)
.attr('transform', d => `rotate(${d.angle})`);
triangles.append('polygon')
.attr('points', triangle.join(' '))
.attr('fill', d => chroma(d.color).darken(2.5));
// .attr('fill', '#fff');
triangles.selectAll('.subtri')
.data(d => _.times(3, i => {
return Object.assign({
subangle: i * 120,
subcolor: chroma(d.color).saturate(1.5).brighten(i),
}, d);
})).enter().append('polygon')
.classed('subtri', true)
.attr('transform', d => `rotate(${d.subangle} 0 ${midpoint})`)
.attr('points', d => {
return [
`${-halfSide},-1`,
`0,${d.midpoint}`,
`${halfSide},-1`
].join(' ');
}).attr('fill', d => d.subcolor);
// add in text if it's for legend
const fontSize = 14;
hex.filter(d => d.legendText)
.append('text')
.attr('y', 1.25)
.attr('font-size', fontSize / hexScale)
.attr('text-anchor', 'middle')
.attr('dy', '.35em')
.text(d => d.legendText);
}
});
/**************************************
** hover interaction
**************************************/
const hover = d3.select('#hover')
.style('display', 'none');
function mouseenter(d) {
if (!d.name) return;
let html = `<h2>${d.name}</h2>`;
html += `<p>started with d3.js v${d.version}`;
if (
d.first &&
d.first !== 'N/A' &&
d.first !== ''
) {
html += ` and made a ${d.first}`;
}
if (d.favorite) {
html += `. ${_.upperFirst(d.possesivePronoun)} favorite d3 function is ${d.favorite}`;
}
html += '.';
const x = d.x + hexSize / 2;
const y = d.y + hexSize / 2;
hover.style('display', 'block')
.style('top', `${y}px`)
.style('left', `${x}px`)
.html(html);
}
function mouseleave() {
hover.style('display', 'none');
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment