@genome-spy/core 0.71.0 → 0.73.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.
Files changed (121) hide show
  1. package/LICENSE +1 -1
  2. package/dist/bundle/index.es.js +6842 -5365
  3. package/dist/bundle/index.js +159 -140
  4. package/dist/bundle/parquetRead-BnAGCa4_.js +1663 -0
  5. package/dist/schema.json +281 -17
  6. package/dist/src/data/formats/bed.d.ts +8 -0
  7. package/dist/src/data/formats/bed.d.ts.map +1 -0
  8. package/dist/src/data/formats/bed.js +53 -0
  9. package/dist/src/data/formats/bedpe.d.ts +8 -0
  10. package/dist/src/data/formats/bedpe.d.ts.map +1 -0
  11. package/dist/src/data/formats/bedpe.js +160 -0
  12. package/dist/src/data/formats/parquet.d.ts +12 -0
  13. package/dist/src/data/formats/parquet.d.ts.map +1 -0
  14. package/dist/src/data/formats/parquet.js +29 -0
  15. package/dist/src/data/formats/parquetRead.d.ts +18 -0
  16. package/dist/src/data/formats/parquetRead.d.ts.map +1 -0
  17. package/dist/src/data/formats/parquetRead.js +326 -0
  18. package/dist/src/data/sources/dataUtils.d.ts +16 -0
  19. package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
  20. package/dist/src/data/sources/dataUtils.js +53 -3
  21. package/dist/src/data/sources/urlSource.d.ts +4 -0
  22. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  23. package/dist/src/data/sources/urlSource.js +141 -17
  24. package/dist/src/encoder/encoder.d.ts +2 -2
  25. package/dist/src/fonts/bmFontManager.d.ts +1 -1
  26. package/dist/src/genome/assemblyPreflight.d.ts +31 -0
  27. package/dist/src/genome/assemblyPreflight.d.ts.map +1 -0
  28. package/dist/src/genome/assemblyPreflight.js +99 -0
  29. package/dist/src/genome/genome.d.ts +2 -2
  30. package/dist/src/genome/genome.d.ts.map +1 -1
  31. package/dist/src/genome/genome.js +4 -0
  32. package/dist/src/genome/genomeStore.d.ts +34 -3
  33. package/dist/src/genome/genomeStore.d.ts.map +1 -1
  34. package/dist/src/genome/genomeStore.js +409 -18
  35. package/dist/src/genome/rootGenomeConfig.d.ts +26 -0
  36. package/dist/src/genome/rootGenomeConfig.d.ts.map +1 -0
  37. package/dist/src/genome/rootGenomeConfig.js +94 -0
  38. package/dist/src/genomeSpy/interactionController.d.ts +5 -1
  39. package/dist/src/genomeSpy/interactionController.d.ts.map +1 -1
  40. package/dist/src/genomeSpy/interactionController.js +244 -29
  41. package/dist/src/genomeSpy/renderCoordinator.js +1 -1
  42. package/dist/src/genomeSpy.d.ts +13 -3
  43. package/dist/src/genomeSpy.d.ts.map +1 -1
  44. package/dist/src/genomeSpy.js +83 -7
  45. package/dist/src/gl/canvasSizeHelper.d.ts +74 -0
  46. package/dist/src/gl/canvasSizeHelper.d.ts.map +1 -0
  47. package/dist/src/gl/canvasSizeHelper.js +203 -0
  48. package/dist/src/gl/hashTable.d.ts +78 -0
  49. package/dist/src/gl/hashTable.d.ts.map +1 -0
  50. package/dist/src/gl/hashTable.js +164 -0
  51. package/dist/src/gl/includes/common.glsl.js +1 -1
  52. package/dist/src/gl/webGLHelper.d.ts +25 -11
  53. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  54. package/dist/src/gl/webGLHelper.js +71 -39
  55. package/dist/src/index.d.ts.map +1 -1
  56. package/dist/src/index.js +5 -2
  57. package/dist/src/marks/link.d.ts.map +1 -1
  58. package/dist/src/marks/link.js +5 -3
  59. package/dist/src/marks/mark.d.ts +1 -1
  60. package/dist/src/marks/mark.d.ts.map +1 -1
  61. package/dist/src/marks/mark.js +8 -4
  62. package/dist/src/scales/domainPlanner.d.ts +34 -3
  63. package/dist/src/scales/domainPlanner.d.ts.map +1 -1
  64. package/dist/src/scales/domainPlanner.js +247 -26
  65. package/dist/src/scales/scaleInstanceManager.d.ts +2 -1
  66. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
  67. package/dist/src/scales/scaleInstanceManager.js +10 -11
  68. package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
  69. package/dist/src/scales/scaleInteractionController.js +16 -14
  70. package/dist/src/scales/scaleResolution.d.ts +16 -0
  71. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  72. package/dist/src/scales/scaleResolution.js +314 -54
  73. package/dist/src/scales/scaleResolutionTestUtils.d.ts +21 -0
  74. package/dist/src/scales/scaleResolutionTestUtils.d.ts.map +1 -0
  75. package/dist/src/scales/scaleResolutionTestUtils.js +33 -0
  76. package/dist/src/scales/selectionDomainUtils.d.ts +22 -0
  77. package/dist/src/scales/selectionDomainUtils.d.ts.map +1 -0
  78. package/dist/src/scales/selectionDomainUtils.js +79 -0
  79. package/dist/src/scales/zoomDomainUtils.d.ts +18 -0
  80. package/dist/src/scales/zoomDomainUtils.d.ts.map +1 -0
  81. package/dist/src/scales/zoomDomainUtils.js +69 -0
  82. package/dist/src/screenshotHarness.d.ts +16 -0
  83. package/dist/src/screenshotHarness.d.ts.map +1 -0
  84. package/dist/src/screenshotHarness.js +242 -0
  85. package/dist/src/singlePageApp.js +1 -1
  86. package/dist/src/spec/data.d.ts +23 -3
  87. package/dist/src/spec/genome.d.ts +22 -2
  88. package/dist/src/spec/parameter.d.ts +39 -2
  89. package/dist/src/spec/root.d.ts +20 -1
  90. package/dist/src/spec/scale.d.ts +41 -5
  91. package/dist/src/styles/genome-spy.css +8 -0
  92. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  93. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  94. package/dist/src/styles/genome-spy.css.js +8 -0
  95. package/dist/src/tooltip/dataTooltipHandler.js +59 -10
  96. package/dist/src/types/embedApi.d.ts +19 -0
  97. package/dist/src/utils/inferSpecBaseUrl.d.ts +14 -0
  98. package/dist/src/utils/inferSpecBaseUrl.d.ts.map +1 -0
  99. package/dist/src/utils/inferSpecBaseUrl.js +73 -0
  100. package/dist/src/utils/interactionEvent.d.ts +53 -3
  101. package/dist/src/utils/interactionEvent.d.ts.map +1 -1
  102. package/dist/src/utils/interactionEvent.js +62 -1
  103. package/dist/src/utils/radixSort.d.ts.map +1 -1
  104. package/dist/src/utils/radixSort.js +26 -1
  105. package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
  106. package/dist/src/view/containerMutationHelper.js +8 -0
  107. package/dist/src/view/dataReadiness.d.ts +2 -2
  108. package/dist/src/view/dataReadiness.d.ts.map +1 -1
  109. package/dist/src/view/dataReadiness.js +63 -58
  110. package/dist/src/view/facetView.d.ts +1 -1
  111. package/dist/src/view/facetView.js +1 -1
  112. package/dist/src/view/gridView/gridChild.d.ts +7 -0
  113. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  114. package/dist/src/view/gridView/gridChild.js +180 -11
  115. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  116. package/dist/src/view/gridView/gridView.js +60 -17
  117. package/dist/src/view/unitView.d.ts +1 -1
  118. package/dist/src/view/zoom.d.ts +14 -2
  119. package/dist/src/view/zoom.d.ts.map +1 -1
  120. package/dist/src/view/zoom.js +373 -76
  121. package/package.json +5 -2
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Handles logical/physical canvas size calculations and optional
3
+ * device-pixel-content-box observation.
4
+ */
5
+ export default class CanvasSizeHelper {
6
+ /**
7
+ * @param {HTMLElement} container
8
+ * @param {HTMLCanvasElement} canvas
9
+ * @param {() => {width: number, height: number}} sizeSource
10
+ * @param {() => void} [onPhysicalSizeChange]
11
+ */
12
+ constructor(container, canvas, sizeSource, onPhysicalSizeChange) {
13
+ this._container = container;
14
+ this._canvas = canvas;
15
+ this._sizeSource = sizeSource;
16
+ this._onPhysicalSizeChange = onPhysicalSizeChange ?? (() => {});
17
+
18
+ /**
19
+ * @type {{ width: number, height: number } | undefined}
20
+ */
21
+ this._logicalCanvasSize = undefined;
22
+
23
+ /**
24
+ * @type {{ width: number, height: number } | undefined}
25
+ */
26
+ this._devicePixelContentBoxSize = undefined;
27
+
28
+ /**
29
+ * @type {ResizeObserver | undefined}
30
+ */
31
+ this._devicePixelContentBoxObserver = undefined;
32
+
33
+ this._observeDevicePixelContentBox();
34
+ }
35
+
36
+ invalidate() {
37
+ this._logicalCanvasSize = undefined;
38
+ this._devicePixelContentBoxSize = undefined;
39
+ }
40
+
41
+ finalize() {
42
+ if (this._devicePixelContentBoxObserver) {
43
+ this._devicePixelContentBoxObserver.disconnect();
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Returns the canvas size in true display pixels
49
+ *
50
+ * @param {{ width: number, height: number }} [logicalSize]
51
+ */
52
+ getPhysicalCanvasSize(logicalSize) {
53
+ // devicePixelContentBox gives the actual backing-store pixel size.
54
+ // Prefer it whenever available to avoid fractional DPR drift.
55
+ // https://web.dev/articles/device-pixel-content-box
56
+ if (this._devicePixelContentBoxSize) {
57
+ return this._devicePixelContentBoxSize;
58
+ }
59
+
60
+ const dpr = window.devicePixelRatio ?? 1;
61
+ logicalSize = logicalSize || this.getLogicalCanvasSize();
62
+ return {
63
+ width: Math.round(logicalSize.width * dpr),
64
+ height: Math.round(logicalSize.height * dpr),
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Returns the ratio between true display pixels and logical pixels.
70
+ *
71
+ * @param {{ width: number, height: number }} [logicalSize]
72
+ */
73
+ getDevicePixelRatio(logicalSize) {
74
+ logicalSize = logicalSize || this.getLogicalCanvasSize();
75
+ const physicalSize = this.getPhysicalCanvasSize(logicalSize);
76
+ const widthRatio =
77
+ logicalSize.width > 0
78
+ ? physicalSize.width / logicalSize.width
79
+ : undefined;
80
+ const heightRatio =
81
+ logicalSize.height > 0
82
+ ? physicalSize.height / logicalSize.height
83
+ : undefined;
84
+
85
+ if (widthRatio !== undefined && heightRatio !== undefined) {
86
+ // Width and height can differ slightly because backing-store dimensions
87
+ // are integers. Averaging keeps snapping stable in both directions.
88
+ return (widthRatio + heightRatio) / 2;
89
+ } else if (widthRatio !== undefined) {
90
+ // During transient layout states one logical dimension may be zero.
91
+ // Use the non-zero dimension instead of falling back to window DPR.
92
+ return widthRatio;
93
+ } else if (heightRatio !== undefined) {
94
+ return heightRatio;
95
+ } else {
96
+ return window.devicePixelRatio ?? 1;
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Returns the size of the canvas canvas container size in logical pixels,
102
+ * without devicePixelRatio correction.
103
+ */
104
+ getLogicalCanvasSize() {
105
+ if (this._logicalCanvasSize) {
106
+ return this._logicalCanvasSize;
107
+ }
108
+
109
+ // TODO: The size should never be smaller than the minimum content size!
110
+ const contentSize = this._sizeSource();
111
+
112
+ const cs = window.getComputedStyle(this._container, null);
113
+ // clientWidth/clientHeight are integer CSS pixels, which causes subtle
114
+ // blur at fractional DPR. getBoundingClientRect preserves fractions.
115
+ const containerRect = this._container.getBoundingClientRect();
116
+
117
+ const paddingLeft = parseFloat(cs.paddingLeft);
118
+ const paddingRight = parseFloat(cs.paddingRight);
119
+ const paddingTop = parseFloat(cs.paddingTop);
120
+ const paddingBottom = parseFloat(cs.paddingBottom);
121
+
122
+ const borderLeft = parseFloat(cs.borderLeftWidth);
123
+ const borderRight = parseFloat(cs.borderRightWidth);
124
+ const borderTop = parseFloat(cs.borderTopWidth);
125
+ const borderBottom = parseFloat(cs.borderBottomWidth);
126
+
127
+ const width =
128
+ contentSize.width ??
129
+ containerRect.width -
130
+ paddingLeft -
131
+ paddingRight -
132
+ borderLeft -
133
+ borderRight;
134
+
135
+ const height =
136
+ contentSize.height ??
137
+ containerRect.height -
138
+ paddingTop -
139
+ paddingBottom -
140
+ borderTop -
141
+ borderBottom;
142
+
143
+ this._logicalCanvasSize = { width, height };
144
+ return this._logicalCanvasSize;
145
+ }
146
+
147
+ _observeDevicePixelContentBox() {
148
+ if (typeof ResizeObserver != "function") {
149
+ return;
150
+ }
151
+
152
+ const observer = new ResizeObserver((entries) => {
153
+ const entry = entries.find(
154
+ (candidate) => candidate.target == this._canvas
155
+ );
156
+ if (!entry) {
157
+ return;
158
+ }
159
+
160
+ const boxSize = entry.devicePixelContentBoxSize;
161
+ if (!boxSize) {
162
+ return;
163
+ }
164
+
165
+ const contentBoxSize = Array.isArray(boxSize)
166
+ ? boxSize[0]
167
+ : boxSize;
168
+ if (!contentBoxSize) {
169
+ return;
170
+ }
171
+
172
+ // ResizeObserver reports device pixels directly, which is exactly what
173
+ // canvas width/height expect.
174
+ const nextPhysicalSize = {
175
+ width: contentBoxSize.inlineSize,
176
+ height: contentBoxSize.blockSize,
177
+ };
178
+
179
+ if (
180
+ this._devicePixelContentBoxSize &&
181
+ this._devicePixelContentBoxSize.width ==
182
+ nextPhysicalSize.width &&
183
+ this._devicePixelContentBoxSize.height ==
184
+ nextPhysicalSize.height
185
+ ) {
186
+ return;
187
+ }
188
+
189
+ this._devicePixelContentBoxSize = nextPhysicalSize;
190
+ this._onPhysicalSizeChange();
191
+ });
192
+
193
+ try {
194
+ // Fails in browsers that do not support device-pixel-content-box.
195
+ observer.observe(this._canvas, {
196
+ box: "device-pixel-content-box",
197
+ });
198
+ this._devicePixelContentBoxObserver = observer;
199
+ } catch {
200
+ observer.disconnect();
201
+ }
202
+ }
203
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Build-time options for sizing the hash table.
3
+ *
4
+ * @typedef {object} HashTableBuildOptions
5
+ * @property {number} [capacity] Power-of-two table size override.
6
+ * @property {number} [maxLoadFactor] Maximum load factor before resizing.
7
+ */
8
+ /**
9
+ * Packed table payload ready for WebGL texture upload.
10
+ *
11
+ * @typedef {object} HashTableBuildResult
12
+ * @property {Uint32Array} table Hash table slots that contain keys.
13
+ * @property {number} capacity Table capacity (number of slots).
14
+ * @property {number} size Number of stored keys.
15
+ */
16
+ /**
17
+ * 32-bit integer hash for u32 keys. Keep in sync with GLSL hash32.
18
+ *
19
+ * @param {number} value
20
+ * @returns {number}
21
+ */
22
+ export function hash32(value: number): number;
23
+ /**
24
+ * Build a hash table for set membership checks.
25
+ *
26
+ * @param {Iterable<number>} keys
27
+ * @param {HashTableBuildOptions} [options]
28
+ * @returns {HashTableBuildResult}
29
+ */
30
+ export function buildHashTableSet(keys: Iterable<number>, options?: HashTableBuildOptions): HashTableBuildResult;
31
+ /**
32
+ * Computes a 2D texture layout for a power-of-two hash table capacity.
33
+ *
34
+ * The returned dimensions satisfy `width * height === capacity`.
35
+ *
36
+ * @param {number} capacity
37
+ * @param {number} maxTextureSize
38
+ * @returns {{ width: number, height: number }}
39
+ */
40
+ export function computeHashTextureDimensions(capacity: number, maxTextureSize: number): {
41
+ width: number;
42
+ height: number;
43
+ };
44
+ /** Sentinel key that marks an empty hash slot. */
45
+ export const HASH_EMPTY_KEY: 4294967295;
46
+ /** Default maximum load factor for table sizing. */
47
+ export const DEFAULT_MAX_LOAD_FACTOR: 0.6;
48
+ /**
49
+ * Build-time options for sizing the hash table.
50
+ */
51
+ export type HashTableBuildOptions = {
52
+ /**
53
+ * Power-of-two table size override.
54
+ */
55
+ capacity?: number;
56
+ /**
57
+ * Maximum load factor before resizing.
58
+ */
59
+ maxLoadFactor?: number;
60
+ };
61
+ /**
62
+ * Packed table payload ready for WebGL texture upload.
63
+ */
64
+ export type HashTableBuildResult = {
65
+ /**
66
+ * Hash table slots that contain keys.
67
+ */
68
+ table: Uint32Array;
69
+ /**
70
+ * Table capacity (number of slots).
71
+ */
72
+ capacity: number;
73
+ /**
74
+ * Number of stored keys.
75
+ */
76
+ size: number;
77
+ };
78
+ //# sourceMappingURL=hashTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashTable.d.ts","sourceRoot":"","sources":["../../../src/gl/hashTable.js"],"names":[],"mappings":"AAQA;;;;;;GAMG;AAEH;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,8BAHW,MAAM,GACJ,MAAM,CAUlB;AAED;;;;;;GAMG;AACH,wCAJW,QAAQ,CAAC,MAAM,CAAC,YAChB,qBAAqB,GACnB,oBAAoB,CAkDhC;AAED;;;;;;;;GAQG;AACH,uDAJW,MAAM,kBACN,MAAM,GACJ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA+B7C;AAxID,kDAAkD;AAClD,6BAA8B,UAAW,CAAC;AAE1C,oDAAoD;AACpD,sCAAuC,GAAG,CAAC;;;;;;;;eAQ7B,MAAM;;;;oBACN,MAAM;;;;;;;;;WAON,WAAW;;;;cACX,MAAM;;;;UACN,MAAM"}
@@ -0,0 +1,164 @@
1
+ /** Sentinel key that marks an empty hash slot. */
2
+ export const HASH_EMPTY_KEY = 0xffff_ffff;
3
+
4
+ /** Default maximum load factor for table sizing. */
5
+ export const DEFAULT_MAX_LOAD_FACTOR = 0.6;
6
+
7
+ const MAX_U32 = 0xffff_ffff;
8
+
9
+ /**
10
+ * Build-time options for sizing the hash table.
11
+ *
12
+ * @typedef {object} HashTableBuildOptions
13
+ * @property {number} [capacity] Power-of-two table size override.
14
+ * @property {number} [maxLoadFactor] Maximum load factor before resizing.
15
+ */
16
+
17
+ /**
18
+ * Packed table payload ready for WebGL texture upload.
19
+ *
20
+ * @typedef {object} HashTableBuildResult
21
+ * @property {Uint32Array} table Hash table slots that contain keys.
22
+ * @property {number} capacity Table capacity (number of slots).
23
+ * @property {number} size Number of stored keys.
24
+ */
25
+
26
+ /**
27
+ * 32-bit integer hash for u32 keys. Keep in sync with GLSL hash32.
28
+ *
29
+ * @param {number} value
30
+ * @returns {number}
31
+ */
32
+ export function hash32(value) {
33
+ let v = value >>> 0;
34
+ v ^= v >>> 16;
35
+ v = Math.imul(v, 0x7feb352d);
36
+ v ^= v >>> 15;
37
+ v = Math.imul(v, 0x846ca68b);
38
+ v ^= v >>> 16;
39
+ return v >>> 0;
40
+ }
41
+
42
+ /**
43
+ * Build a hash table for set membership checks.
44
+ *
45
+ * @param {Iterable<number>} keys
46
+ * @param {HashTableBuildOptions} [options]
47
+ * @returns {HashTableBuildResult}
48
+ */
49
+ export function buildHashTableSet(keys, options = {}) {
50
+ const normalized = Array.from(keys, (key) => normalizeU32(key, "key"));
51
+ const size = normalized.length;
52
+ const maxLoadFactor = options.maxLoadFactor ?? DEFAULT_MAX_LOAD_FACTOR;
53
+ if (!(maxLoadFactor > 0 && maxLoadFactor < 1)) {
54
+ throw new Error("maxLoadFactor must be between 0 and 1.");
55
+ }
56
+
57
+ const capacity =
58
+ options.capacity ?? nextPow2(Math.ceil(size / maxLoadFactor));
59
+ if (!Number.isSafeInteger(capacity) || capacity < 1) {
60
+ throw new Error("capacity must be a positive power of two.");
61
+ }
62
+ if ((capacity & (capacity - 1)) !== 0) {
63
+ throw new Error("capacity must be a power of two.");
64
+ }
65
+
66
+ const table = new Uint32Array(capacity);
67
+ table.fill(HASH_EMPTY_KEY);
68
+
69
+ const mask = capacity - 1;
70
+ for (const key of normalized) {
71
+ if (key === HASH_EMPTY_KEY) {
72
+ throw new Error(
73
+ "Hash table keys must not equal the empty sentinel (0xffffffff)."
74
+ );
75
+ }
76
+ let index = hash32(key) & mask;
77
+ let inserted = false;
78
+
79
+ for (let probe = 0; probe < capacity; probe += 1) {
80
+ const existingKey = table[index];
81
+ if (existingKey === HASH_EMPTY_KEY || existingKey === key) {
82
+ table[index] = key;
83
+ inserted = true;
84
+ break;
85
+ }
86
+ index = (index + 1) & mask;
87
+ }
88
+
89
+ if (!inserted) {
90
+ throw new Error(
91
+ "Hash table insertion failed. Increase capacity or lower load factor."
92
+ );
93
+ }
94
+ }
95
+
96
+ return { table, capacity, size };
97
+ }
98
+
99
+ /**
100
+ * Computes a 2D texture layout for a power-of-two hash table capacity.
101
+ *
102
+ * The returned dimensions satisfy `width * height === capacity`.
103
+ *
104
+ * @param {number} capacity
105
+ * @param {number} maxTextureSize
106
+ * @returns {{ width: number, height: number }}
107
+ */
108
+ export function computeHashTextureDimensions(capacity, maxTextureSize) {
109
+ if (!Number.isSafeInteger(capacity) || capacity < 1) {
110
+ throw new Error("capacity must be a positive integer.");
111
+ }
112
+ if ((capacity & (capacity - 1)) !== 0) {
113
+ throw new Error("capacity must be a power of two.");
114
+ }
115
+ if (!Number.isSafeInteger(maxTextureSize) || maxTextureSize < 1) {
116
+ throw new Error("maxTextureSize must be a positive integer.");
117
+ }
118
+
119
+ const maxSlots = maxTextureSize * maxTextureSize;
120
+ if (capacity > maxSlots) {
121
+ throw new Error(
122
+ "Selection hash table exceeds maximum texture capacity."
123
+ );
124
+ }
125
+
126
+ const maxPow2Width = 1 << Math.floor(Math.log2(maxTextureSize));
127
+ const width = Math.min(capacity, maxPow2Width);
128
+ const height = capacity / width;
129
+
130
+ if (height > maxTextureSize) {
131
+ throw new Error(
132
+ "Selection hash table dimensions exceed maximum texture size."
133
+ );
134
+ }
135
+
136
+ return { width, height };
137
+ }
138
+
139
+ /**
140
+ * @param {number} value
141
+ * @param {string} label
142
+ * @returns {number}
143
+ */
144
+ function normalizeU32(value, label) {
145
+ if (!Number.isSafeInteger(value) || value < 0 || value > MAX_U32) {
146
+ throw new Error(label + " must be a non-negative u32.");
147
+ }
148
+ return value >>> 0;
149
+ }
150
+
151
+ /**
152
+ * @param {number} value
153
+ * @returns {number}
154
+ */
155
+ function nextPow2(value) {
156
+ let v = Math.max(1, value);
157
+ v -= 1;
158
+ v |= v >>> 1;
159
+ v |= v >>> 2;
160
+ v |= v >>> 4;
161
+ v |= v >>> 8;
162
+ v |= v >>> 16;
163
+ return v + 1;
164
+ }
@@ -1,2 +1,2 @@
1
- const shader = "#define PI 3.141593\nuniform View{mediump vec2 uViewOffset;mediump vec2 uViewScale;mediump vec2 uViewportSize;lowp float uDevicePixelRatio;lowp float uViewOpacity;bool uPickingEnabled;};/***Maps a coordinate on the unit scale to a normalized device coordinate.*(0,0)is at the bottom left corner.*/vec4 unitToNdc(vec2 coord){return vec4((coord*uViewScale+uViewOffset)*2.0-1.0,0.0,1.0);}vec4 unitToNdc(float x,float y){return unitToNdc(vec2(x,y));}vec4 pixelsToNdc(vec2 coord){return unitToNdc(coord/uViewportSize);}vec4 pixelsToNdc(float x,float y){return pixelsToNdc(vec2(x,y));}float linearstep(float edge0,float edge1,float x){return clamp((x-edge0)/(edge1-edge0),0.0,1.0);}bool isEmptyBinarySearchTexture(highp usampler2D s){return textureSize(s,0).x==1&&texelFetch(s,ivec2(0,0),0).r==0u;}bool binarySearchTexture(highp usampler2D s,uint value){int texSize=textureSize(s,0).x;if(texSize==1&&texelFetch(s,ivec2(0,0),0).r==0u){return false;}int left=0;int right=texSize-1;while(left<=right){int mid=left+(right-left)/2;uint midValue=texelFetch(s,ivec2(mid,0),0).r;if(midValue==value){return true;}if(midValue<value){left=mid+1;}else{right=mid-1;}}return false;}/***Calculates a gamma for antialiasing opacity based on the color.*/float getGammaForColor(vec3 rgb){return mix(1.25,0.75,smoothstep(0.0,1.0,dot(rgb,vec3(0.299,0.587,0.114))));}/***Specialized linearstep for doing antialiasing*/float distanceToRatio(float d){return clamp(d*uDevicePixelRatio+0.5,0.0,1.0);}vec4 distanceToColor(float d,vec4 fill,vec4 stroke,vec4 background,float halfStrokeWidth){if(halfStrokeWidth>0.0){float sd=abs(d)-halfStrokeWidth;return mix(stroke,d<=0.0 ? fill : background,distanceToRatio(sd));}else{return mix(background,fill,distanceToRatio(-d));}}";
1
+ const shader = "#define PI 3.141593\nuniform View{mediump vec2 uViewOffset;mediump vec2 uViewScale;mediump vec2 uViewportSize;lowp float uDevicePixelRatio;lowp float uViewOpacity;bool uPickingEnabled;};/***Maps a coordinate on the unit scale to a normalized device coordinate.*(0,0)is at the bottom left corner.*/vec4 unitToNdc(vec2 coord){return vec4((coord*uViewScale+uViewOffset)*2.0-1.0,0.0,1.0);}vec4 unitToNdc(float x,float y){return unitToNdc(vec2(x,y));}vec4 pixelsToNdc(vec2 coord){return unitToNdc(coord/uViewportSize);}vec4 pixelsToNdc(float x,float y){return pixelsToNdc(vec2(x,y));}float linearstep(float edge0,float edge1,float x){return clamp((x-edge0)/(edge1-edge0),0.0,1.0);}const highp uint HASH_EMPTY_KEY=0xffffffffu;highp uint hash32(highp uint key){highp uint v=key;v ^=v>>16u;v*=0x7feb352du;v ^=v>>15u;v*=0x846ca68bu;v ^=v>>16u;return v;}bool isEmptyHashTexture(highp usampler2D s){ivec2 texSize=textureSize(s,0);return texSize.x==1&&texSize.y==1&&texelFetch(s,ivec2(0,0),0).r==HASH_EMPTY_KEY;}bool hashContainsTexture(highp usampler2D s,highp uint value){ivec2 texSize=textureSize(s,0);highp uint width=uint(texSize.x);highp uint size=width*uint(texSize.y);highp uint mask=size-1u;highp uint index=hash32(value)&mask;for(highp uint probe=0u;probe<size;probe+=1u){ivec2 coord=ivec2(int(index % width),int(index/width));highp uint entry=texelFetch(s,coord,0).r;if(entry==value){return true;}if(entry==HASH_EMPTY_KEY){return false;}index=(index+1u)&mask;}return false;}/***Calculates a gamma for antialiasing opacity based on the color.*/float getGammaForColor(vec3 rgb){return mix(1.25,0.75,smoothstep(0.0,1.0,dot(rgb,vec3(0.299,0.587,0.114))));}/***Specialized linearstep for doing antialiasing*/float distanceToRatio(float d){return clamp(d*uDevicePixelRatio+0.5,0.0,1.0);}vec4 distanceToColor(float d,vec4 fill,vec4 stroke,vec4 background,float halfStrokeWidth){if(halfStrokeWidth>0.0){float sd=abs(d)-halfStrokeWidth;return mix(stroke,d<=0.0 ? fill : background,distanceToRatio(sd));}else{return mix(background,fill,distanceToRatio(-d));}}";
2
2
  export default shader;
@@ -45,11 +45,19 @@ export default class WebGLHelper {
45
45
  width: number;
46
46
  height: number;
47
47
  }, webglContextAttributes?: WebGLContextAttributes);
48
- _container: HTMLElement;
49
- _sizeSource: () => {
50
- width: any;
51
- height: any;
52
- };
48
+ /**
49
+ * @type {CanvasSizeHelper}
50
+ */
51
+ _canvasSizeHelper: CanvasSizeHelper;
52
+ /**
53
+ * @type {{ logicalWidth: number, logicalHeight: number, physicalWidth: number, physicalHeight: number } | undefined}
54
+ */
55
+ _appliedCanvasSize: {
56
+ logicalWidth: number;
57
+ logicalHeight: number;
58
+ physicalWidth: number;
59
+ physicalHeight: number;
60
+ } | undefined;
53
61
  /** @type {Map<string, WebGLShader>} */
54
62
  _shaderCache: Map<string, WebGLShader>;
55
63
  /** @type {WeakMap<import("../types/encoder.js").VegaScale, WebGLTexture>} */
@@ -64,10 +72,6 @@ export default class WebGLHelper {
64
72
  _pickingAttachmentOptions: import("twgl.js").AttachmentOptions[];
65
73
  _pickingBufferInfo: import("twgl.js").FramebufferInfo;
66
74
  invalidateSize(): void;
67
- _logicalCanvasSize: {
68
- width: any;
69
- height: any;
70
- };
71
75
  /**
72
76
  * Compiles and caches a shader. The shader source is used as a cache key.
73
77
  *
@@ -89,13 +93,22 @@ export default class WebGLHelper {
89
93
  width: number;
90
94
  height: number;
91
95
  };
96
+ /**
97
+ * Returns the ratio between true display pixels and logical pixels.
98
+ *
99
+ * @param {{ width: number, height: number }} [logicalSize]
100
+ */
101
+ getDevicePixelRatio(logicalSize?: {
102
+ width: number;
103
+ height: number;
104
+ }): number;
92
105
  /**
93
106
  * Returns the size of the canvas canvas container size in logical pixels,
94
107
  * without devicePixelRatio correction.
95
108
  */
96
109
  getLogicalCanvasSize(): {
97
- width: any;
98
- height: any;
110
+ width: number;
111
+ height: number;
99
112
  };
100
113
  /**
101
114
  * Creates textures for color schemes and discrete/discretizing ranges.
@@ -113,4 +126,5 @@ export default class WebGLHelper {
113
126
  */
114
127
  createSelectionTexture(selection: import("../types/selectionTypes.js").MultiPointSelection, update?: boolean): void;
115
128
  }
129
+ import CanvasSizeHelper from "./canvasSizeHelper.js";
116
130
  //# sourceMappingURL=webGLHelper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webGLHelper.d.ts","sourceRoot":"","sources":["../../../src/gl/webGLHelper.js"],"names":[],"mappings":"AAyZA;;;;GAIG;AACH,kCAJW,sBAAsB,gBACtB,WAAW,kBACX,WAAW;;;;;;EA8CrB;AAED;;;;;GAKG;AACH,0CALW,qBAAqB,WACrB,IAAI,CAAC,OAAO,SAAS,EAAE,cAAc,EAAE,KAAK,CAAC,OAC7C,MAAM,EAAE,GAAG,eAAe,YAC1B,YAAY,gBAYtB;AAED;;;;;;GAMG;AACH,qCALW,sBAAsB,mBACtB,OAAO,SAAS,EAAE,eAAe,KACjC,MAAM,KACN,MAAM,2BAWhB;AAED;;;;;GAKG;AACH,yCAJW,sBAAsB,mBACtB,OAAO,SAAS,EAAE,eAAe,SACjC,MAAM,UA4BhB;AAlfD;IACI;;;;;;;OAOG;IACH,uBANW,WAAW,eACX,MAAM;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,2BAGrC,sBAAsB,EAsFhC;IAnFG,wBAA2B;IAC3B;;;MAKO;IAEP,uCAAuC;IACvC,cADW,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CACN;IAE7B,6EAA6E;IAC7E,eADW,OAAO,CAAC,OAAO,qBAAqB,EAAE,SAAS,EAAE,YAAY,CAAC,CACvC;IAElC;;OAEG;IACH,mBAFU,OAAO,CAAC,OAAO,4BAA4B,EAAE,mBAAmB,EAAE,YAAY,CAAC,CAEnD;IA8CtC,0BAAoB;IACpB,2BAAY;IAGZ,oDAAoD;IACpD,2BADW,OAAO,SAAS,EAAE,iBAAiB,EAAE,CAQ/C;IACD,sDAGC;IAML,uBAGC;IAFG;;;MAAmC;IAIvC;;;;;OAKG;IACH,oBAHW,MAAM,QACN,MAAM,GAAG,MAAM,EAAE,eA2B3B;IAED,iBAcC;IAED,iBAEC;IAED;;;;OAIG;IACH,oCAFW;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;;;MAS3C;IAED;;;OAGG;IACH;;;MAuBC;IAED;;;;;;;;;OASG;IACH,+BAHW,OAAO,8BAA8B,EAAE,OAAO,WAC9C,OAAO,QA2GjB;IAED;;OAEG;IACH,kCAFW,OAAO,4BAA4B,EAAE,mBAAmB,0BA+BlE;CACJ"}
1
+ {"version":3,"file":"webGLHelper.d.ts","sourceRoot":"","sources":["../../../src/gl/webGLHelper.js"],"names":[],"mappings":"AAybA;;;;GAIG;AACH,kCAJW,sBAAsB,gBACtB,WAAW,kBACX,WAAW;;;;;;EA8CrB;AAED;;;;;GAKG;AACH,0CALW,qBAAqB,WACrB,IAAI,CAAC,OAAO,SAAS,EAAE,cAAc,EAAE,KAAK,CAAC,OAC7C,MAAM,EAAE,GAAG,eAAe,YAC1B,YAAY,gBAYtB;AAED;;;;;;GAMG;AACH,qCALW,sBAAsB,mBACtB,OAAO,SAAS,EAAE,eAAe,KACjC,MAAM,KACN,MAAM,2BAWhB;AAED;;;;;GAKG;AACH,yCAJW,sBAAsB,mBACtB,OAAO,SAAS,EAAE,eAAe,SACjC,MAAM,UA4BhB;AA7gBD;IACI;;;;;;;OAOG;IACH,uBANW,WAAW,eACX,MAAM;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,2BAGrC,sBAAsB,EAsGhC;IA5FG;;OAEG;IACH,mBAFU,gBAAgB,CAEQ;IAElC;;OAEG;IACH,oBAFU;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAEjF;IAEnC,uCAAuC;IACvC,cADW,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CACN;IAE7B,6EAA6E;IAC7E,eADW,OAAO,CAAC,OAAO,qBAAqB,EAAE,SAAS,EAAE,YAAY,CAAC,CACvC;IAElC;;OAEG;IACH,mBAFU,OAAO,CAAC,OAAO,4BAA4B,EAAE,mBAAmB,EAAE,YAAY,CAAC,CAEnD;IA8CtC,0BAAoB;IACpB,2BAAY;IAGZ,oDAAoD;IACpD,2BADW,OAAO,SAAS,EAAE,iBAAiB,EAAE,CAQ/C;IACD,sDAGC;IAaL,uBAGC;IAED;;;;;OAKG;IACH,oBAHW,MAAM,QACN,MAAM,GAAG,MAAM,EAAE,eA2B3B;IAED,iBAgCC;IAED,iBAGC;IAED;;;;OAIG;IACH,oCAFW;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;;;MAI3C;IAED;;;;OAIG;IACH,kCAFW;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,UAI3C;IAED;;;OAGG;IACH;;;MAEC;IAED;;;;;;;;;OASG;IACH,+BAHW,OAAO,8BAA8B,EAAE,OAAO,WAC9C,OAAO,QA2GjB;IAED;;OAEG;IACH,kCAFW,OAAO,4BAA4B,EAAE,mBAAmB,0BAwClE;CACJ;6BAvX4B,uBAAuB"}