@js-draw/math 1.0.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/Color4.d.ts +40 -0
  3. package/dist/cjs/Color4.js +102 -0
  4. package/dist/cjs/Color4.test.d.ts +1 -0
  5. package/dist/cjs/Mat33.test.d.ts +1 -0
  6. package/dist/cjs/Vec2.test.d.ts +1 -0
  7. package/dist/cjs/Vec3.test.d.ts +1 -0
  8. package/dist/cjs/polynomial/solveQuadratic.test.d.ts +1 -0
  9. package/dist/cjs/rounding.test.d.ts +1 -0
  10. package/dist/cjs/shapes/LineSegment2.test.d.ts +1 -0
  11. package/dist/cjs/shapes/Path.fromString.test.d.ts +1 -0
  12. package/dist/cjs/shapes/Path.test.d.ts +1 -0
  13. package/dist/cjs/shapes/Path.toString.test.d.ts +1 -0
  14. package/dist/cjs/shapes/QuadraticBezier.test.d.ts +1 -0
  15. package/dist/cjs/shapes/Rect2.test.d.ts +1 -0
  16. package/dist/cjs/shapes/Triangle.test.d.ts +1 -0
  17. package/dist/mjs/Color4.d.ts +40 -0
  18. package/dist/mjs/Color4.mjs +102 -0
  19. package/dist/mjs/Color4.test.d.ts +1 -0
  20. package/dist/mjs/Mat33.test.d.ts +1 -0
  21. package/dist/mjs/Vec2.test.d.ts +1 -0
  22. package/dist/mjs/Vec3.test.d.ts +1 -0
  23. package/dist/mjs/polynomial/solveQuadratic.test.d.ts +1 -0
  24. package/dist/mjs/rounding.test.d.ts +1 -0
  25. package/dist/mjs/shapes/LineSegment2.test.d.ts +1 -0
  26. package/dist/mjs/shapes/Path.fromString.test.d.ts +1 -0
  27. package/dist/mjs/shapes/Path.test.d.ts +1 -0
  28. package/dist/mjs/shapes/Path.toString.test.d.ts +1 -0
  29. package/dist/mjs/shapes/QuadraticBezier.test.d.ts +1 -0
  30. package/dist/mjs/shapes/Rect2.test.d.ts +1 -0
  31. package/dist/mjs/shapes/Triangle.test.d.ts +1 -0
  32. package/dist-test/test_imports/package-lock.json +13 -0
  33. package/dist-test/test_imports/package.json +12 -0
  34. package/dist-test/test_imports/test-imports.js +15 -0
  35. package/dist-test/test_imports/test-require.cjs +15 -0
  36. package/package.json +4 -3
  37. package/src/Color4.test.ts +94 -0
  38. package/src/Color4.ts +430 -0
  39. package/src/Mat33.test.ts +244 -0
  40. package/src/Mat33.ts +450 -0
  41. package/src/Vec2.test.ts +30 -0
  42. package/src/Vec2.ts +49 -0
  43. package/src/Vec3.test.ts +51 -0
  44. package/src/Vec3.ts +245 -0
  45. package/src/lib.ts +42 -0
  46. package/src/polynomial/solveQuadratic.test.ts +39 -0
  47. package/src/polynomial/solveQuadratic.ts +43 -0
  48. package/src/rounding.test.ts +65 -0
  49. package/src/rounding.ts +167 -0
  50. package/src/shapes/Abstract2DShape.ts +63 -0
  51. package/src/shapes/BezierJSWrapper.ts +93 -0
  52. package/src/shapes/CubicBezier.ts +35 -0
  53. package/src/shapes/LineSegment2.test.ts +99 -0
  54. package/src/shapes/LineSegment2.ts +232 -0
  55. package/src/shapes/Path.fromString.test.ts +223 -0
  56. package/src/shapes/Path.test.ts +309 -0
  57. package/src/shapes/Path.toString.test.ts +77 -0
  58. package/src/shapes/Path.ts +963 -0
  59. package/src/shapes/PointShape2D.ts +33 -0
  60. package/src/shapes/QuadraticBezier.test.ts +31 -0
  61. package/src/shapes/QuadraticBezier.ts +142 -0
  62. package/src/shapes/Rect2.test.ts +209 -0
  63. package/src/shapes/Rect2.ts +346 -0
  64. package/src/shapes/Triangle.test.ts +61 -0
  65. package/src/shapes/Triangle.ts +139 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Henry Heino
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -46,6 +46,25 @@ export default class Color4 {
46
46
  * ```
47
47
  */
48
48
  mix(other: Color4, fractionTo: number): Color4;
49
+ /**
50
+ * Ignoring this color's alpha component, returns a vector with components,
51
+ * $$
52
+ * \begin{pmatrix} \colorbox{#F44}{\tt r} \\ \colorbox{#4F4}{\tt g} \\ \colorbox{#44F}{\tt b} \end{pmatrix}
53
+ * $$
54
+ */
55
+ get rgb(): Vec3;
56
+ /**
57
+ * Returns the [relative luminance](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef)
58
+ * of this color in the sRGB color space.
59
+ *
60
+ * Ignores the alpha component.
61
+ */
62
+ relativeLuminance(): number;
63
+ /**
64
+ * Returns the [contrast ratio](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef)
65
+ * between `colorA` and `colorB`.
66
+ */
67
+ static contrastRatio(colorA: Color4, colorB: Color4): number;
49
68
  /**
50
69
  * @returns the component-wise average of `colors`, or `Color4.transparent` if `colors` is empty.
51
70
  */
@@ -57,6 +76,27 @@ export default class Color4 {
57
76
  * The resultant hue is represented in radians and is thus in $[0, 2\pi]$.
58
77
  */
59
78
  asHSV(): Vec3;
79
+ /**
80
+ * Creates a new `Color4` from a representation [in $HSV$](https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB).
81
+ *
82
+ * [Algorithm](https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB).
83
+ *
84
+ * Note that hue must be given **in radians**. While non-standard, this is consistent with
85
+ * {@link asHSV}.
86
+ *
87
+ * `hue` and `value` should range from 0 to 1.
88
+ *
89
+ * @param hue $H \in [0, 2\pi]$
90
+ * @param saturation $S_V \in [0, 1]$
91
+ * @param value $V \in [0, 1]$
92
+ */
93
+ static fromHSV(hue: number, saturation: number, value: number): Color4;
94
+ /**
95
+ * Equivalent to `ofRGB(rgb.x, rgb.y, rgb.z)`.
96
+ *
97
+ * All components should be in the range `[0, 1]` (0 to 1 inclusive).
98
+ */
99
+ static fromRGBVector(rgb: Vec3, alpha?: number): Color4;
60
100
  private hexString;
61
101
  /**
62
102
  * @returns a hexadecimal color string representation of `this`, in the form `#rrggbbaa`.
@@ -144,6 +144,49 @@ class Color4 {
144
144
  const fractionOfThis = 1 - fractionTo;
145
145
  return new Color4(this.r * fractionOfThis + other.r * fractionTo, this.g * fractionOfThis + other.g * fractionTo, this.b * fractionOfThis + other.b * fractionTo, this.a * fractionOfThis + other.a * fractionTo);
146
146
  }
147
+ /**
148
+ * Ignoring this color's alpha component, returns a vector with components,
149
+ * $$
150
+ * \begin{pmatrix} \colorbox{#F44}{\tt r} \\ \colorbox{#4F4}{\tt g} \\ \colorbox{#44F}{\tt b} \end{pmatrix}
151
+ * $$
152
+ */
153
+ get rgb() {
154
+ return Vec3_1.default.of(this.r, this.g, this.b);
155
+ }
156
+ /**
157
+ * Returns the [relative luminance](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef)
158
+ * of this color in the sRGB color space.
159
+ *
160
+ * Ignores the alpha component.
161
+ */
162
+ relativeLuminance() {
163
+ // References:
164
+ // - https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
165
+ // - https://stackoverflow.com/a/9733420
166
+ // Normalize the components, as per above
167
+ const components = [this.r, this.g, this.b].map(component => {
168
+ if (component < 0.03928) {
169
+ return component / 12.92;
170
+ }
171
+ else {
172
+ return Math.pow((component + 0.055) / 1.055, 2.4);
173
+ }
174
+ });
175
+ // From w3.org,
176
+ // > For the sRGB colorspace, the relative luminance of a color is
177
+ // > defined as L = 0.2126 * R + 0.7152 * G + 0.0722 * B
178
+ // where R, G, B are defined in components above.
179
+ return 0.2126 * components[0] + 0.7152 * components[1] + 0.0722 * components[2];
180
+ }
181
+ /**
182
+ * Returns the [contrast ratio](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef)
183
+ * between `colorA` and `colorB`.
184
+ */
185
+ static contrastRatio(colorA, colorB) {
186
+ const L1 = colorA.relativeLuminance();
187
+ const L2 = colorB.relativeLuminance();
188
+ return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05);
189
+ }
147
190
  /**
148
191
  * @returns the component-wise average of `colors`, or `Color4.transparent` if `colors` is empty.
149
192
  */
