Edge detection in a canvas I have one function in my code to detect edges in a canvas but it's the slowest part of my code and is used everywhere. If I could just optimise this, my whole program would speed up considerably.

Maybe something better can be done with Em6?

Basically the function goes from the left until it finds a pixel colour greater (or less than) the colour value passed to the function. Then it gets the maximum or minimum of all the values which is the edge of whatever is inside the image.

Then it does the same for the top, the right the bottom to find all edges. Useful for cropping something within a canvas.

function getEdges(tempcanv, colour, which, condition) {
    let ledge = [], redge = [], tedge = [], bedge = [];
    const canvwidth = tempcanv.width, canvheight = tempcanv.height;
    const contextd = tempcanv.getContext('2d');
    for (let y = 0; y &lt; canvheight; y++) {//left edge
        for (let x = 0; x &lt; canvwidth; x++) {
            const data = contextd.getImageData(x, y, 1, 1).data;
            if (condition(data[which], colour)) {
                ledge.push(x);
                break;
            }
        }
    }
    ledge = Math.min(...ledge);
    const llim = ledge === 0 ? ledge : ledge - 1;
    for (let x = llim; x &lt; canvwidth; x++) {//top edge
        for (let y = 0; y &lt; canvheight; y++) {
            const data = contextd.getImageData(x, y, 1, 1).data;
            if (condition(data[which], colour)) {
                tedge.push(y);
                break;
            }
        }
    }
    tedge = Math.min(...tedge);
    const tlim = tedge === 0 ? tedge : tedge - 1;
    for (let y = tlim; y &lt; canvheight; y++) {//right edge
        for (let x = canvwidth - 1; x &gt;= ledge; x--) {
            const data = contextd.getImageData(x, y, 1, 1).data;
            if (condition(data[which], colour)) {
                redge.push(x);
                break;
            }
        }
    }
    redge = Math.max(...redge);
    for (let x = llim; x &lt;= redge; x++) {//bottom edge
        for (let y = canvheight - 1; y &gt;= tedge; y--) {
            const data = contextd.getImageData(x, y, 1, 1).data;
            if (condition(data[which], colour)) {
                bedge.push(y);
                break;
            }
        }
    }
    return [ledge, tedge, redge + 1, Math.max(...bedge) + 1]
}

//(canvas passed, colour threshold, R,G or B, greater or less than)
getEdges(canvas, 180, 0, (a, b) =&gt; a &gt; b))


My code does have some optimisation since as it finds an edge, the next edge check does not check the dead space already checked.

Here is a test shape.
In your code you're calling GetImageData for each pixel adding a lot of call that are not necessary, you can do this by calling it once for the entire canvas and getting the data from the array.

GetImageData returns a 1 dim array with RGBA for each pixel like :

[R(pixel1),G(Pixel1),B(Pixel1),A(Pixel1),R(pixel2),G(Pixel2),...etc]


this means that you can get the pixel value by using (y * canvasWidth+ x)*4+RGBA
(RBGA is a 0-3 value representing the 4 values)

Another thing you can improve on is the order of your for loops. The way you're looping now you need to loop through the whole image before you can know the edge, however if you turn the loops around you can lessen the amount of pixels you need to check.

For example when going for the left edge you can start the double loop with x then y. This means that whenever the condition first becomes true you can be sure that it is the outer most left edge.

If you implement these relative easy changes the code would look more like this:

function getEdges(tempcanv, colour, which, condition) {
    let ledge = -1, redge = -1, tedge = -1, bedge = -1;
    const canvwidth = tempcanv.width, canvheight = tempcanv.height;
    const imageData = tempcanv.getContext('2d').getImageData(0, 0, canvwidth, canvheight).data; //gets all image data
    for (let x = 0; x &lt; canvwidth; x++) {//left edge
        if (ledge &gt;= 0) {
            break;
        }
        for (let y = 0; y &lt; canvheight; y++) {
            //(y * canvwidth + x) * 4 is for getting the current location
            if (condition(imageData[(y * canvwidth + x) * 4 + which], colour)) {
                ledge = x;
                break;
            }
        }
    }
    for (let x = canvwidth - 1; x &gt;= ledge; x--) {//right edge
        if (redge &gt;= 0) {
            break;
        }
        for (let y = 0; y &lt; canvheight; y++) {
            //(y * canvwidth + x) * 4 is for getting the current location
            if (condition(imageData[(y * canvwidth + x) * 4 + which], colour)) {
                redge = x;
                break;
            }
        }
    }
    for (let y = 0; y &lt; canvheight; y++) {//top edge
        if (tedge &gt;= 0) {
            break;
        }
        for (let x = ledge; x &lt;= redge; x++) {
            //(y * canvwidth + x) * 4 is for getting the current location
            if (condition(imageData[(y * canvwidth + x) * 4 + which], colour)) {
                tedge = y;
                break;
            }
        }
    }
    for (let y = canvheight-1; y &gt;= tedge; y--) {//bottom edge
        if (bedge &gt;= 0) {
            break;
        }
        for (let x = ledge; x &lt;= redge; x++) {
            //(y * canvwidth + x) * 4 is for getting the current location
            if (condition(imageData[(y * canvwidth + x) * 4 + which], colour)) {
                bedge = y;
                break;
            }
        }
    }
    console.log('edges', [ledge, tedge, redge + 1, bedge + 1]);
    return [ledge, tedge, redge + 1, bedge + 1]
}