index.html
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="ungp-logo">
<div class="inputs">
<label>
<input type="radio" name="mode" value="letters" /> Logotype
</label>
<label>
<input type="radio" name="mode" value="dots" /> Dots
</label>
</div>
<div class="canvas">
</div>
</div>
<script>
var w = 1132,
h = 372;
var x = d3.scale.ordinal()
.domain(d3.range(4))
.rangeRoundBands([0, w], 1);
var path = d3.svg.line()
.x(function(d) { return d[0]; })
.y(function(d) { return d[1]; });
var timeout;
var svg = d3.select("#ungp-logo .canvas").append('svg')
.attr('class', 'logo')
.attr('width', w)
.attr('height', h)
.attr('viewBox', "0 0 " + w + " " + h)
.append("g")
.attr('transform', '' +
'translate(' + w / 2 + ', ' + h / 2 + ') ' +
'scale(1, -1) ' +
'translate(-' + w / 2 + ', -' + h / 2 + ') ' +
'translate(0, 1)'
);
d3.json("logo.json", function(data) {
data.forEach(function(d) {
d.circle_radius = d.circle >= 0 ? 50 : 1;
d.circle_coords = compute_circle(d.letter_coords, d.circle_radius);
});
svg.selectAll('path')
.data(data)
.enter().append('path')
.attr("class", function(d) { return d.color; })
.attr("d", function(d) { return path(d.letter_coords); });
timeout = setTimeout(function() {
d3.select('input[value="dots"]')
.property("checked", true).each(change);
}, 2000);
});
d3.selectAll("#ungp-logo input").on("change", change);
function change() {
clearTimeout(timeout);
if (this.value === "dots") morph_to_dots();
else morph_to_letters();
}
function morph_to_dots() {
var t = svg.transition().duration(500);
t.selectAll('path')
.attr("d", function(d) { return path(d.circle_coords); })
.attr('transform', function(d, i) {
var el = d3.select(this),
bb = el.node().getBBox();
var x_centroid = bb.x + bb.width / 2,
y_centroid = bb.y + bb.height / 2;
var x_new = d.circle >= 0 ? x(d.circle) - x_centroid : 0,
y_new = (h / 2) - y_centroid;
return "translate(" + x_new + ", " + y_new + ")";
});
}
function morph_to_letters() {
var t = svg.transition().duration(500);
t.selectAll('path')
.attr('d', function(d) { return path(d.letter_coords); })
.attr('transform', 'translate(0, 0)');
}
function compute_circle(coordinates, r) {
var circle = [],
length = 0,
lengths = [length],
polygon = d3.geom.polygon(coordinates),
p0 = coordinates[0],
p1,
x,
y,
i = 0,
n = Math.min(250, coordinates.length);
while (++i < n) {
p1 = coordinates[i];
x = p1[0] - p0[0];
y = p1[1] - p0[1];
lengths.push(length += Math.sqrt(x * x + y * y));
p0 = p1;
}
var area = polygon.area(),
radius = r || 50,
centroid = polygon.centroid(-1 / (6 * area)),
angleOffset = -Math.PI / 2,
angle,
i = -1,
k = 2 * Math.PI / lengths[lengths.length - 1];
while (++i < n) {
angle = angleOffset + lengths[i] * k;
circle.push([
centroid[0] + radius * Math.cos(angle),
centroid[1] + radius * Math.sin(angle)
]);
}
return circle;
}
d3.interpolators.push(function(a, b) {
var isPath, isArea, interpolator, ac, bc, an, bn, d;
function fill(value, length) {
return d3.range(length).map(function() {
return value;
});
}
function extractCoordinates(path) {
return path.substr(1, path.length - (isArea ? 2 : 1)).split('L');
}
function makePath(coordinates) {
return 'M' + coordinates.join('L') + (isArea ? 'Z' : '');
}
function bufferPath(p1, p2) {
var d = p2.length - p1.length;
if (isArea) {
return fill(p1[0], d / 2).concat(p1, fill(p1[p1.length - 1], d / 2));
} else {
return fill(p1[0], d).concat(p1);
}
}
isPath = /M-?\d*\.?\d*,-?\d*\.?\d*(L-?\d*\.?\d*,-?\d*\.?\d*)*Z?/;
if (isPath.test(a) && isPath.test(b)) {
isArea = a[a.length - 1] === 'Z';
ac = extractCoordinates(a);
bc = extractCoordinates(b);
an = ac.length;
bn = bc.length;
if (an > bn) bc = bufferPath(bc, ac);
if (bn > an) ac = bufferPath(ac, bc);
interpolator = d3.interpolateString(
bn > an ? makePath(ac) : a,
an > bn ? makePath(bc) : b
);
return bn > an ? interpolator : function(t) {
return t === 1 ? b : interpolator(t);
};
}
});
</script>
</body>