@@ -229,6 +272,65 @@ class Color4 {
229
272
  const saturation = value > 0 ? chroma / value : 0;
230
273
  return Vec3_1.default.of(hue, saturation, value);
231
274
  }
275
+ /**
276
+ * Creates a new `Color4` from a representation [in $HSV$](https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB).
277
+ *
278
+ * [Algorithm](https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB).
279
+ *
280
+ * Note that hue must be given **in radians**. While non-standard, this is consistent with
281
+ * {@link asHSV}.
282
+ *
283
+ * `hue` and `value` should range from 0 to 1.
284
+ *
285
+ * @param hue $H \in [0, 2\pi]$
286
+ * @param saturation $S_V \in [0, 1]$
287
+ * @param value $V \in [0, 1]$
288
+ */
289
+ static fromHSV(hue, saturation, value) {
290
+ if (hue < 0) {
291
+ hue += Math.PI * 2;
292
+ }
293
+ hue %= Math.PI * 2;
294
+ // Clamp value and saturation to [0, 1]
295
+ value = Math.max(0, Math.min(1, value));
296
+ saturation = Math.max(0, Math.min(1, saturation));
297
+ // Formula from https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
298
+ // Saturation can be thought of as scaled chroma. Unapply the scaling.
299
+ // See https://en.wikipedia.org/wiki/HSL_and_HSV#Saturation
300
+ const chroma = value * saturation;
301
+ // Determines which edge of the projected color cube
302
+ const huePrime = hue / (Math.PI / 3);
303
+ const secondLargestComponent = chroma * (1 - Math.abs((huePrime % 2) - 1));
304
+ let rgb;
305
+ if (huePrime < 1) {
306
+ rgb = [chroma, secondLargestComponent, 0];
307
+ }
308
+ else if (huePrime < 2) {
309
+ rgb = [secondLargestComponent, chroma, 0];
310
+ }
311
+ else if (huePrime < 3) {
312
+ rgb = [0, chroma, secondLargestComponent];
313
+ }
314
+ else if (huePrime < 4) {
315
+ rgb = [0, secondLargestComponent, chroma];
316
+ }
317
+ else if (huePrime < 5) {
318
+ rgb = [secondLargestComponent, 0, chroma];
319
+ }
320
+ else {
321
+ rgb = [chroma, 0, secondLargestComponent];
322
+ }
323
+ const adjustment = value - chroma;
324
+ return Color4.ofRGB(rgb[0] + adjustment, rgb[1] + adjustment, rgb[2] + adjustment);
325
+ }
326
+ /**
327
+ * Equivalent to `ofRGB(rgb.x, rgb.y, rgb.z)`.
328
+ *
329
+ * All components should be in the range `[0, 1]` (0 to 1 inclusive).
330
+ */
331
+ static fromRGBVector(rgb, alpha) {
332
+ return Color4.ofRGBA(rgb.x, rgb.y, rgb.z, alpha ?? 1);
333
+ }
232
334
  /**
233
335
  * @returns a hexadecimal color string representation of `this`, in the form `#rrggbbaa`.
234
336
  *
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -46,6 +46,25 @@ export default class Color4 {
46
46
  * ```
47
47
  */
