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