Skip to content

Instantly share code, notes, and snippets.

@tlfrd
Last active August 31, 2017 16:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tlfrd/601b1251d939fa4e00bd2c2962986402 to your computer and use it in GitHub Desktop.
Save tlfrd/601b1251d939fa4e00bd2c2962986402 to your computer and use it in GitHub Desktop.
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.

<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment