Built with blockbuilder.org
forked from sxywu's block: d3.unconf 2016, v6
forked from sxywu's block: d3.unconf 2016, v7
forked from sxywu's block: d3.unconf 2016, v8
forked from sxywu's block: d3.unconf 2016, v9
forked from sxywu's block: d3.unconf 2016, v10
xxxxxxxxxx
<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>
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');
}
</script>
</body>
Modified http://gka.github.io/chroma.js/vendor/chroma-js/chroma.min.js to a secure url
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js
https://npmcdn.com/babel-core@5.8.34/browser.min.js
https://gka.github.io/chroma.js/vendor/chroma-js/chroma.min.js