@genome-spy/core 0.48.1 → 0.48.2

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.
@@ -37,6 +37,10 @@ export default class Inertia {
37
37
  }
38
38
 
39
39
  cancel() {
40
+ if (this.lastValue === this.targetValue) {
41
+ return;
42
+ }
43
+
40
44
  // decelelerate rapidly
41
45
  this.targetValue = lerp([this.lastValue, this.targetValue], 0.3);
42
46
  this.smoother({ x: this.targetValue });
@@ -3,9 +3,10 @@
3
3
  *
4
4
  * Yields arrays that contain the compound key and the grouped data items.
5
5
  *
6
- * @param {Map<any, any>} map The root
6
+ * @param {Map<any, T>} map The root
7
7
  * @param {any[]} [path] The path so far.
8
- * @returns {Generator<[any[], any[]]>}
8
+ * @returns {Generator<[any[], T]>}
9
+ * @template T
9
10
  */
10
- export default function iterateNestedMaps(map: Map<any, any>, path?: any[]): Generator<[any[], any[]]>;
11
+ export default function iterateNestedMaps<T>(map: Map<any, T>, path?: any[]): Generator<[any[], T], any, any>;
11
12
  //# sourceMappingURL=iterateNestedMaps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"iterateNestedMaps.d.ts","sourceRoot":"","sources":["../../../src/utils/iterateNestedMaps.js"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,+CAJW,IAAI,GAAG,EAAE,GAAG,CAAC,SACb,GAAG,EAAE,GACH,UAAU,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAarC"}
1
+ {"version":3,"file":"iterateNestedMaps.d.ts","sourceRoot":"","sources":["../../../src/utils/iterateNestedMaps.js"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,sEAJW,GAAG,EAAE,mCAef"}
@@ -3,9 +3,10 @@
3
3
  *
4
4
  * Yields arrays that contain the compound key and the grouped data items.
5
5
  *
6
- * @param {Map<any, any>} map The root
6
+ * @param {Map<any, T>} map The root
7
7
  * @param {any[]} [path] The path so far.
8
- * @returns {Generator<[any[], any[]]>}
8
+ * @returns {Generator<[any[], T]>}
9
+ * @template T
9
10
  */
10
11
  export default function* iterateNestedMaps(map, path = []) {
11
12
  for (const [key, value] of map.entries()) {
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @param {number[]} arr An array of unsigned integers
3
+ */
4
+ export default function radixSort(arr: number[]): number[];
5
+ /**
6
+ * @param {number[]} arr An array of unsigned integers
7
+ */
8
+ export function radixSortIntoLookupArray(arr: number[]): number[];
9
+ //# sourceMappingURL=radixSort.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radixSort.d.ts","sourceRoot":"","sources":["../../../src/utils/radixSort.js"],"names":[],"mappings":"AAKA;;GAEG;AACH,uCAFW,MAAM,EAAE,YAyDlB;AAaD;;GAEG;AACH,8CAFW,MAAM,EAAE,YAoDlB"}
@@ -0,0 +1,130 @@
1
+ const MAX_INTEGER = 2147483647;
2
+ const MAX_INTEGER_DIGIT = getDigits([MAX_INTEGER]);
3
+
4
+ // TODO: Optimize more! Some ideas: https://travisdowns.github.io/blog/2019/05/22/sorting.html
5
+
6
+ /**
7
+ * @param {number[]} arr An array of unsigned integers
8
+ */
9
+ export default function radixSort(arr) {
10
+ const maxDigits = getDigits(arr);
11
+
12
+ let buffer = new Array(arr.length);
13
+ let bufferPtr = buffer;
14
+ const counts = new Array(16);
15
+
16
+ for (let digitIndex = 0; digitIndex < maxDigits; digitIndex++) {
17
+ counts.fill(0);
18
+
19
+ const shift = digitIndex * 4;
20
+ const pow = Math.pow(16, digitIndex);
21
+
22
+ /**
23
+ * @param {*} i number
24
+ */
25
+ // eslint-disable-next-line no-loop-func
26
+ const getDigit = (/** @type {number} */ i) => {
27
+ const value = arr[i];
28
+
29
+ // Need hacks for large numbers because JS bitwise operators only work
30
+ // with 32-bit integers.
31
+ // TODO: This could be implemented in WASM for better performance as
32
+ // it would be able to use 64-bit integers.
33
+ if (digitIndex >= MAX_INTEGER_DIGIT) {
34
+ if (value > MAX_INTEGER) {
35
+ return Math.floor(value / pow) % 16;
36
+ } else {
37
+ return 0;
38
+ }
39
+ } else {
40
+ return (value >> shift) & 0xf;
41
+ }
42
+ };
43
+
44
+ // Count occurrences of each digit
45
+ for (let i = 0, n = arr.length; i < n; i++) {
46
+ counts[getDigit(i)]++;
47
+ }
48
+
49
+ // Prefix sum to get starting indexes
50
+ for (let i = 1; i < 16; i++) {
51
+ counts[i] += counts[i - 1];
52
+ }
53
+
54
+ // Sort based on current digit
55
+ for (let i = arr.length - 1; i >= 0; i--) {
56
+ bufferPtr[--counts[getDigit(i)]] = arr[i];
57
+ }
58
+
59
+ // Swap buffer and arr for next iteration
60
+ [arr, bufferPtr] = [bufferPtr, arr];
61
+ }
62
+
63
+ return arr;
64
+ }
65
+
66
+ /**
67
+ * @param {number[]} arr An array of unsigned integers
68
+ */
69
+ function getDigits(arr) {
70
+ let max = 0;
71
+ for (let i = 0, n = arr.length; i < n; i++) {
72
+ max = Math.max(max, arr[i]);
73
+ }
74
+ return Math.floor(Math.log2(max) / 4) + 1;
75
+ }
76
+
77
+ /**
78
+ * @param {number[]} arr An array of unsigned integers
79
+ */
80
+ export function radixSortIntoLookupArray(arr) {
81
+ const maxDigits = getDigits(arr);
82
+ let indexes = Array.from({ length: arr.length }, (_, i) => i);
83
+ let buffer = new Array(arr.length);
84
+ const counts = new Array(16);
85
+
86
+ for (let digitIndex = 0; digitIndex < maxDigits; digitIndex++) {
87
+ counts.fill(0);
88
+
89
+ const shift = digitIndex * 4;
90
+ const pow = Math.pow(16, digitIndex);
91
+
92
+ /**
93
+ * @param {*} i number
94
+ */
95
+ // eslint-disable-next-line no-loop-func
96
+ const getDigit = (i) => {
97
+ const value = arr[indexes[i]]; // Use index to access array value
98
+
99
+ if (digitIndex >= MAX_INTEGER_DIGIT) {
100
+ if (value > MAX_INTEGER) {
101
+ return Math.floor(value / pow) % 16;
102
+ } else {
103
+ return 0;
104
+ }
105
+ } else {
106
+ return (value >> shift) & 0xf;
107
+ }
108
+ };
109
+
110
+ // Count occurrences of each digit
111
+ for (let i = 0; i < arr.length; i++) {
112
+ counts[getDigit(i)]++;
113
+ }
114
+
115
+ // Prefix sum to get starting indexes
116
+ for (let i = 1; i < 16; i++) {
117
+ counts[i] += counts[i - 1];
118
+ }
119
+
120
+ // Sort indexes based on current digit
121
+ for (let i = arr.length - 1; i >= 0; i--) {
122
+ buffer[--counts[getDigit(i)]] = indexes[i];
123
+ }
124
+
125
+ // Swap buffer and indexes for next iteration
126
+ [indexes, buffer] = [buffer, indexes];
127
+ }
128
+
129
+ return indexes; // Return the sorted index array
130
+ }
@@ -0,0 +1,51 @@
1
+ import { expect, test } from "vitest";
2
+ import radixSort, { radixSortIntoLookupArray } from "./radixSort.js";
3
+
4
+ /**
5
+ * Checks that numbers in an array are in ascending order.
6
+
7
+ * @param {number[]} arr An array of unsigned integers
8
+ */
9
+ function isSorted(arr) {
10
+ for (let i = 1; i < arr.length; i++) {
11
+ if (arr[i - 1] > arr[i]) {
12
+ return false;
13
+ }
14
+ }
15
+
16
+ return true;
17
+ }
18
+
19
+ /**
20
+ * Generates a random array of unsigned integers.
21
+ *
22
+ * @param {number} length
23
+ */
24
+ function generateArray(length) {
25
+ const arr = new Array(length);
26
+
27
+ for (let i = 0; i < length; i++) {
28
+ arr[i] = Math.floor(Math.random() * 10_000_000_000);
29
+ }
30
+
31
+ return arr;
32
+ }
33
+
34
+ test("Radix Sort correctly sorts numbers", () => {
35
+ expect(isSorted(radixSort([1, 2, 3]))).toBeTruthy();
36
+ expect(isSorted(radixSort([3, 2, 1]))).toBeTruthy();
37
+ expect(isSorted(radixSort([123, 1234567, 12, 1, 1234]))).toBeTruthy();
38
+ expect(isSorted(radixSort(generateArray(1_000_000)))).toBeTruthy();
39
+ });
40
+
41
+ test("Lookup", () => {
42
+ expect(radixSortIntoLookupArray([1, 2, 3])).toEqual([0, 1, 2]);
43
+ expect(radixSortIntoLookupArray([3, 2, 1])).toEqual([2, 1, 0]);
44
+ expect(radixSortIntoLookupArray([10000, 100, 1000, 10, 1])).toEqual([
45
+ 4, 3, 1, 2, 0,
46
+ ]);
47
+
48
+ const arr = generateArray(1_000_000);
49
+ const lookup = radixSortIntoLookupArray(arr);
50
+ expect(isSorted(arr.map((_, i) => arr[lookup[i]]))).toBeTruthy();
51
+ });
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "contributors": [],
9
9
  "license": "MIT",
10
- "version": "0.48.1",
10
+ "version": "0.48.2",
11
11
  "jsdelivr": "dist/bundle/index.js",
12
12
  "unpkg": "dist/bundle/index.js",
13
13
  "browser": "dist/bundle/index.js",
@@ -64,5 +64,5 @@
64
64
  "vega-scale": "^7.3.1",
65
65
  "vega-util": "^1.17.2"
66
66
  },
67
- "gitHead": "f2e023ce43cf18091cb81140f5be1f59887271df"
67
+ "gitHead": "f2817f82263b92e453356083f2d770b8b236f77a"
68
68
  }