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:

1
2
3
4
5
6
7
8
9
    $scope.save = ( 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

1
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
1
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
1
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.

1
2
3
4
5
    $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

1
the_state.primes
instead of referencing
1
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

1
$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.