4

In BASIC there is a command called PAINT that looks like this:

PAINT (column, row), color, color-stop

It takes x/y coordinates as a starting place and begins filling it and the surrounding pixels in with color until it reaches the color defined in color-stop. An example with values might be:

PAINT (200, 400), 4, 6

QuickBasic uses 0-15 to represent different colors. Each of these colors has an equivalent hexadecimal value.

In the lines preceding the PAINT there are usually lines, circles, etc. drawn of a different (the color-stop) color which set boundaries for how much screen space the PAINT command can actually utilize.

Any ideas on how to accomplish something similar in JavaScript?

Dave Mackey
  • 4,306
  • 21
  • 78
  • 136
  • 2
    Do a DFS/BFS on a point inside `canvas.getImageData` https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData – Isaac Nov 23 '16 at 04:36
  • This looks like it only applies to rectangles? – Dave Mackey Nov 23 '16 at 04:44
  • get the whole rectangle, do a DFS from a point on that map in every direction until you hit a boundary, keep a record of the boundary, set the pixels within that boundary – Isaac Nov 23 '16 at 04:48
  • 1
    https://en.wikipedia.org/wiki/Flood_fill – Isaac Nov 23 '16 at 04:49
  • Thanks! That is helpful. It looks like I need the slightly different boundary fill...looking to see what I can find on this, not nearly as much on boundary fill as on flood fill. – Dave Mackey Nov 23 '16 at 05:56
  • Did you ever manage to accomplish what you were trying for? I could help retool the code I provided for your purposes after work. – Robert Talada May 14 '18 at 14:42

1 Answers1

1

I adapted a solution I found here: http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool/

It works like a scanline and creates nodes to return the scan to in a different direction when its path is blocked, this is the "pixelStack."

In general, all of the good solutions that I have seen involve creating a stack of blocked locations to return to from which the fill algorithm's path is essentially forked.

        function fill(startX,startY,fcol,bcol,vram){
            // This function adapted from code at:
            // http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool/
            // and https://github.com/williammalone/HTML5-Paint-Bucket-Tool/blob/master/html5-canvas-paint-bucket.js
            // Copyright 2010 William Malone (www.williammalone.com)
            //
            // Thanks William, yours works better than mine did. :)
            //
            // Licensed under the Apache License, Version 2.0 (the "License");
            // you may not use this fill function except in compliance with the License.
            // You may obtain a copy of the License at
            //
            //   http://www.apache.org/licenses/LICENSE-2.0
            //
            // Unless required by applicable law or agreed to in writing, software
            // distributed under the License is distributed on an "AS IS" BASIS,
            // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
            // See the License for the specific language governing permissions and
            // limitations under the License.

            var pixelStack = [[startX, startY]];
            var startColor = point(startX,startY,vram);

            while(pixelStack.length)
            {
              var newPos, x, y, pixelPos, reachLeft, reachRight;
              newPos = pixelStack.pop();
              x = newPos[0];
              y = newPos[1];

              pixelPos = (y*canvasWidth + x);
              while(y-- >= 25 && matchStartColor(pixelPos,startColor,vram))
              {
                pixelPos -= canvasWidth;
              }
              pixelPos += canvasWidth;
              ++y;
              reachLeft = false;
              reachRight = false;
              while(y++ < canvasHeight-1 && matchStartColor(pixelPos,startColor,vram))
              {
                colorPixel(pixelPos,fcol,vram);

                if(x > 0)
                {
                  if(matchStartColor(pixelPos - 1,startColor,vram))
                  {
                    if(!reachLeft){
                      pixelStack.push([x - 1, y]);
                      reachLeft = true;
                    }
                  }
                  else if(reachLeft)
                  {
                    reachLeft = false;
                  }
                }

                if(x < canvasWidth-1)
                {
                  if(matchStartColor(pixelPos + 1,startColor,vram))
                  {
                    if(!reachRight)
                    {
                      pixelStack.push([x + 1, y]);
                      reachRight = true;
                    }
                  }
                  else if(reachRight)
                  {
                    reachRight = false;
                  }
                }

                pixelPos += canvasWidth;
              }
            }

            function matchStartColor(pixelPos,startColor,vram)
            {
              return (vram[pixelPos]==startColor);
            }

            function colorPixel(pixelPos,col,vram)
            {
              pset(pixelPos%320,Math.floor(pixelPos/320),col,vram)
            }
        }
Robert Talada
  • 317
  • 1
  • 10
  • To satiate any curiosity, this code was used in my attempt to port a SCREEN 13 sprite editor to JavaScript. If you want to see it in use, stop by: https://robtalada.com/apps/entity-editor7 (or 8, or whichever version I'm currently on) – Robert Talada May 04 '18 at 17:17