Showing then hiding animated indicator / spinner gifs are a good way to show a user that their action has worked and that something is happening while they wait for their ac
I've had similar problems in the past. Ultimately they've been fixed by optimizing or doing work in smaller chucks responding to user actions. In your case different zoom levels would trigger different rendering algorithms. You would only process what the user can see (plus maybe a buffer margin).
I believe the only simple workaround for you that would be cross-browser is to use setTimeout to give the ui thread a chance to run. Batch up your work into sets of operations and chain them together using several setTimeout calls. This will slow down the total processing time, but the user will at least be given feedback. Obviously this suggestion requires that your processing can be easily sectioned off. If that is the case you could also consider adding a progress bar for improved UX.
Modern browsers now run CSS animations independently of the UI thread if the animation is implemented using a transform, rather than by changing properties. An article on this can be found at http://www.phpied.com/css-animations-off-the-ui-thread/.
For example, some of the CSS spinners at http://projects.lukehaas.me/css-loaders/ are implemented with transforms and will not freeze when the UI thread is busy (e.g., the last spinner on that page).