An HTML5 canvas Flood Fill that doesn’t kill the browser

I took the longest time implementing the fill tool  on Mandalagaba. How hard could it be? Recurse through pixels looking for a color and update them to a new color.

While this method certainly works and is easy to implement, it is also extremely slow. Slow in a way that hangs the browser, yielding infamous messages from the browser.

Here we’ll take a look at various Javascript flood fill implementations along with their drawbacks. Jump to #4 if you are only interested in the best one.

2018-10-04 – edit – added fill algorithm #5 which proposes an alternate approach to filling pixel by pixel. Depending on your project it may or may not serve your needs better.

In all cases, the code is available in the example iframe, look for the function flood_fill.

1. Simple Recursive

Not much to explain here, we simply recursively call the function on adjacent pixels when they match the color we are trying to fill over.

Click to change color / pop-out link

It’s reasonably fast but the problem with this one is that any fill area slightly large yields too much recursion which breaks subsequent JS. This Canvas box is 200x200px and at 300x300px, Firefox complained about:It’s easy to see how this implementation will not satisfy a reasonably featured paint program. Even if your browser let you stack more function on the heap, I would bet it would lead to slowness.

2. Iterative

We simply take the previous idea of looking at adjacent pixels and filling them, and make it iterative instead so the function calls don’t get stacked to a ceiling.

Click to change color / pop-out link

The problem with this is is that is is sloooow. So slow it stalls browser. Most of time is spent having to keep track of pixels_stack. Recursion doesn’t have that need but as we’ve seen, it has other issues.

3. Recursive-Iterative (AKA catch-your-breath iterative)

This is a twist on #2 which every so often, recurses on itself via a setTimeout to let the browser catch it breath a little. It also yields a cool visual effect.

Click to change color / pop-out link

I really like the visual effect, and it makes the slowness tolerable. But the issue is that Mandalagaba has a network engine and allows for re-rendering of one’s work. So synchronization is a big deal, and you know what makes synchronization easy? Not having to worry about it.

So as long as I can help it, my life is a lot easier if the operations the users can perform are atomic. Operations need to be able to be processed one after the other counting on the fact that the ones that came before have completed.

The first 2 solutions are atomic but suck; this 3rd one, however cool it may be, isn’t.

4. The Holy Grail

I’m not sure where this algorithm originated from, but I’ve gotten to know it on this web page which explains it very well (with GIFs!). It is iterative and goes about finding pixels to fill in a much smarter way.

Click to change color / pop-out link

That’s it, no drawback here 🙂 I’ve tested it on large canvasses and this is what is implemented on Mandalagaba. Now of course, in a real application there is a ton more complexity dealing with smoothing edges and blending alpha. I only wanted to expose boiled down versions of these algorithms so they are easier to wrap your mind around.

5. The Holier Grail?

While #4 is fastest algorithm for filling pixel by pixel, I found myself in the need to have a fill operation in for form of a path which is filled with the native HTML5 canvas capabilities. This algorithm is a bit different from all the other ones in that it doesn’t go through every pixel and fills it. What it does is pathfinding to draw the outline of the shape of be filled, and then simply calls the native canvas fill() function. It does come with certain drawbacks and so I wouldn’t recommend it unless you specifically need this sort of approach.

Click to change color / pop-out link

Feel free to ask questions in the comments.

Haying Fever

I’m getting good at changing implements

[mejsvideo mp4=”http://ben.akrin.com/videos/haying_fever.mov.mp4″ ogg=”http://ben.akrin.com/videos/haying_fever.mov.ogv” webm=”http://ben.akrin.com/videos/haying_fever.mov.webm” poster=”http://ben.akrin.com/videos/haying_fever.mov.jpg” width=”640″ height=”360″]

A nightmare if you’re allergic to pollen

Stuck in the mud once more… The truck will pull it out.

Take 2, with board to help not sink in. We need more culverts.

Off we go! later suckers, me & my tractor have got some fields to mow.

Black gold

From one Vermont hill

To our Vermont hill

Featuring: some guy with a giant ass tractor

Compost is gold, we haven’t been so good at making our own and the raspberries haven’t grown so well. This year we’re trying to pamper them more by weeding them more aggressively and making sure they’ve got more than enough nutrients in the soil.

Room flooring

This is a bedroom a kid will grow up and become a teenager in, I laid tongue and groove pine because I could use the hardest of woods, there will be holes through it. I figured it’ll be easier to be ok with the damage if it’s not super expensive wood. The result looks great but it will wear faster. I love the angles in that room, Robin has not been in it for weeks, we’re keeping it a surprise and will have a ribbon cutting ceremony in a couple of days.

The old crowbar helping straighten up recalcitrant boards

Working in tight spaces

Construction baby managing the crew

A first in 3 years

A nicely finished room, no visible insulation, studs or vapor barrier. It is incredibly satisfying to work on finishing a room. Since we now have enough space in the house, all the others will follow. We are done making temporary arrangements.

A guide for the circular is incredibly useful for making rip cuts.

How trims are born

Finer work is super satisfying

I opened the windows and discovered the view a few weeks ago, giving them a nice frame makes it all the more enjoyable.