@litecanvas/utils 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/grid/index.js CHANGED
@@ -1,91 +1,239 @@
1
- class Grid {
1
+ export default class Grid {
2
+ /** @type {number} The grid width */
3
+ _w
4
+
5
+ /** @type {number} The grid height */
6
+ _h
7
+
8
+ /** @type {any[]} The grid cells */
9
+ _c
10
+
11
+ /**
12
+ * @static
13
+ * @param {number} width
14
+ * @param {number} height
15
+ * @param {any[]} values
16
+ */
17
+ static fromArray(width, height, values) {
18
+ const grid = new Grid(width, height)
19
+ for (let i = 0; i < values.length; i++) {
20
+ grid._c[i] = values[i]
21
+ }
22
+ return grid
23
+ }
24
+
25
+ /**
26
+ * @param {number} width The grid width
27
+ * @param {number} height The grid height
28
+ */
2
29
  constructor(width, height) {
3
- this._width = Math.abs(width)
4
- this._height = Math.abs(height)
30
+ this.width = width
31
+ this.height = height
5
32
  this.clear()
6
33
  }
7
34
 
8
- set(x, y, value) {
9
- this.__cells[this.__getIndex(x, y)] = value
10
- return this
35
+ /**
36
+ * Delete all cell values.
37
+ */
38
+ clear() {
39
+ this._c = Array(this._w * this._h)
11
40
  }
12
41
 
13
- get(x, y) {
14
- return this.__cells[this.__getIndex(x, y)] || null
42
+ /**
43
+ * @param {number} value
44
+ */
45
+ set width(value) {
46
+ this._w = Math.max(1, ~~value)
15
47
  }
16
48
 
17
- has(x, y) {
18
- return this.get(x, y) != null
49
+ get width() {
50
+ return this._w
19
51
  }
20
52
 
21
- get width() {
22
- return this._width
53
+ /**
54
+ * @param {number} value
55
+ */
56
+ set height(value) {
57
+ this._h = Math.max(1, ~~value)
23
58
  }
24
59
 
25
60
  get height() {
26
- return this._height
61
+ return this._h
62
+ }
63
+
64
+ /**
65
+ * The the value of a grid's cell.
66
+ *
67
+ * @param {number} x
68
+ * @param {number} y
69
+ * @param {any} value
70
+ */
71
+ set(x, y, value) {
72
+ this._c[this.pointToIndex(x, y)] = value
73
+ }
74
+
75
+ /**
76
+ * Returns the value of a grid's cell.
77
+ *
78
+ * @param {number} x
79
+ * @param {number} y
80
+ * @returns {any}
81
+ */
82
+ get(x, y) {
83
+ return this._c[this.pointToIndex(x, y)]
27
84
  }
28
85
 
86
+ /**
87
+ * Returns true if the which cell has any value not equal to `null` or `undefined`.
88
+ *
89
+ * @param {number} x
90
+ * @param {number} y
91
+ * @returns {boolean}
92
+ */
93
+ has(x, y) {
94
+ return this.get(x, y) != null
95
+ }
96
+
97
+ /**
98
+ * Returns the total of cells.
99
+ *
100
+ * @returns {number}
101
+ */
29
102
  get length() {
30
- return this._width * this._height
31
- }
32
-
33
- forEach(callback, reverse = false) {
34
- const cells = this.__cells,
35
- w = this._width,
36
- h = this._height,
37
- limitX = !reverse ? w : -1,
38
- limitY = !reverse ? h : -1
39
- let x = !reverse ? 0 : w - 1,
40
- y = !reverse ? 0 : h - 1
41
-
42
- while (y != limitY) {
43
- let proceed
44
- x = !reverse ? 0 : w - 1
45
- while (x != limitX) {
46
- proceed = callback(cells[this.__getIndex(x, y)], x, y, this)
47
- if (false === proceed) break
48
- x += reverse ? -1 : 1
49
- }
50
- if (false === proceed) break
51
- y += reverse ? -1 : 1
103
+ return this._w * this._h
104
+ }
105
+
106
+ /**
107
+ * Convert a grid point (X, Y) to a index.
108
+ *
109
+ * @param {number} x
110
+ * @param {number} y
111
+ * @returns {number} The index
112
+ */
113
+ pointToIndex(x, y) {
114
+ return this.clampX(~~x) + this.clampY(~~y) * this._w
115
+ }
116
+
117
+ /**
118
+ * Convert index to a grid point X.
119
+ *
120
+ * @param {number} index
121
+ * @returns {number}
122
+ */
123
+ indexToPointX(index) {
124
+ return index % this._w
125
+ }
126
+
127
+ /**
128
+ * Convert index to a grid point Y.
129
+ *
130
+ * @param {number} index
131
+ * @returns {number}
132
+ */
133
+ indexToPointY(index) {
134
+ return Math.floor(index / this._w)
135
+ }
136
+
137
+ /**
138
+ * Loops over all grid cells.
139
+ *
140
+ * @callback GridForEachCallback
141
+ * @param {number} x
142
+ * @param {number} y
143
+ * @param {any} value
144
+ * @param {Grid} grid
145
+ * @returns {boolean?} returns `false` to stop/break the loop
146
+ *
147
+ * @param {GridForEachCallback} handler
148
+ * @param {boolean} [reverse=false]
149
+ */
150
+ forEach(handler, reverse = false) {
151
+ let i = reverse ? this.length - 1 : 0,
152
+ limit = reverse ? -1 : this.length,
153
+ step = reverse ? -1 : 1
154
+
155
+ while (i !== limit) {
156
+ const x = this.indexToPointX(i),
157
+ y = this.indexToPointY(i),
158
+ cellValue = this._c[i]
159
+
160
+ if (false === handler(x, y, cellValue, this)) break
161
+
162
+ i += step
52
163
  }
53
- return this
54
164
  }
55
165
 
56
- clone() {
57
- return Grid.fromArray(this._width, this._height, this.__cells)
166
+ /**
167
+ * @param {*} value
168
+ */
169
+ fill(value) {
170
+ this.forEach((x, y) => {
171
+ this.set(x, y, value)
172
+ })
58
173
  }
59
174
 
60
- clear() {
61
- this.__cells = Array(this._width * this._height)
62
- return this
175
+ /**
176
+ * @returns {Grid} the cloned grid
177
+ */
178
+ clone() {
179
+ return Grid.fromArray(this._w, this._h, this._c)
63
180
  }
64
181
 
65
- clipX(x) {
66
- return this.__clip(x, 0, this._width - 1)
182
+ /**
183
+ * @param {number} y
184
+ * @returns {number}
185
+ */
186
+ clampX(x) {
187
+ return _clamp(x, 0, this._w - 1)
67
188
  }
68
189
 
69
- clipY(y) {
70
- return this.__clip(y, 0, this._height - 1)
190
+ /**
191
+ * @param {number} y
192
+ * @returns {number}
193
+ */
194
+ clampY(y) {
195
+ return _clamp(y, 0, this._h - 1)
71
196
  }
72
197
 
198
+ /**
199
+ * Returns the cell values in a single array.
200
+ *
201
+ * @returns {any[]}
202
+ */
73
203
  toArray() {
74
- return this.__cells.slice(0)
204
+ return this._c.slice(0)
75
205
  }
76
206
 
77
- toString() {
78
- return this.__cells.join(",")
79
- }
207
+ /**
208
+ * @param {string} separator
209
+ * @param {boolean} format
210
+ * @returns {string}
211
+ */
212
+ toString(separator = " ", format = true) {
213
+ if (!format) return this._c.join(separator)
80
214
 
81
- // internals
82
- __getIndex(x, y) {
83
- x = this.clipX(x)
84
- y = this.clipY(y)
85
- return x + y * this._width
86
- }
215
+ const rows = []
216
+ this.forEach((x, y, value) => {
217
+ rows[y] = rows[y] || ""
218
+ rows[y] += value + separator
219
+ })
87
220
 
88
- __clip(n, min, max) {
89
- return Math.min(Math.max(n, min), max)
221
+ return rows.join("\n")
90
222
  }
91
223
  }
224
+
225
+ /**
226
+ * Constrains a number between `min` and `max`.
227
+ *
228
+ * @param {number} value
229
+ * @param {number} min
230
+ * @param {number} max
231
+ * @returns {number}
232
+ */
233
+ function _clamp(value, min, max) {
234
+ if (value < min) return min
235
+ if (value > max) return max
236
+ return value
237
+ }
238
+
239
+ function _fill(x, y) {}
package/src/index.js CHANGED
@@ -4,4 +4,6 @@ export { default as wave } from "./math/wave.js"
4
4
  export { default as resolve } from "./collision/resolve.js"
5
5
  export { default as intersection } from "./collision/intersection.js"
6
6
  export { default as Camera } from "./camera/index.js"
7
+ export { default as Grid } from "./grid/index.js"
7
8
  export * from "./vector/index.js"
9
+ export * from "./actor/index.js"
@@ -42,7 +42,7 @@ export const veceq = (v, x, y = x) => {
42
42
  if (isvector(x)) {
43
43
  return veceq(v, x.x, x.y)
44
44
  }
45
- return v.x === x && v.y === (y || x)
45
+ return v.x === x && v.y === y
46
46
  }
47
47
 
48
48
  /**