José Morais
José Morais

Reputation: 359

Optimize javascript animation

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:

CPU consumption

How can I optimize this?

Upvotes: 0

Views: 195

Answers (2)

Owen
Owen

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

Gerardo Furtado
Gerardo Furtado

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

Related Questions