Search code examples
javascriptcanvasflood-fill

Recursive flood fill not working in Javascript


Here is my code. I don't think my logic is wrong but if it is please tell me:

function floodrecursive()
{
    let x=0;
    let y=0;
    
    canvas.addEventListener('click', e => {
        x = e.offsetX;
        y = e.offsetY;
        
        var basecolor = c.getImageData(x, y, 1, 1).data;
        //alert(basecolor);
        var fillcolor = document.getElementById("colorinput").value;
        
        flood(c, x, y, basecolor, fillcolor);
    });
}
    
function flood(c, x, y, basecolor, fillcolor)
{
    var currentpixel = c.getImageData(x, y, 1, 1).data;
    if (currentpixel === basecolor)
    {
        putpixel(c, x, y, fillcolor);
        flood(c, x+1, y, basecolor, fillcolor);
        flood(c, x-1, y, basecolor, fillcolor);
        flood(c, x, y+1, basecolor, fillcolor);
        flood(c, x, y-1, basecolor, fillcolor);
    }
}

function putpixel(c, x, y, fillcolor)
{
    c.fillStyle = "#" + fillcolor;
    c.fillRect(x, y, 1, 1);
}

I tried putting the flood and putpixel functions inside the floodrecursive function, or inside the addEventListener but it still won't work. I don't know why.

I already have this function:

window.onload=function() {covercanvas()};
function covercanvas()
{
    c.fillStyle="plum";
    c.fillRect(0, 0, 1030, 430);
}

so that the basecolor isn't transparent. And the alert(basecolor) works too so I don't know what's going wrong here.

Here's the HTML:

<button class="floodbutton" onclick="floodrecursive()"> Flood fill </button>

<input type="text" id="colorinput"></input>

How I expected the code to work is that after I draw on the canvas, put the hexa value of a color in the input box, then click the button, and click the canvas again, it should start flood filling.


Solution

  • I've added a hexAtoRGBA function and now it works perfectly. But I still... kinda don't understand. Here's the updated code:

    function floodrecursive()
    {
        let x=0;
        let y=0;
        
        canvas.addEventListener('click', e => {
            x = e.offsetX;
            y = e.offsetY;
            
            var basecolor = c.getImageData(x, y, 1, 1).data;
            var base = hexAToRGBA(basecolor);
            var fillcolor = document.getElementById("colorinput").value;
            
            flood(c, x, y, base, fillcolor);
        });
    }
        
    function flood(c, x, y, base, fillcolor)
    {
        var currentpixel = c.getImageData(x, y, 1, 1).data;
        var currentpix = hexAToRGBA(currentpixel);
        if (currentpix === base)
        {
            putpixel(c, x, y, fillcolor);
            flood(c, x+1, y, base, fillcolor);
            flood(c, x-1, y, base, fillcolor);
            flood(c, x, y+1, base, fillcolor);
            flood(c, x, y-1, base, fillcolor);
        }
    }
    
    function hexAToRGBA(h) {
      let r = 0, g = 0, b = 0, a = 1;
    
      if (h.length == 4) {
        r = "0x" + h[1] + h[1];
        g = "0x" + h[2] + h[2];
        b = "0x" + h[3] + h[3];
        a = "0x" + h[4] + h[4];
    
      } else if (h.length == 8) {
        r = "0x" + h[1] + h[2];
        g = "0x" + h[3] + h[4];
        b = "0x" + h[5] + h[6];
        a = "0x" + h[7] + h[8];
      }
      a = +(a / 255).toFixed(3);
    
      return "rgba(" + +r + "," + +g + "," + +b + "," + a + ")";
    }
    

    The thing I don't understand is, the c.getImageData already returns the value in RGBA format, so why does it work only after I've added the hexAtoRGBA function for both base and currentpix? They're both using c.getImageData so they're already comparing RGBA, right?