@synnaxlabs/x 0.40.0 → 0.41.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/.turbo/turbo-build.log +22 -22
- package/dist/{bounds-azUOoVVR.js → bounds-DQrjn60Q.js} +83 -86
- package/dist/bounds-M-SZ3X1Z.cjs +1 -0
- package/dist/bounds.cjs +1 -1
- package/dist/bounds.js +1 -1
- package/dist/box-0YrQibkB.cjs +1 -0
- package/dist/box-Cc8IzcNo.js +205 -0
- package/dist/box.cjs +1 -1
- package/dist/box.js +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.js +235 -198
- package/dist/location-BGl5Ddds.cjs +1 -0
- package/dist/{location-BuYbIFHD.js → location-C3aeu046.js} +16 -12
- package/dist/location.cjs +1 -1
- package/dist/location.js +1 -1
- package/dist/{position-DTrNGtrm.cjs → position-Cai5-wi1.cjs} +1 -1
- package/dist/{position-DemzGvAY.js → position-DIglP1l2.js} +2 -2
- package/dist/position.cjs +1 -1
- package/dist/position.js +1 -1
- package/dist/{scale-DpJM6__6.cjs → scale-DL9VFGhL.cjs} +1 -1
- package/dist/{scale-C0EllH-1.js → scale-DQwBWnwc.js} +4 -4
- package/dist/scale.cjs +1 -1
- package/dist/scale.js +1 -1
- package/dist/series-BMma2b5q.cjs +11 -0
- package/dist/{series-CXnO-P0V.js → series-D0zxMWxP.js} +285 -297
- package/dist/spatial.cjs +1 -1
- package/dist/spatial.js +6 -6
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/math/external.d.ts +3 -0
- package/dist/src/math/external.d.ts.map +1 -0
- package/dist/src/math/index.d.ts +1 -1
- package/dist/src/math/index.d.ts.map +1 -1
- package/dist/src/math/round.d.ts +40 -0
- package/dist/src/math/round.d.ts.map +1 -0
- package/dist/src/math/round.spec.d.ts +2 -0
- package/dist/src/math/round.spec.d.ts.map +1 -0
- package/dist/src/notation/index.d.ts +2 -0
- package/dist/src/notation/index.d.ts.map +1 -0
- package/dist/src/notation/notation.d.ts +33 -0
- package/dist/src/notation/notation.d.ts.map +1 -0
- package/dist/src/notation/notation.spec.d.ts +2 -0
- package/dist/src/notation/notation.spec.d.ts.map +1 -0
- package/dist/src/spatial/box/box.d.ts +4 -0
- package/dist/src/spatial/box/box.d.ts.map +1 -1
- package/dist/src/spatial/location/location.d.ts +2 -2
- package/dist/src/spatial/xy/xy.d.ts +10 -0
- package/dist/src/spatial/xy/xy.d.ts.map +1 -1
- package/dist/src/telem/series.d.ts.map +1 -1
- package/dist/src/telem/telem.d.ts +2 -0
- package/dist/src/telem/telem.d.ts.map +1 -1
- package/dist/telem.cjs +1 -1
- package/dist/telem.js +1 -1
- package/dist/{xy-DyQSETQZ.cjs → xy-B7065J2S.cjs} +1 -1
- package/dist/{xy-DHBO1dG_.js → xy-D_LqxaGt.js} +8 -4
- package/dist/xy.cjs +1 -1
- package/dist/xy.js +1 -1
- package/package.json +8 -8
- package/src/index.ts +1 -0
- package/src/math/external.ts +11 -0
- package/src/math/index.ts +1 -1
- package/src/math/round.spec.ts +81 -0
- package/src/math/round.ts +68 -0
- package/src/notation/index.ts +10 -0
- package/src/notation/notation.spec.ts +88 -0
- package/src/notation/notation.ts +61 -0
- package/src/spatial/box/box.spec.ts +3 -3
- package/src/spatial/box/box.ts +8 -0
- package/src/spatial/location/location.ts +4 -4
- package/src/spatial/position/position.spec.ts +10 -10
- package/src/spatial/xy/xy.spec.ts +8 -0
- package/src/spatial/xy/xy.ts +14 -0
- package/src/telem/series.spec.ts +39 -0
- package/src/telem/series.ts +15 -27
- package/src/telem/telem.ts +8 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/bounds-Dwq6ZFHm.cjs +0 -1
- package/dist/box-Bzya27QS.cjs +0 -1
- package/dist/box-DrsrRNSe.js +0 -201
- package/dist/location-BgpQ3rN2.cjs +0 -1
- package/dist/series-BgoCtU71.cjs +0 -11
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { bounds } from "@/spatial/bounds";
|
|
11
|
+
|
|
12
|
+
const LARGE_SPAN_DECIMAL_PLACES = 2;
|
|
13
|
+
const MEDIUM_SPAN_DECIMAL_PLACES = 3;
|
|
14
|
+
|
|
15
|
+
// The number of additional decimal places to show past the precision of the span.
|
|
16
|
+
const EXTRA_DECIMAL_PLACES = 2;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Rounds a number based on the span of the provided bounds. The function adjusts the
|
|
20
|
+
* number of decimal places based on the magnitude of the bounds.
|
|
21
|
+
*
|
|
22
|
+
* @param value - The number to be rounded.
|
|
23
|
+
* @param bounds - The bounds object containing the min and max values that provide
|
|
24
|
+
* context for rounding.
|
|
25
|
+
* @returns The rounded number.
|
|
26
|
+
*
|
|
27
|
+
* Rules for decimal places:
|
|
28
|
+
* - For spans >= 1000: 2 decimal places
|
|
29
|
+
* - For spans >= 1: 3 decimal places
|
|
30
|
+
* - For spans < 1: 2 decimal places + 2 decimal places past the precision of the span
|
|
31
|
+
*
|
|
32
|
+
* Edge cases:
|
|
33
|
+
* - If the value is `NaN`, returns `NaN`
|
|
34
|
+
* - If the value is `Infinity` or `-Infinity`, returns the original value
|
|
35
|
+
* - If the bounds span is 0, returns the original value
|
|
36
|
+
*
|
|
37
|
+
* Examples:
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // Large spans (>= 1000) use 2 decimal places
|
|
40
|
+
* roundBySpan(1234.5678, { start: 0, end: 2000 }); // 1200
|
|
41
|
+
*
|
|
42
|
+
* // Medium spans (>= 1) use 3 decimal places
|
|
43
|
+
* roundBySpan(1.23456, { start: 0, end: 2 }); // 1.235
|
|
44
|
+
*
|
|
45
|
+
* // Small spans (< 1) adapt based on the span
|
|
46
|
+
* roundBySpan(0.123456, { start: 0, end: 0.2 }); // 0.123 = 1 + 2 decimal places
|
|
47
|
+
* roundBySpan(0.0001234, { start: 0, end: 0.001 }); // 0.00012 = 3 + 2 decimal places
|
|
48
|
+
*
|
|
49
|
+
* // Edge cases
|
|
50
|
+
* roundBySpan(NaN, { start: 0, end: 1 }); // NaN
|
|
51
|
+
* roundBySpan(Infinity, { start: 0, end: 1 }); // Infinity
|
|
52
|
+
* roundBySpan(123, { start: 1, end: 1 }); // 123 (span is 0)
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const roundBySpan = (value: number, b: bounds.Bounds<number>): number => {
|
|
56
|
+
if (Number.isNaN(value) || !Number.isFinite(value)) return value;
|
|
57
|
+
const span = bounds.span(b);
|
|
58
|
+
if (span == 0) return value;
|
|
59
|
+
let decimalPlaces: number;
|
|
60
|
+
if (span >= 1000) decimalPlaces = LARGE_SPAN_DECIMAL_PLACES;
|
|
61
|
+
else if (span >= 1) decimalPlaces = MEDIUM_SPAN_DECIMAL_PLACES;
|
|
62
|
+
else {
|
|
63
|
+
const decimalPlacesInSpan = Math.ceil(-Math.log10(span));
|
|
64
|
+
decimalPlaces = decimalPlacesInSpan + EXTRA_DECIMAL_PLACES;
|
|
65
|
+
}
|
|
66
|
+
const multiplier = 10 ** decimalPlaces;
|
|
67
|
+
return Math.round(value * multiplier) / multiplier;
|
|
68
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
export * as notation from "@/notation/notation";
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
|
|
12
|
+
import { notation } from "@/notation";
|
|
13
|
+
|
|
14
|
+
interface TestCase {
|
|
15
|
+
number: number;
|
|
16
|
+
precision: number;
|
|
17
|
+
expected: Record<notation.Notation, string>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const TEST_CASES: TestCase[] = [
|
|
21
|
+
{
|
|
22
|
+
number: 12345.678,
|
|
23
|
+
precision: 1,
|
|
24
|
+
expected: { standard: "12345.7", scientific: "1.2ᴇ4", engineering: "12.3ᴇ3" },
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
number: 12345.678,
|
|
28
|
+
precision: 0,
|
|
29
|
+
expected: { standard: "12346", scientific: "1ᴇ4", engineering: "12ᴇ3" },
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
number: 0,
|
|
33
|
+
precision: 1,
|
|
34
|
+
expected: { standard: "0.0", scientific: "0.0ᴇ0", engineering: "0.0ᴇ0" },
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
number: 0,
|
|
38
|
+
precision: 0,
|
|
39
|
+
expected: { standard: "0", scientific: "0ᴇ0", engineering: "0ᴇ0" },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
number: -1234.5678,
|
|
43
|
+
precision: 1,
|
|
44
|
+
expected: { standard: "-1234.6", scientific: "-1.2ᴇ3", engineering: "-1.2ᴇ3" },
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
number: -1234.5678,
|
|
48
|
+
precision: 0,
|
|
49
|
+
expected: { standard: "-1235", scientific: "-1ᴇ3", engineering: "-1ᴇ3" },
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
number: NaN,
|
|
53
|
+
precision: 0,
|
|
54
|
+
expected: { standard: "NaN", scientific: "NaN", engineering: "NaN" },
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
number: Infinity,
|
|
58
|
+
precision: 0,
|
|
59
|
+
expected: { standard: "∞", scientific: "∞", engineering: "∞" },
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
number: -Infinity,
|
|
63
|
+
precision: 0,
|
|
64
|
+
expected: { standard: "-∞", scientific: "-∞", engineering: "-∞" },
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
number: 0.0001234,
|
|
68
|
+
precision: 1,
|
|
69
|
+
expected: { standard: "0.0", scientific: "1.2ᴇ-4", engineering: "123.4ᴇ-6" },
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
number: 0.0001234,
|
|
73
|
+
precision: 0,
|
|
74
|
+
expected: { standard: "0", scientific: "1ᴇ-4", engineering: "123ᴇ-6" },
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
describe("stringifyNumber", () => {
|
|
79
|
+
TEST_CASES.forEach(({ number, precision, expected }) =>
|
|
80
|
+
describe(`number: ${number}, precision: ${precision}`, () =>
|
|
81
|
+
notation.NOTATIONS.forEach((n) =>
|
|
82
|
+
it(`should format correctly in ${n} notation`, () => {
|
|
83
|
+
const result = notation.stringifyNumber(number, precision, n);
|
|
84
|
+
expect(result).toBe(expected[n]);
|
|
85
|
+
}),
|
|
86
|
+
)),
|
|
87
|
+
);
|
|
88
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Copyright 2025 Synnax Labs, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Use of this software is governed by the Business Source License included in the file
|
|
4
|
+
// licenses/BSL.txt.
|
|
5
|
+
//
|
|
6
|
+
// As of the Change Date specified in that file, in accordance with the Business Source
|
|
7
|
+
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
|
+
// included in the file licenses/APL.txt.
|
|
9
|
+
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
export const NOTATIONS = ["standard", "scientific", "engineering"] as const;
|
|
13
|
+
export const notationZ = z.enum(NOTATIONS);
|
|
14
|
+
export type Notation = z.infer<typeof notationZ>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Converts a number to a string representation with a specified precision and notation.
|
|
18
|
+
*
|
|
19
|
+
* @param value - The number to be converted.
|
|
20
|
+
* @param precision - The number of decimal places to include in the output. Must be between 0 and 20.
|
|
21
|
+
* @param notation - The notation to use for the conversion. Can be "standard", "scientific", or "engineering".
|
|
22
|
+
* @returns The string representation of the number.
|
|
23
|
+
*
|
|
24
|
+
* Edge cases:
|
|
25
|
+
* - If the value is `NaN`, returns "NaN".
|
|
26
|
+
* - If the value is `Infinity`, returns "∞".
|
|
27
|
+
* - If the value is `-Infinity`, returns "-∞".
|
|
28
|
+
*
|
|
29
|
+
* Examples:
|
|
30
|
+
*
|
|
31
|
+
* ```typescript
|
|
32
|
+
* stringifyNumber(1234.5678, 2, "standard"); // "1234.57"
|
|
33
|
+
* stringifyNumber(1234.5678, 2, "scientific"); // "1.23ᴇ3"
|
|
34
|
+
* stringifyNumber(1234.5678, 2, "engineering"); // "1.23ᴇ3"
|
|
35
|
+
* stringifyNumber(0.0001234, 4, "standard"); // "0.0001"
|
|
36
|
+
* stringifyNumber(0.0001234, 4, "scientific"); // "1.2340ᴇ-4"
|
|
37
|
+
* stringifyNumber(0.0001234, 4, "engineering"); // "123.4000ᴇ-6"
|
|
38
|
+
* stringifyNumber(NaN, 2, "standard"); // "NaN"
|
|
39
|
+
* stringifyNumber(Infinity, 2, "standard"); // "∞"
|
|
40
|
+
* stringifyNumber(-Infinity, 2, "standard"); // "-∞"
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export const stringifyNumber = (
|
|
44
|
+
value: number,
|
|
45
|
+
precision: number,
|
|
46
|
+
notation: Notation,
|
|
47
|
+
): string => {
|
|
48
|
+
if (Number.isNaN(value)) return "NaN";
|
|
49
|
+
if (value === Infinity) return "∞";
|
|
50
|
+
if (value === -Infinity) return "-∞";
|
|
51
|
+
if (notation === "standard") return value.toFixed(precision);
|
|
52
|
+
if (value === 0) {
|
|
53
|
+
if (precision === 0) return "0ᴇ0";
|
|
54
|
+
return `0.${"0".repeat(precision)}ᴇ0`;
|
|
55
|
+
}
|
|
56
|
+
let exp: number;
|
|
57
|
+
if (notation === "scientific") exp = Math.floor(Math.log10(Math.abs(value)));
|
|
58
|
+
else exp = Math.floor(Math.log10(Math.abs(value)) / 3) * 3;
|
|
59
|
+
const mantissa = value / 10 ** exp;
|
|
60
|
+
return `${mantissa.toFixed(precision)}ᴇ${exp}`;
|
|
61
|
+
};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
import { describe, expect, it,test } from "vitest";
|
|
10
|
+
import { describe, expect, it, test } from "vitest";
|
|
11
11
|
|
|
12
12
|
import * as box from "@/spatial/box/box";
|
|
13
13
|
import * as location from "@/spatial/location/location";
|
|
@@ -102,8 +102,8 @@ describe("Box", () => {
|
|
|
102
102
|
describe("xyLoc", () => {
|
|
103
103
|
const v: location.XY[] = [
|
|
104
104
|
location.BOTTOM_CENTER,
|
|
105
|
-
location.
|
|
106
|
-
location.
|
|
105
|
+
location.CENTER_LEFT,
|
|
106
|
+
location.CENTER_RIGHT,
|
|
107
107
|
location.TOP_CENTER,
|
|
108
108
|
location.BOTTOM_LEFT,
|
|
109
109
|
location.BOTTOM_RIGHT,
|
package/src/spatial/box/box.ts
CHANGED
|
@@ -278,12 +278,20 @@ export const signedHeight = (b: Crude): number => {
|
|
|
278
278
|
|
|
279
279
|
export const topLeft = (b: Crude): xy.XY => xyLoc(b, location.TOP_LEFT);
|
|
280
280
|
|
|
281
|
+
export const topCenter = (b: Crude): xy.XY => xyLoc(b, location.TOP_CENTER);
|
|
282
|
+
|
|
281
283
|
export const topRight = (b: Crude): xy.XY => xyLoc(b, location.TOP_RIGHT);
|
|
282
284
|
|
|
283
285
|
export const bottomLeft = (b: Crude): xy.XY => xyLoc(b, location.BOTTOM_LEFT);
|
|
284
286
|
|
|
287
|
+
export const bottomCenter = (b: Crude): xy.XY => xyLoc(b, location.BOTTOM_CENTER);
|
|
288
|
+
|
|
285
289
|
export const bottomRight = (b: Crude): xy.XY => xyLoc(b, location.BOTTOM_RIGHT);
|
|
286
290
|
|
|
291
|
+
export const centerLeft = (b: Crude): xy.XY => xyLoc(b, location.CENTER_LEFT);
|
|
292
|
+
|
|
293
|
+
export const centerRight = (b: Crude): xy.XY => xyLoc(b, location.CENTER_RIGHT);
|
|
294
|
+
|
|
287
295
|
export const right = (b: Crude): number => loc(b, "right");
|
|
288
296
|
|
|
289
297
|
export const bottom = (b: Crude): number => loc(b, "bottom");
|
|
@@ -102,11 +102,11 @@ export const BOTTOM_RIGHT: CornerXY = Object.freeze({ x: "right", y: "bottom" })
|
|
|
102
102
|
export const CENTER: XY = Object.freeze({ x: "center", y: "center" });
|
|
103
103
|
export const TOP_CENTER: XY = Object.freeze({ x: "center", y: "top" });
|
|
104
104
|
export const BOTTOM_CENTER: XY = Object.freeze({ x: "center", y: "bottom" });
|
|
105
|
-
export const
|
|
106
|
-
export const
|
|
105
|
+
export const CENTER_RIGHT: XY = Object.freeze({ x: "right", y: "center" });
|
|
106
|
+
export const CENTER_LEFT: XY = Object.freeze({ x: "left", y: "center" });
|
|
107
107
|
export const XY_LOCATIONS: readonly XY[] = Object.freeze([
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
CENTER_LEFT,
|
|
109
|
+
CENTER_RIGHT,
|
|
110
110
|
TOP_CENTER,
|
|
111
111
|
BOTTOM_CENTER,
|
|
112
112
|
TOP_LEFT,
|
|
@@ -24,7 +24,7 @@ describe("position", () => {
|
|
|
24
24
|
target: box.construct(45, 55, 10, 10),
|
|
25
25
|
dialog: box.construct(0, 0, 20, 20),
|
|
26
26
|
},
|
|
27
|
-
location.
|
|
27
|
+
location.CENTER_LEFT,
|
|
28
28
|
];
|
|
29
29
|
|
|
30
30
|
const SPEC_CASE_2: Spec = [
|
|
@@ -54,7 +54,7 @@ describe("position", () => {
|
|
|
54
54
|
dialog: box.construct(0, 0, 20, 20),
|
|
55
55
|
initial: "left",
|
|
56
56
|
},
|
|
57
|
-
location.
|
|
57
|
+
location.CENTER_LEFT,
|
|
58
58
|
];
|
|
59
59
|
|
|
60
60
|
const SPEC_CASE_5: Spec = [
|
|
@@ -64,7 +64,7 @@ describe("position", () => {
|
|
|
64
64
|
dialog: box.construct(0, 0, 20, 20),
|
|
65
65
|
initial: "right",
|
|
66
66
|
},
|
|
67
|
-
location.
|
|
67
|
+
location.CENTER_RIGHT,
|
|
68
68
|
];
|
|
69
69
|
|
|
70
70
|
// Target is in bottom right corner
|
|
@@ -74,7 +74,7 @@ describe("position", () => {
|
|
|
74
74
|
target: box.construct(90, 90, 10, 10),
|
|
75
75
|
dialog: box.construct(0, 0, 20, 20),
|
|
76
76
|
},
|
|
77
|
-
location.
|
|
77
|
+
location.CENTER_LEFT,
|
|
78
78
|
];
|
|
79
79
|
|
|
80
80
|
// Target is in the top left corner
|
|
@@ -186,12 +186,12 @@ describe("position", () => {
|
|
|
186
186
|
[location.TOP_CENTER, "start", location.BOTTOM_LEFT],
|
|
187
187
|
[location.TOP_CENTER, "center", location.BOTTOM_CENTER],
|
|
188
188
|
[location.TOP_CENTER, "end", location.BOTTOM_RIGHT],
|
|
189
|
-
[location.
|
|
190
|
-
[location.
|
|
191
|
-
[location.
|
|
192
|
-
[location.
|
|
193
|
-
[location.
|
|
194
|
-
[location.
|
|
189
|
+
[location.CENTER_LEFT, "start", location.BOTTOM_RIGHT],
|
|
190
|
+
[location.CENTER_LEFT, "center", location.CENTER_RIGHT],
|
|
191
|
+
[location.CENTER_LEFT, "end", location.TOP_RIGHT],
|
|
192
|
+
[location.CENTER_RIGHT, "start", location.BOTTOM_LEFT],
|
|
193
|
+
[location.CENTER_RIGHT, "center", location.CENTER_LEFT],
|
|
194
|
+
[location.CENTER_RIGHT, "end", location.TOP_LEFT],
|
|
195
195
|
[location.BOTTOM_LEFT, "start", location.TOP_RIGHT],
|
|
196
196
|
[location.BOTTOM_LEFT, "center", location.TOP_CENTER],
|
|
197
197
|
[location.BOTTOM_LEFT, "end", location.TOP_LEFT],
|
|
@@ -143,4 +143,12 @@ describe("XY", () => {
|
|
|
143
143
|
]);
|
|
144
144
|
});
|
|
145
145
|
});
|
|
146
|
+
|
|
147
|
+
describe("swap", () => {
|
|
148
|
+
it("should swap x and y coordinates", () => {
|
|
149
|
+
expect(xy.swap([1, 2])).toEqual({ x: 2, y: 1 });
|
|
150
|
+
expect(xy.swap({ x: 3, y: 4 })).toEqual({ x: 4, y: 3 });
|
|
151
|
+
expect(xy.swap({ width: 5, height: 6 })).toEqual({ x: 6, y: 5 });
|
|
152
|
+
});
|
|
153
|
+
});
|
|
146
154
|
});
|
package/src/spatial/xy/xy.ts
CHANGED
|
@@ -279,3 +279,17 @@ export const calculateMiters = (path: XY[], offset: number): XY[] => {
|
|
|
279
279
|
}
|
|
280
280
|
return miters;
|
|
281
281
|
};
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Swaps the x and y coordinates of a point.
|
|
285
|
+
* @param a - The coordinate to swap. Can be provided in any supported format (couple, object, dimensions, etc.)
|
|
286
|
+
* @returns A new XY coordinate with the x and y values swapped.
|
|
287
|
+
* @example
|
|
288
|
+
* swap([1, 2]) // returns { x: 2, y: 1 }
|
|
289
|
+
* swap({ x: 3, y: 4 }) // returns { x: 4, y: 3 }
|
|
290
|
+
* swap({ width: 5, height: 6 }) // returns { x: 6, y: 5 }
|
|
291
|
+
*/
|
|
292
|
+
export const swap = (a: Crude): XY => {
|
|
293
|
+
const xy = construct(a);
|
|
294
|
+
return { x: xy.y, y: xy.x };
|
|
295
|
+
};
|
package/src/telem/series.spec.ts
CHANGED
|
@@ -1064,4 +1064,43 @@ describe("MultiSeries", () => {
|
|
|
1064
1064
|
expect(multi.timeRange).toEqual(new TimeRange(1, 4));
|
|
1065
1065
|
});
|
|
1066
1066
|
});
|
|
1067
|
+
|
|
1068
|
+
describe("as", () => {
|
|
1069
|
+
it("should correctly cast a numeric series to number type", () => {
|
|
1070
|
+
const a = new Series(new Float32Array([1, 2, 3]));
|
|
1071
|
+
const b = new Series(new Float32Array([4, 5, 6]));
|
|
1072
|
+
const multi = new MultiSeries([a, b]);
|
|
1073
|
+
const asNum = multi.as("number");
|
|
1074
|
+
expect(asNum.at(0)).toEqual(1);
|
|
1075
|
+
expect(asNum.at(5)).toEqual(6);
|
|
1076
|
+
expect(Array.from(asNum)).toEqual([1, 2, 3, 4, 5, 6]);
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
it("should correctly cast a string series to string type", () => {
|
|
1080
|
+
const a = new Series(["apple", "banana"]);
|
|
1081
|
+
const b = new Series(["carrot", "date"]);
|
|
1082
|
+
const multi = new MultiSeries([a, b]);
|
|
1083
|
+
const asStr = multi.as("string");
|
|
1084
|
+
expect(asStr.at(0)).toEqual("apple");
|
|
1085
|
+
expect(asStr.at(3)).toEqual("date");
|
|
1086
|
+
expect(Array.from(asStr)).toEqual(["apple", "banana", "carrot", "date"]);
|
|
1087
|
+
});
|
|
1088
|
+
|
|
1089
|
+
it("should correctly cast a bigint series to bigint type", () => {
|
|
1090
|
+
const a = new Series([1n, 2n]);
|
|
1091
|
+
const b = new Series([3n, 4n]);
|
|
1092
|
+
const multi = new MultiSeries([a, b]);
|
|
1093
|
+
const asBigInt = multi.as("bigint");
|
|
1094
|
+
expect(asBigInt.at(0)).toEqual(1n);
|
|
1095
|
+
expect(asBigInt.at(3)).toEqual(4n);
|
|
1096
|
+
expect(Array.from(asBigInt)).toEqual([1n, 2n, 3n, 4n]);
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
it("should throw an error when trying to cast to an incompatible type", () => {
|
|
1100
|
+
const a = new Series(new Float32Array([1, 2, 3]));
|
|
1101
|
+
const b = new Series(new Float32Array([4, 5, 6]));
|
|
1102
|
+
const multi = new MultiSeries([a, b]);
|
|
1103
|
+
expect(() => multi.as("string")).toThrow();
|
|
1104
|
+
});
|
|
1105
|
+
});
|
|
1067
1106
|
});
|
package/src/telem/series.ts
CHANGED
|
@@ -126,6 +126,17 @@ const nullArrayZ = z
|
|
|
126
126
|
|
|
127
127
|
const NEW_LINE = 10;
|
|
128
128
|
|
|
129
|
+
type JSType = "string" | "number" | "bigint";
|
|
130
|
+
|
|
131
|
+
const checkAsType = (jsType: JSType, dataType: DataType) => {
|
|
132
|
+
if (jsType === "string" && !dataType.isVariable)
|
|
133
|
+
throw new Error(`cannot convert series of type ${dataType.toString()} to string`);
|
|
134
|
+
if (jsType === "number" && !dataType.isNumeric)
|
|
135
|
+
throw new Error(`cannot convert series of type ${dataType.toString()} to number`);
|
|
136
|
+
if (jsType === "bigint" && !dataType.usesBigInt)
|
|
137
|
+
throw new Error(`cannot convert series of type ${dataType.toString()} to bigint`);
|
|
138
|
+
};
|
|
139
|
+
|
|
129
140
|
/**
|
|
130
141
|
* Series is a strongly typed array of telemetry samples backed by an underlying binary
|
|
131
142
|
* buffer.
|
|
@@ -696,28 +707,8 @@ export class Series<T extends TelemValue = TelemValue> {
|
|
|
696
707
|
as(jsType: "bigint"): Series<bigint>;
|
|
697
708
|
|
|
698
709
|
as<T extends TelemValue>(jsType: "string" | "number" | "bigint"): Series<T> {
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
throw new Error(
|
|
702
|
-
`cannot convert series of type ${this.dataType.toString()} to string`,
|
|
703
|
-
);
|
|
704
|
-
return this as unknown as Series<T>;
|
|
705
|
-
}
|
|
706
|
-
if (jsType === "number") {
|
|
707
|
-
if (!this.dataType.isNumeric)
|
|
708
|
-
throw new Error(
|
|
709
|
-
`cannot convert series of type ${this.dataType.toString()} to number`,
|
|
710
|
-
);
|
|
711
|
-
return this as unknown as Series<T>;
|
|
712
|
-
}
|
|
713
|
-
if (jsType === "bigint") {
|
|
714
|
-
if (!this.dataType.equals(DataType.INT64))
|
|
715
|
-
throw new Error(
|
|
716
|
-
`cannot convert series of type ${this.dataType.toString()} to bigint`,
|
|
717
|
-
);
|
|
718
|
-
return this as unknown as Series<T>;
|
|
719
|
-
}
|
|
720
|
-
throw new Error(`cannot convert series to ${jsType as string}`);
|
|
710
|
+
checkAsType(jsType, this.dataType);
|
|
711
|
+
return this as unknown as Series<T>;
|
|
721
712
|
}
|
|
722
713
|
|
|
723
714
|
get digest(): SeriesDigest {
|
|
@@ -950,11 +941,8 @@ export class MultiSeries<T extends TelemValue = TelemValue> implements Iterable<
|
|
|
950
941
|
|
|
951
942
|
as(jsType: "bigint"): MultiSeries<bigint>;
|
|
952
943
|
|
|
953
|
-
as<T extends TelemValue>(
|
|
954
|
-
|
|
955
|
-
throw new Error(
|
|
956
|
-
`cannot convert series of type ${this.dataType.toString()} to ${dataType.toString()}`,
|
|
957
|
-
);
|
|
944
|
+
as<T extends TelemValue>(jsType: "string" | "number" | "bigint"): MultiSeries<T> {
|
|
945
|
+
checkAsType(jsType, this.dataType);
|
|
958
946
|
return this as unknown as MultiSeries<T>;
|
|
959
947
|
}
|
|
960
948
|
|
package/src/telem/telem.ts
CHANGED
|
@@ -360,6 +360,14 @@ export class TimeStamp implements Stringer {
|
|
|
360
360
|
return Number(this.valueOf()) / Number(TimeStamp.MILLISECOND.valueOf());
|
|
361
361
|
}
|
|
362
362
|
|
|
363
|
+
get microseconds(): number {
|
|
364
|
+
return Number(this.valueOf()) / Number(TimeStamp.MICROSECOND.valueOf());
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
get nanoseconds(): number {
|
|
368
|
+
return Number(this.valueOf());
|
|
369
|
+
}
|
|
370
|
+
|
|
363
371
|
/** @returns the integer year that the timestamp corresponds to. */
|
|
364
372
|
get year(): number {
|
|
365
373
|
return this.date().getFullYear();
|