A simple D3-powered animation, inspired by an image found on Otaku Gangsta.
View on bl.ocks.org at http://bl.ocks.org/rogerhutchings/967945b1b5db5cbe623c
A simple D3-powered animation, inspired by an image found on Otaku Gangsta.
View on bl.ocks.org at http://bl.ocks.org/rogerhutchings/967945b1b5db5cbe623c
<!DOCTYPE html> | |
<head> | |
<meta charset='utf-8'> | |
<style> | |
body { | |
background: #1a1a1d; | |
} | |
</style> | |
</head> | |
<body> | |
<script src='http://d3js.org/d3.v3.min.js'></script> | |
<script> | |
(function () { | |
'use strict'; | |
var margin = { | |
top: 10, | |
right: 10, | |
bottom: 10, | |
left: 10 | |
}; | |
var bar = { | |
color: '#fff', | |
height: 20, | |
margin: { | |
x: 20, | |
y: 5 | |
}, | |
minimumWidth: 40 | |
}; | |
var height = 500 - margin.top - margin.bottom; | |
var width = 500 - margin.left - margin.right; | |
var availableWidth = width - bar.margin.x; | |
var animation = { | |
// Speed in px / ms | |
speed: 0.1, | |
// Animation interval in ms | |
interval: 1000 | |
}; | |
// How many whole lines? | |
var numberOfLines = Math.floor(height / (bar.height + bar.margin.y)); | |
// So work out how tall the actual content will be, divide by two, | |
// and save it to adjust the content transform so it's vertically | |
// aligned | |
margin.topG = margin.top + (height - (numberOfLines * (bar.height + bar.margin.y) - bar.margin.y)) / 2; | |
var svg = d3.select('body').append('svg') | |
.attr('width', width + margin.left + margin.right) | |
.attr('height', height + margin.top + margin.bottom) | |
.append('g') | |
.attr('transform', 'translate(' + margin.left + ',' + margin.topG + ')'); | |
// Generate random dataset | |
// We create a random value for each line. This is used to generate the | |
// left bar width, and then subtracted from the availableWidth to give the | |
// right bar width. | |
var randomBetween = function (min, max) { | |
return Math.floor(Math.random() * (max - min + 1) + min); | |
}; | |
// We want our bars to BOTH be at least the minimum width, so we use that in | |
// setting both the upper and the lower bounds | |
var data = []; | |
for (var i = 0; i < numberOfLines; i++) { | |
data[i] = randomBetween(bar.minimumWidth, availableWidth - bar.minimumWidth); | |
} | |
// Create bar groups | |
var barGroups = svg.selectAll('.bar-group') | |
.data(data) | |
.enter() | |
.append('g') | |
.attr('class', 'bar-group') | |
.attr('transform', function(d, i) { return 'translate(0, ' + (i * (bar.height + bar.margin.y)) + ')'; }); | |
// Create the left bars | |
barGroups.append('rect') | |
.attr('class', 'left-bar') | |
.attr('x', 0) | |
.attr('y', 0) | |
.attr('height', bar.height) | |
.attr('width', function (d) { return d; }) | |
.attr('fill', bar.color); | |
// Create the right bars | |
barGroups.append('rect') | |
.attr('class', 'right-bar') | |
.attr('x', function (d) { return d + bar.margin.x; }) | |
.attr('y', 0) | |
.attr('height', bar.height) | |
.attr('width', function (d) { return availableWidth - d; }) | |
.attr('fill', bar.color); | |
var getAnimationTime = function (distance) { | |
// Speed = distance / time, so to get a constant speed for our | |
// animations, we need time = distance / speed. | |
return distance / animation.speed; | |
}; | |
var moveBar = function () { | |
// Randomly select a bar group, and get its left and right bars | |
var target = barGroups[0][randomBetween(0, (numberOfLines - 1))]; | |
var leftBar = d3.select(target.childNodes[0]); | |
var rightBar = d3.select(target.childNodes[1]); | |
// Generate a new width, and work out the distance from the | |
// starting point | |
var newValue = randomBetween(bar.minimumWidth, availableWidth - bar.minimumWidth); | |
var distance = Math.abs(leftBar.node().getBBox().width - newValue); | |
// Start the animations | |
leftBar.transition() | |
.duration(getAnimationTime(distance)) | |
.ease('linear') | |
.attr('width', newValue); | |
rightBar.transition() | |
.duration(getAnimationTime(distance)) | |
.ease('linear') | |
.attr('width', availableWidth - newValue) | |
.attr('x', newValue + bar.margin.x); | |
}; | |
// Periodically trigger an animation | |
setInterval(moveBar, animation.interval); | |
}()); | |
</script> | |
</body> | |
</html> |