99 * @see https://www.techiedelight.com/flood-fill-algorithm/
1010 */
1111
12- const neighbors = [
12+ const neighborOffsets = [
1313 [ - 1 , - 1 ] ,
1414 [ - 1 , 0 ] ,
1515 [ - 1 , 1 ] ,
@@ -20,6 +20,27 @@ const neighbors = [
2020 [ 1 , 1 ]
2121]
2222
23+ function isInside ( rgbData , location ) {
24+ const x = location [ 0 ]
25+ const y = location [ 1 ]
26+ return x >= 0 && x < rgbData . length && y >= 0 && y < rgbData [ 0 ] . length
27+ }
28+
29+ function checkLocation ( rgbData , location ) {
30+ if ( ! isInside ( rgbData , location ) ) {
31+ throw new Error ( 'location should point to a pixel within the rgbData' )
32+ }
33+ }
34+
35+ function * neighbors ( rgbData , location ) {
36+ for ( const offset of neighborOffsets ) {
37+ const neighborLocation = [ location [ 0 ] + offset [ 0 ] , location [ 1 ] + offset [ 1 ] ]
38+ if ( isInside ( rgbData , neighborLocation ) ) {
39+ yield neighborLocation
40+ }
41+ }
42+ }
43+
2344/**
2445 * Implements the flood fill algorithm through a breadth-first approach using a queue.
2546 *
@@ -34,14 +55,7 @@ export function breadthFirstSearch(
3455 targetColor ,
3556 replacementColor
3657) {
37- if (
38- location [ 0 ] < 0 ||
39- location [ 0 ] >= rgbData . length ||
40- location [ 1 ] < 0 ||
41- location [ 1 ] >= rgbData [ 0 ] . length
42- ) {
43- throw new Error ( 'location should point to a pixel within the rgbData' )
44- }
58+ checkLocation ( rgbData , location )
4559
4660 const queue = [ ]
4761 queue . push ( location )
@@ -65,14 +79,7 @@ export function depthFirstSearch(
6579 targetColor ,
6680 replacementColor
6781) {
68- if (
69- location [ 0 ] < 0 ||
70- location [ 0 ] >= rgbData . length ||
71- location [ 1 ] < 0 ||
72- location [ 1 ] >= rgbData [ 0 ] . length
73- ) {
74- throw new Error ( 'location should point to a pixel within the rgbData' )
75- }
82+ checkLocation ( rgbData , location )
7683
7784 depthFirstFill ( rgbData , location , targetColor , replacementColor )
7885}
@@ -98,13 +105,8 @@ function breadthFirstFill(
98105
99106 if ( rgbData [ currentLocation [ 0 ] ] [ currentLocation [ 1 ] ] === targetColor ) {
100107 rgbData [ currentLocation [ 0 ] ] [ currentLocation [ 1 ] ] = replacementColor
101-
102- for ( let i = 0 ; i < neighbors . length ; i ++ ) {
103- const x = currentLocation [ 0 ] + neighbors [ i ] [ 0 ]
104- const y = currentLocation [ 1 ] + neighbors [ i ] [ 1 ]
105- if ( x >= 0 && x < rgbData . length && y >= 0 && y < rgbData [ 0 ] . length ) {
106- queue . push ( [ x , y ] )
107- }
108+ for ( const neighborLocation of neighbors ( rgbData , currentLocation ) ) {
109+ queue . push ( neighborLocation )
108110 }
109111 }
110112}
@@ -120,13 +122,8 @@ function breadthFirstFill(
120122function depthFirstFill ( rgbData , location , targetColor , replacementColor ) {
121123 if ( rgbData [ location [ 0 ] ] [ location [ 1 ] ] === targetColor ) {
122124 rgbData [ location [ 0 ] ] [ location [ 1 ] ] = replacementColor
123-
124- for ( let i = 0 ; i < neighbors . length ; i ++ ) {
125- const x = location [ 0 ] + neighbors [ i ] [ 0 ]
126- const y = location [ 1 ] + neighbors [ i ] [ 1 ]
127- if ( x >= 0 && x < rgbData . length && y >= 0 && y < rgbData [ 0 ] . length ) {
128- depthFirstFill ( rgbData , [ x , y ] , targetColor , replacementColor )
129- }
125+ for ( const neighborLocation of neighbors ( rgbData , location ) ) {
126+ depthFirstFill ( rgbData , neighborLocation , targetColor , replacementColor )
130127 }
131128 }
132129}
0 commit comments