Reputation: 359
I have a sky full of stars (at least 200 at any given time) and I want to make them twinkle. I'm using D3.js to render the stars. Currently I'm using the following code:
svg.select(".stars").selectAll("circle")
.each(function() {
var circle = d3.select(this);
(function twinkle() {
circle.transition()
.duration(20 + 480 * Math.random())
.ease("linear")
.attr("opacity", 0.5 + 0.5 * Math.random())
.each("end", twinkle);
})();
});
As you can see, twinkle()
make a random opacity animation and then recall twinkle()
. With 200 stars it doesn't go so well:
How can I optimize this?
Upvotes: 0
Views: 195
Reputation: 1547
I think the reason for the poor performance is that Chrome is trying to maintain hundreds of parallel transitions and interpolations. Since the effect you are after is not dependent on transitions, consider removing the transition and simply updating the opacity with sufficient frequency to make it look smooth. My attempt is as follows:
var stars = svg.select(".stars").selectAll("circle");
function twinkle() {
stars
.filter(function() { return Math.random() < 0.1 })
.attr('opacity', function(d,i) { return 0.7 + 0.3 * Math.random() })
setTimeout(twinkle, 90)
}
twinkle()
Upvotes: 1
Reputation: 102194
An alternative using setInterval
:
var svg = d3.select("body")
.append("svg")
.attr("width", 400)
.attr("height", 400);
var data = d3.range(200);
var circles = svg.selectAll(".circles")
.data(data)
.enter()
.append("circle");
circles.attr("r", 1)
.attr("cx", function(){ return Math.random()*400})
.attr("cy", function(){ return Math.random()*400});
function twinkle(){
svg.selectAll("circle").each(function(){
var thisCircle = d3.select(this);
thisCircle.transition()
.duration(20 + 480 * Math.random())
.ease("linear")
.attr("opacity", 0.5 + 0.5 * Math.random());
})
}
setInterval(twinkle, 500);
svg {
background-color: black;
}
circle {
fill: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 1