48
48
  mix(other: Color4, fractionTo: number): Color4;
49
+ /**
50
+ * Ignoring this color's alpha component, returns a vector with components,
51
+ * $$
52
+ * \begin{pmatrix} \colorbox{#F44}{\tt r} \\ \colorbox{#4F4}{\tt g} \\ \colorbox{#44F}{\tt b} \end{pmatrix}
53
+ * $$
54
+ */
55
+ get rgb(): Vec3;
56
+ /**
57
+ * Returns the [relative luminance](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef)
58
+ * of this color in the sRGB color space.
59
+ *
60
+ * Ignores the alpha component.
61
+ */
62
+ relativeLuminance(): number;
63
+ /**
64
+ * Returns the [contrast ratio](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef)
65
+ * between `colorA` and `colorB`.
66
+ */
67
+ static contrastRatio(colorA: Color4, colorB: Color4): number;
49
68
  /**
50
69
  * @returns the component-wise average of `colors`, or `Color4.transparent` if `colors` is empty.
51
70
  */
@@ -57,6 +76,27 @@ export default class Color4 {
57
76
  * The resultant hue is represented in radians and is thus in $[0, 2\pi]$.
58
77
  */
59
78
  asHSV(): Vec3;
79
+ /**
80
+ * Creates a new `Color4` from a representation [in $HSV$](https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB).
81
+ *
82
+ * [Algorithm](https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB).
83
+ *
84
+ * Note that hue must be given **in radians**. While non-standard, this is consistent with
85
+ * {@link asHSV}.
86
+ *
87
+ * `hue` and `value` should range from 0 to 1.
88
+ *
89
+ * @param hue $H \in [0, 2\pi]$
90
+ * @param saturation $S_V \in [0, 1]$
91
+ * @param value $V \in [0, 1]$
92
+ */
93
+ static fromHSV(hue: number, saturation: number, value: number): Color4;
94
+ /**
95
+ * Equivalent to `ofRGB(rgb.x, rgb.y, rgb.z)`.
96
+ *
97
+ * All components should be in the range `[0, 1]` (0 to 1 inclusive).
98
+ */
99
+ static fromRGBVector(rgb: Vec3, alpha?: number): Color4;
60
100
  private hexString;
61
101
  /**
62
102
  * @returns a hexadecimal color string representation of `this`, in the form `#rrggbbaa`.
@@ -138,6 +138,49 @@ class Color4 {
138
138
  const fractionOfThis = 1 - fractionTo;
139
139
  return new Color4(this.r * fractionOfThis + other.r * fractionTo, this.g * fractionOfThis + other.g * fractionTo, this.b * fractionOfThis + other.b * fractionTo, this.a * fractionOfThis + other.a * fractionTo);
140
140
  }
141
+ /**
142
+ * Ignoring this color's alpha component, returns a vector with components,
143
+ * $$
144
+ * \begin{pmatrix} \colorbox{#F44}{\tt r} \\ \colorbox{#4F4}{\tt g} \\ \colorbox{#44F}{\tt b} \end{pmatrix}
145
+ * $$
146
+ */
147
+ get rgb() {
148
+ return Vec3.of(this.r, this.g, this.b);
149
+ }
150
+ /**
151
+ * Returns the [relative luminance](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef)
152
+ * of this color in the sRGB color space.
153
+ *
154
+ * Ignores the alpha component.
155
+ */
156
+ relativeLuminance() {
157
+ // References:
158
+ // - https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
159
+ // - https://stackoverflow.com/a/9733420
160
+ // Normalize the components, as per above
161
+ const components = [this.r, this.g, this.b].map(component => {
162
+ if (component < 0.03928) {
163
+ return component / 12.92;
164
+ }
165
+ else {
166
+ return Math.pow((component + 0.055) / 1.055, 2.4);
167
+ }
168
+ });
169
+ // From w3.org,
170
+ // > For the sRGB colorspace, the relative luminance of a color is
171
+ // > defined as L = 0.2126 * R + 0.7152 * G + 0.0722 * B
172
+ // where R, G, B are defined in components above.
173
+ return 0.2126 * components[0] + 0.7152 * components[1] + 0.0722 * components[2];
174
+ }
175
+ /**
176
+ * Returns the [contrast ratio](https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef)
177
+ * between `colorA` and `colorB`.
178
+ */
179
+ static contrastRatio(colorA, colorB) {
180
+ const L1 = colorA.relativeLuminance();
181
+ const L2 = colorB.relativeLuminance();
182
+ return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05);
183
+ }
141
184
  /**
142
185
  * @returns the component-wise average of `colors`, or `Color4.transparent` if `colors` is empty.
143
186
  */
