Sieve of Eratosthenes in AngularJS with better but not perfect animation

In my last post I explored how to build the Sieve of Eratosthenes using AngularJS. The one issue I disliked was that my animation of the algorithm process did not really reflect the true timing if each step were slowed down to allow a human to watch it operate. You can do this if you use JS timeouts, but using timeouts with recursive algorithms leaves a bad taste in the mouth.

I have been thinking about this for a few days and I think I have a good solution. At each important step save the state of the process and then have a separate timeout looping over those states and displaying them. The user gets a true calculation without wrapping recursion inside a timeout callback, and the UI displays correctly.

For example, this code shows what I mean:

$ = ( arr ) ->
        $scope.states.push {
                marking: arr?.marking,
                primes: angular.copy( $scope.primes ),
                looking : arr?.looking,
                found: arr?.found,
                p : $scope.p,
                numbers: angular.copy( $scope.numbers )

I built a function called state which simply saves the state at any point. I know which variables are interesting inside my algorithm: in the case of the Sieve of Eratosthenes, they are the P value, the value of the current index when looking for the next prime (called looking here) and when a new prime has been found. I also have an array of the current primes, and the entire set of numbers. Also, if you need to copy an object like an array which is not a simple value you need to use angular.copy to do a deep copy. Otherwise you are just copying a reference and your data will be coming from the moment in time the variable is referenced, rather than the moment in time when the save() method was called.

Then, after I start my algorithm, I set a timeout to iterate over all the state objects, putting a new state into the current state.

$scope.startAnimation = () ->
        console.log "Jumping to next state"
        if $scope.states.length > 1
                $scope.the_state = $scope.states.shift()
                $timeout( $scope.startAnimation, $scope.stepInt )

I had to change the HTML code to use the_state.primes instead of referencing primes.

You can see all this in action on the gh-pages site or in the repository.

There is a problem which I have not hunted down yet: the CPU slowly gets to 100% with this code. I am unclear as to why: it seems like the intensive portion should be the place where I copy in the arrays and that timeout should simply be copying a reference. But, towards the end of the algorithm, my browser starts to crawl.

Also, the explosion animations are lost. This is because I am rebuilding the DOM with new data each time a new state is popped off the stack, instead of modifying some existing data such that AngularJS knows a change has occurred. The way to fix this is to do a diff of the state as rendered in the browser from the state popped off the stack. This would mean that AngularJS would notice a change in the $digest() cycle and add the proper CSS classes for the animations. This diffing operating looks pretty straightforward in this case, but not something I want to write now.