Recreating a long exposure photograph of the night sky in d3. Randomly generate circles and arcs. Arcs are animated using attrTween.
forked from tlfrd's block: Starry Sky (Long Exposure)
forked from anonymous's block: Starry Sky (Long Exposure)
license: mit | |
height: 960 |
Recreating a long exposure photograph of the night sky in d3. Randomly generate circles and arcs. Arcs are animated using attrTween.
forked from tlfrd's block: Starry Sky (Long Exposure)
forked from anonymous's block: Starry Sky (Long Exposure)
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }; | |
</style> | |
</head> | |
<body> | |
<script> | |
var width = 960, | |
height = 960; | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var definitions = svg.append("defs"); | |
var filter = definitions.append("filter") | |
.attr("id", "glow"); | |
filter.append("feGaussianBlur") | |
.attr("class", "blur") | |
.attr("stdDeviation", 2) | |
.attr("result","coloredBlur"); | |
var feMerge = filter.append("feMerge") | |
feMerge.append("feMergeNode") | |
.attr("in","coloredBlur"); | |
feMerge.append("feMergeNode") | |
.attr("in","SourceGraphic"); | |
var gradient = definitions.append("linearGradient") | |
.attr("id", "gradient") | |
.attr("x1", "0%") | |
.attr("y1", "0%") | |
.attr("x2", "0%") | |
.attr("y2", "100%") | |
.attr("spreadMethod", "pad"); | |
gradient.append("stop") | |
.attr("offset", "0%") | |
.attr("stop-color", "#black") | |
.attr("stop-opacity", 1); | |
gradient.append("stop") | |
.attr("offset", "100%") | |
.attr("stop-color", "#131862") | |
.attr("stop-opacity", 1); | |
var bg = svg.append("rect") | |
.attr("width", width) | |
.attr("height", height) | |
.style("fill", "url(#gradient)") | |
var tau = 2 * Math.PI; | |
var config = { | |
starRadius: 2, | |
rotationPoint: [width / 2, height / 2], | |
angle: 45, | |
arcLength: 0 | |
}; | |
var g = svg.append("g") | |
.attr("transform", "translate(" + config.rotationPoint + ")"); | |
function calculateDistance(point) { | |
return Math.sqrt(Math.pow(point[0], 2) + Math.pow(point[1], 2)); | |
} | |
function calculateAngle(point) { | |
var angle = Math.atan2(point[1], point[0]) + Math.PI / 2; | |
return angle; | |
} | |
var stars; | |
generateStars(500, false); | |
svg.append("circle") | |
.attr("cx", config.rotationPoint[0]) | |
.attr("cy", config.rotationPoint[1]) | |
.attr("r", 2.5) | |
.style("fill", "white") | |
.style("filter", "url(#glow)"); | |
function generateStars(number, glow) { | |
var starData = d3.range(number).map(d => | |
i = {x: Math.random() * (width) - (width / 2), | |
y: Math.random() * (height) - (height / 2), | |
r: Math.random() * config.starRadius, | |
opacity: Math.random() | |
} | |
); | |
stars = g.selectAll("circle") | |
.data(starData) | |
.enter().append("circle") | |
.attr("class", "star") | |
.attr("cx", d => d.x) | |
.attr("cy", d => d.y) | |
.attr("r", d => d.r) | |
.style("opacity", d => d.opacity) | |
.style("fill", "white") | |
.style("filter", glow ? "url(#glow)" : ""); | |
stars.transition() | |
.duration(10000) | |
.style("opacity", 0); | |
starData.forEach(d => { | |
var arc = d3.arc() | |
.innerRadius(calculateDistance([d.x, d.y])) | |
.outerRadius(calculateDistance([d.x, d.y])) | |
.startAngle(calculateAngle([d.x, d.y]) + config.arcLength); | |
var arcLine = g.append("path") | |
.datum({endAngle: calculateAngle([d.x, d.y])}) | |
.style("stroke", "white") | |
.style("stroke-width", d.r) | |
.style("opacity", d.opacity) | |
.style("stroke-linecap", "round") | |
.attr("d", arc) | |
.style("filter", glow ? "url(#glow)" : ""); | |
arcLine.transition() | |
.duration(20000) | |
.attrTween("d", arcTween(calculateAngle([d.x, d.y]) + 1)); | |
function arcTween(newAngle) { | |
return function(a) { | |
var interpolate = d3.interpolate(a.endAngle, newAngle); | |
return function(t) { | |
a.endAngle = interpolate(t); | |
return arc(a); | |
}; | |
}; | |
} | |
}); | |
} | |
</script> | |
</body> |