9
9
* @see https://www.techiedelight.com/flood-fill-algorithm/
10
10
*/
11
11
12
- const neighbors = [
12
+ const neighborOffsets = [
13
13
[ - 1 , - 1 ] ,
14
14
[ - 1 , 0 ] ,
15
15
[ - 1 , 1 ] ,
@@ -20,6 +20,27 @@ const neighbors = [
20
20
[ 1 , 1 ]
21
21
]
22
22
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
+
23
44
/**
24
45
* Implements the flood fill algorithm through a breadth-first approach using a queue.
25
46
*
@@ -34,14 +55,7 @@ export function breadthFirstSearch(
34
55
targetColor ,
35
56
replacementColor
36
57
) {
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 )
45
59
46
60
const queue = [ ]
47
61
queue . push ( location )
@@ -65,14 +79,7 @@ export function depthFirstSearch(
65
79
targetColor ,
66
80
replacementColor
67
81
) {
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 )
76
83
77
84
depthFirstFill ( rgbData , location , targetColor , replacementColor )
78
85
}
@@ -98,13 +105,8 @@ function breadthFirstFill(
98
105
99
106
if ( rgbData [ currentLocation [ 0 ] ] [ currentLocation [ 1 ] ] === targetColor ) {
100
107
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 )
108
110
}
109
111
}
110
112
}
@@ -120,13 +122,8 @@ function breadthFirstFill(
120
122
function depthFirstFill ( rgbData , location , targetColor , replacementColor ) {
121
123
if ( rgbData [ location [ 0 ] ] [ location [ 1 ] ] === targetColor ) {
122
124
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 )
130
127
}
131
128
}
132
129
}
0 commit comments