@@ -223,6 +266,65 @@ class Color4 {
223
266
  const saturation = value > 0 ? chroma / value : 0;
224
267
  return Vec3.of(hue, saturation, value);
225
268
  }
269
+ /**
270
+ * Creates a new `Color4` from a representation [in $HSV$](https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB).
271
+ *
272
+ * [Algorithm](https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB).
273
+ *
274
+ * Note that hue must be given **in radians**. While non-standard, this is consistent with
275
+ * {@link asHSV}.
276
+ *
277
+ * `hue` and `value` should range from 0 to 1.
278
+ *
279
+ * @param hue $H \in [0, 2\pi]$
280
+ * @param saturation $S_V \in [0, 1]$
281
+ * @param value $V \in [0, 1]$
282
+ */
283
+ static fromHSV(hue, saturation, value) {
284
+ if (hue < 0) {
285
+ hue += Math.PI * 2;
286
+ }
287
+ hue %= Math.PI * 2;
288
+ // Clamp value and saturation to [0, 1]
289
+ value = Math.max(0, Math.min(1, value));
290
+ saturation = Math.max(0, Math.min(1, saturation));
291
+ // Formula from https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB
292
+ // Saturation can be thought of as scaled chroma. Unapply the scaling.
293
+ // See https://en.wikipedia.org/wiki/HSL_and_HSV#Saturation
294
+ const chroma = value * saturation;
295
+ // Determines which edge of the projected color cube
296
+ const huePrime = hue / (Math.PI / 3);
297
+ const secondLargestComponent = chroma * (1 - Math.abs((huePrime % 2) - 1));
298
+ let rgb;
299
+ if (huePrime < 1) {
300
+ rgb = [chroma, secondLargestComponent, 0];
301
+ }
302
+ else if (huePrime < 2) {
303
+ rgb = [secondLargestComponent, chroma, 0];
304
+ }
305
+ else if (huePrime < 3) {
306
+ rgb = [0, chroma, secondLargestComponent];
307
+ }
308
+ else if (huePrime < 4) {
309
+ rgb = [0, secondLargestComponent, chroma];
310
+ }
311
+ else if (huePrime < 5) {
312
+ rgb = [secondLargestComponent, 0, chroma];
313
+ }
314
+ else {
315
+ rgb = [chroma, 0, secondLargestComponent];
316
+ }
317
+ const adjustment = value - chroma;
318
+ return Color4.ofRGB(rgb[0] + adjustment, rgb[1] + adjustment, rgb[2] + adjustment);
319
+ }
320
+ /**
321
+ * Equivalent to `ofRGB(rgb.x, rgb.y, rgb.z)`.
322
+ *
323
+ * All components should be in the range `[0, 1]` (0 to 1 inclusive).
324
+ */
325
+ static fromRGBVector(rgb, alpha) {
326
+ return Color4.ofRGBA(rgb.x, rgb.y, rgb.z, alpha ?? 1);
327
+ }
226
328
  /**
227
329
  * @returns a hexadecimal color string representation of `this`, in the form `#rrggbbaa`.
228
330
  *
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "js-draw-math-test-imports",
3
+ "version": "0.0.1",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "js-draw-math-test-imports",
9
+ "version": "0.0.1",
10
+ "license": "MIT"
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "js-draw-math-test-imports",
3
+ "version": "0.0.1",
4
+ "description": "Test module and CommonJS imports",
5
+ "author": "Henry Heino",
6
+ "license": "MIT",
7
+ "private": true,
8
+ "type": "module",
9
+ "scripts": {
10
+ "test": "node test-imports.js && node test-require.cjs"
11
+ }
12
+ }
@@ -0,0 +1,15 @@
1
+ console.log('Testing imports...');
2
+
3
+ import { Vec2, Color4, Mat33 } from '@js-draw/math';
4
+
5
+ if (Vec2.of(1, 1).x !== 1) {
6
+ throw new Error('Failed to import module Vec2');
7
+ }
8
+
9
+ if (!Mat33.identity) {
10
+ throw new Error('Failed to import Mat33 via CommonJS');
11
+ }
12
+
13
+ if (!Color4.red) {
14
+ throw new Error('Failed to import Color4 from js-draw');
15
+ }
@@ -0,0 +1,15 @@
1
+ console.log('Testing require()...');
2
+
3
+ const { Vec2, Color4, Mat33 } = require('@js-draw/math');
4
+
5
+ if (Vec2.of(1, 1).x !== 1) {
6
+ throw new Error('Failed to import module Vec2');
7
+ }
8
+
9
+ if (!Mat33.identity) {
10
+ throw new Error('Failed to import Mat33 via CommonJS');
11
+ }
12
+
13
+ if (!Color4.red) {
14
+ throw new Error('Failed to import Color4 from js-draw');
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@js-draw/math",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "A math library for js-draw. ",
5
5
  "types": "./dist/mjs/lib.d.ts",
6
6
  "main": "./dist/cjs/lib.js",
@@ -28,7 +28,7 @@
28
28
  "bezier-js": "6.1.3"
29
29
  },
30
30
  "devDependencies": {
31
- "@js-draw/build-tool": "^1.0.0",
31
+ "@js-draw/build-tool": "^1.0.2",
32
32
  "@types/bezier-js": "4.1.0",
33
33
  "@types/jest": "29.5.3",
34
34
  "@types/jsdom": "21.1.1"
@@ -44,5 +44,6 @@
44
44
  "freehand",
45
45
  "svg",
46
46
  "math"
47
- ]
47
+ ],
48
+ "gitHead": "3e77c7d833ecdc13bcb57e905280ba547629680a"
48
49
  }
@@ -0,0 +1,94 @@
1
+ import Color4 from './Color4';
2
+ import Vec3 from './Vec3';
3
+
4
+ describe('Color4', () => {
5
+ it('should convert to #RRGGBB-format hex strings (when no alpha)', () => {
6
+ expect(Color4.black.toHexString()).toBe('#000000');
7
+ expect(Color4.fromHex('#f0f').toHexString()).toBe('#f000f0');
8
+ });
9
+
10
+ it('should create #RRGGBBAA-format hex strings when there is an alpha component', () => {
11
+ expect(Color4.ofRGBA(1, 1, 1, 0.5).toHexString()).toBe('#ffffff80');
12
+ });
13
+
14
+ it('should parse rgb and rgba-format strings', () => {
15
+ expect(Color4.fromString('rgb(0, 0, 0)')).objEq(Color4.black);
16
+ expect(Color4.fromString('rgb ( 255, 0,\t 0)')).objEq(Color4.ofRGBA(1, 0, 0, 1));
17
+ expect(Color4.fromString('rgba ( 255, 0,\t 0, 0.5)')).objEq(Color4.ofRGBA(1, 0, 0, 0.5));
18
+ expect(Color4.fromString('rgba( 0, 0, 128, 0)')).objEq(Color4.ofRGBA(0, 0, 128/255, 0));
19
+ });
20
+
21
+ it('should parse transparent/none as completely transparent', () => {
22
+ expect(Color4.fromString('none')).toBe(Color4.transparent);
23
+ expect(Color4.fromString('transparent')).toBe(Color4.transparent);
24
+ });
25
+
26
+ it('should mix blue and red to get dark purple', () => {
27
+ expect(Color4.ofRGB(1, 0, 0).mix(Color4.ofRGB(0, 0, 1), 0.5)).objEq(Color4.ofRGB(0.5, 0, 0.5));
28
+ expect(Color4.ofRGB(1, 0, 0).mix(Color4.ofRGB(0, 0, 1), 0.1)).objEq(Color4.ofRGB(0.9, 0, 0.1));
29
+ });
30
+
31
+ it('should mix red and green to get yellow', () => {
32
+ expect(Color4.ofRGB(1, 0, 0).mix(Color4.ofRGB(0, 1, 0), 0.3)).objEq(
33
+ Color4.ofRGB(0.7, 0.3, 0)
34
+ );
35
+ });
36
+
37
+ it('should mix red with nothing and get red', () => {
38
+ expect(Color4.average([ Color4.red ])).objEq(Color4.red);
39
+ });
40
+
41
+ it('different colors should be different', () => {
42
+ expect(Color4.red.eq(Color4.red)).toBe(true);
43
+ expect(Color4.red.eq(Color4.green)).toBe(false);
44
+ expect(Color4.fromString('#ff000000').eq(Color4.transparent)).toBe(true);
45
+ });
46
+
47
+ it('should correctly convert to hsv', () => {
48
+ expect(Color4.red.asHSV()).objEq(Vec3.of(0, 1, 1));
49
+ expect(Color4.ofRGB(0.5, 0.5, 0.5).asHSV()).objEq(Vec3.of(0, 0, 0.5));
50
+ expect(Color4.ofRGB(0.5, 0.25, 0.5).asHSV()).objEq(Vec3.of(Math.PI * 5 / 3, 0.5, 0.5), 0.1);
51
+ });
52
+
53
+ it('fromHSV(color.asHSV) should return the original color', () => {
54
+ const testColors = [
55
+ Color4.red, Color4.green, Color4.blue,
56
+ Color4.white, Color4.black,
57
+ ];
58
+
59
+ const testWithColor = (color: Color4) => {
60
+ expect(Color4.fromHSV(...color.asHSV().asArray())).objEq(color);
61
+ };
62
+
63
+ for (const color of testColors) {
64
+ testWithColor(color);
65
+ }
66
+
67
+ for (let i = 0; i <= 6; i++) {
68
+ testWithColor(Color4.fromHSV(i * Math.PI / 7, 0.5, 0.5));
69
+ testWithColor(Color4.fromHSV(i * Math.PI / 6, 0.5, 0.5));
70
+ }
71
+ });
72
+
73
+ it('.rgb should return a 3-component vector', () => {
74
+ expect(Color4.red.rgb).objEq(Vec3.of(1, 0, 0));
75
+ expect(Color4.green.rgb).objEq(Vec3.of(0, 1, 0));
76
+ expect(Color4.blue.rgb).objEq(Vec3.of(0, 0, 1));
77
+ });
78
+
79
+ it('should return correct contrast ratios', () => {
80
+ // Expected values from https://webaim.org/resources/contrastchecker/
81
+ const testCases: [ Color4, Color4, number ][] = [
82
+ [ Color4.white, Color4.black, 21 ],
83
+ [ Color4.fromHex('#FF0000'), Color4.black, 5.25 ],
84
+ [ Color4.fromHex('#FF0000'), Color4.fromHex('#0000FF'), 2.14 ],
85
+ [ Color4.fromHex('#300000'), Color4.fromHex('#003000'), 1.26 ],
86
+ [ Color4.fromHex('#300000'), Color4.fromHex('#003000'), 1.26 ],
87
+ [ Color4.fromHex('#D60000'), Color4.fromHex('#003000'), 2.71 ],
88
+ ];
89
+
90
+ for (const [ colorA, colorB, expectedContrast ] of testCases) {
91
+ expect(Color4.contrastRatio(colorA, colorB)).toBeCloseTo(expectedContrast, 1);
92
+ }
93
+ });
94
+ });