Gooey hexagons for d3.unconf 2016 / Badgetron.
forked from mbostock's block: Hexagon Mesh
forked from ericsoco's block: Hexagon Mesh
forked from ericsoco's block: hexablobs
forked from ericsoco's block: hexablobs 2
forked from ericsoco's block: hexablobs 3
xxxxxxxxxx
<meta charset="utf-8">
<style>
.hexagon {
fill: none;
pointer-events: all;
}
.hexagon path {
-webkit-transition: fill 250ms linear;
transition: fill 250ms linear;
}
.hexagon .fill {
fill: red;
}
.mesh {
fill: none;
stroke: #000;
stroke-opacity: .05;
pointer-events: none;
}
.border {
fill: none;
stroke: #000;
stroke-width: 2px;
stroke-opacity: 0;
pointer-events: none;
}
</style>
<body>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
var width = 1050,
height = 1500,
radius = 80;
var topology = hexTopology(radius, width, height);
var projection = hexProjection(radius);
var path = d3.geoPath()
.projection(projection);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(-310, 240)");
// modified gooey filter a la nadieh bremer:
// https://www.visualcinnamon.com/2015/05/gooey-effect.html
// Originally from https://tympanus.net/codrops/2015/03/10/creative-gooey-effects/
var defs = svg.append('defs');
var filter = defs.append('filter').attr('id','gooey');
filter.append('feGaussianBlur')
.attr('in','SourceGraphic')
.attr('stdDeviation', radius/4)
.attr('result','blur');
filter.append('feColorMatrix')
.attr('in','blur')
.attr('mode','matrix')
.attr('values','1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 16 -8')
.attr('result','gooeyBottom');
filter.append('feGaussianBlur')
.attr('in','SourceGraphic')
.attr('stdDeviation', 2)
.attr('result','gooeyTop');
filter.append('feComposite')
.attr('in','gooeyTop')
.attr('in2','gooeyBottom')
.attr('operator','atop')
.attr('result','gooey');
var hexes = svg.append("g")
.attr("class", "hexagon")
.style("filter", "url(#gooey)")
.selectAll("path")
.data(topology.objects.hexagons.geometries).enter();
hexes.append("path")
.attr("class", function(d) { return "i"+d.i+"j"+d.j; })
.classed("hex", true)
.classed("fill", function(d) { return d.fill; })
.attr("d", function(d) { return path(topojson.feature(topology, d)); });
var col = d3.interpolateRdYlGn;
// var col = d3.interpolatePlasma;
d3.selectAll(".hex")
.attr("fill", function (d) {
let dist = (Math.abs(d.i - 6))/12 + Math.abs(d.j - 5)/10;
// let dist = Math.max(Math.abs(d.i - 5)/10, Math.abs(d.j - 4)/8);
return col(dist*1.6);
})
.attr("transform", function (d) { return scaleHex(d, 0); });
var step = 1500;
setInterval(function () { animate(); }, 2*step);
animate();
function scaleHex (d, s) {
cx = (d.i + ((d.j%2) ? 0 : 0.5)) * radius * 2 * Math.sin(Math.PI / 3);
cy = (d.j - 1) * radius * 1.5;
return "matrix("+s+", 0, 0, "+s+", "+(cx-s*cx)+"," +(cy-s*cy)+")";
}
function animate () {
svg.selectAll(".i6j5")
.attr("transform", function (d) { return scaleHex(d, 1.0); });
svg.selectAll(
".i5j4, .i7j5, .i5j6," +
".i7j3,.i7j4, .i7j7,.i6j7, .i4j5,.i4j4," +
".i4j2,.i5j2,.i6j2, .i9j5,.i8j6,.i8j7, .i4j8,.i4j7,.i3j6," +
".i3j2,.i3j3,.i2j4,.i2j5, .i9j4,.i9j3,.i8j2,.i8j1, .i5j9,.i6j9,.i7j9,.i8j9")
.attr("transform", function (d) { return scaleHex(d, 0.25); })
.style("opacity", 0.5)
.transition()
.delay(step/2)
.ease(d3.easeQuadInOut)
.duration(step)
.attr("transform", function (d) { return scaleHex(d, 1); })
.style("opacity", 1.0)
.transition()
.ease(d3.easeQuadInOut)
.duration(step)
.attr("transform", function (d) { return scaleHex(d, 0.25); })
.style("opacity", 0.5);
svg.selectAll(
".i6j4, .i5j5, .i6j6," +
".i5j3,.i6j3, .i8j5,.i7j6, .i5j7,.i4j6," +
".i7j2,.i8j3,.i8j4, .i5j8,.i6j8,.i7j8, .i3j5,.i3j4,.i4j3," +
".i10j5,.i9j6,.i9j7,.i8j8, .i4j9,.i3j8,.i3j7,.i2j6, .i7j1,.i6j1,.i5j1,.i4j1")
.attr("transform", function (d) { return scaleHex(d, 0.25); })
.style("opacity", 0.5)
.transition()
.delay(step)
.ease(d3.easeQuadInOut)
.duration(2/3*step)
.attr("transform", function (d) { return scaleHex(d, 1); })
.style("opacity", 1.0)
.transition()
.ease(d3.easeQuadInOut)
.duration(4/3*step)
.attr("transform", function (d) { return scaleHex(d, 0.25); })
.style("opacity", 0.5);
}
function hexTopology(radius, width, height) {
var dx = radius * 2 * Math.sin(Math.PI / 3),
dy = radius * 1.5,
m = Math.ceil((height + radius) / dy) + 2,
n = Math.ceil(width / dx) + 3,
geometries = [],
arcs = [];
for (var j = -1; j <= m; ++j) {
for (var i = -1; i <= n; ++i) {
var y = j * 2, x = (i + (j & 1) / 2) * 2;
arcs.push([[x, y - 1], [1, 1]], [[x + 1, y], [0, 1]], [[x + 1, y + 1], [-1, 1]]);
}
}
for (var j = 0, q = 3; j < m; ++j, q += 6) {
for (var i = 0; i < n; ++i, q += 3) {
geometries.push({
type: "Polygon",
arcs: [[q, q + 1, q + 2, ~(q + (n + 2 - (j & 1)) * 3), ~(q - 2), ~(q - (n + 2 + (j & 1)) * 3 + 2)]],
fill: false,//i > n / 2,
j: j,
i: i
});
}
}
return {
transform: {translate: [0, 0], scale: [1, 1]},
objects: {hexagons: {type: "GeometryCollection", geometries: geometries}},
arcs: arcs
};
}
function hexProjection(radius) {
var dx = radius * 2 * Math.sin(Math.PI / 3),
dy = radius * 1.5;
return {
stream: function(stream) {
return {
point: function(x, y) { stream.point(x * dx / 2, (y - (2 - (y & 1)) / 3) * dy / 2); },
lineStart: function() { stream.lineStart(); },
lineEnd: function() { stream.lineEnd(); },
polygonStart: function() { stream.polygonStart(); },
polygonEnd: function() { stream.polygonEnd(); }
};
}
};
}
</script>
https://d3js.org/d3.v4.min.js
https://d3js.org/d3-scale-chromatic.v1.min.js
https://d3js.org/topojson.v1.min.js