@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.
- package/LICENSE +1 -1
- package/dist/bundle/index.es.js +6842 -5365
- package/dist/bundle/index.js +159 -140
- package/dist/bundle/parquetRead-BnAGCa4_.js +1663 -0
- package/dist/schema.json +281 -17
- package/dist/src/data/formats/bed.d.ts +8 -0
- package/dist/src/data/formats/bed.d.ts.map +1 -0
- package/dist/src/data/formats/bed.js +53 -0
- package/dist/src/data/formats/bedpe.d.ts +8 -0
- package/dist/src/data/formats/bedpe.d.ts.map +1 -0
- package/dist/src/data/formats/bedpe.js +160 -0
- package/dist/src/data/formats/parquet.d.ts +12 -0
- package/dist/src/data/formats/parquet.d.ts.map +1 -0
- package/dist/src/data/formats/parquet.js +29 -0
- package/dist/src/data/formats/parquetRead.d.ts +18 -0
- package/dist/src/data/formats/parquetRead.d.ts.map +1 -0
- package/dist/src/data/formats/parquetRead.js +326 -0
- package/dist/src/data/sources/dataUtils.d.ts +16 -0
- package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
- package/dist/src/data/sources/dataUtils.js +53 -3
- package/dist/src/data/sources/urlSource.d.ts +4 -0
- package/dist/src/data/sources/urlSource.d.ts.map +1 -1
- package/dist/src/data/sources/urlSource.js +141 -17
- package/dist/src/encoder/encoder.d.ts +2 -2
- package/dist/src/fonts/bmFontManager.d.ts +1 -1
- package/dist/src/genome/assemblyPreflight.d.ts +31 -0
- package/dist/src/genome/assemblyPreflight.d.ts.map +1 -0
- package/dist/src/genome/assemblyPreflight.js +99 -0
- package/dist/src/genome/genome.d.ts +2 -2
- package/dist/src/genome/genome.d.ts.map +1 -1
- package/dist/src/genome/genome.js +4 -0
- package/dist/src/genome/genomeStore.d.ts +34 -3
- package/dist/src/genome/genomeStore.d.ts.map +1 -1
- package/dist/src/genome/genomeStore.js +409 -18
- package/dist/src/genome/rootGenomeConfig.d.ts +26 -0
- package/dist/src/genome/rootGenomeConfig.d.ts.map +1 -0
- package/dist/src/genome/rootGenomeConfig.js +94 -0
- package/dist/src/genomeSpy/interactionController.d.ts +5 -1
- package/dist/src/genomeSpy/interactionController.d.ts.map +1 -1
- package/dist/src/genomeSpy/interactionController.js +244 -29
- package/dist/src/genomeSpy/renderCoordinator.js +1 -1
- package/dist/src/genomeSpy.d.ts +13 -3
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +83 -7
- package/dist/src/gl/canvasSizeHelper.d.ts +74 -0
- package/dist/src/gl/canvasSizeHelper.d.ts.map +1 -0
- package/dist/src/gl/canvasSizeHelper.js +203 -0
- package/dist/src/gl/hashTable.d.ts +78 -0
- package/dist/src/gl/hashTable.d.ts.map +1 -0
- package/dist/src/gl/hashTable.js +164 -0
- package/dist/src/gl/includes/common.glsl.js +1 -1
- package/dist/src/gl/webGLHelper.d.ts +25 -11
- package/dist/src/gl/webGLHelper.d.ts.map +1 -1
- package/dist/src/gl/webGLHelper.js +71 -39
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -2
- package/dist/src/marks/link.d.ts.map +1 -1
- package/dist/src/marks/link.js +5 -3
- package/dist/src/marks/mark.d.ts +1 -1
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +8 -4
- package/dist/src/scales/domainPlanner.d.ts +34 -3
- package/dist/src/scales/domainPlanner.d.ts.map +1 -1
- package/dist/src/scales/domainPlanner.js +247 -26
- package/dist/src/scales/scaleInstanceManager.d.ts +2 -1
- package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
- package/dist/src/scales/scaleInstanceManager.js +10 -11
- package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
- package/dist/src/scales/scaleInteractionController.js +16 -14
- package/dist/src/scales/scaleResolution.d.ts +16 -0
- package/dist/src/scales/scaleResolution.d.ts.map +1 -1
- package/dist/src/scales/scaleResolution.js +314 -54
- package/dist/src/scales/scaleResolutionTestUtils.d.ts +21 -0
- package/dist/src/scales/scaleResolutionTestUtils.d.ts.map +1 -0
- package/dist/src/scales/scaleResolutionTestUtils.js +33 -0
- package/dist/src/scales/selectionDomainUtils.d.ts +22 -0
- package/dist/src/scales/selectionDomainUtils.d.ts.map +1 -0
- package/dist/src/scales/selectionDomainUtils.js +79 -0
- package/dist/src/scales/zoomDomainUtils.d.ts +18 -0
- package/dist/src/scales/zoomDomainUtils.d.ts.map +1 -0
- package/dist/src/scales/zoomDomainUtils.js +69 -0
- package/dist/src/screenshotHarness.d.ts +16 -0
- package/dist/src/screenshotHarness.d.ts.map +1 -0
- package/dist/src/screenshotHarness.js +242 -0
- package/dist/src/singlePageApp.js +1 -1
- package/dist/src/spec/data.d.ts +23 -3
- package/dist/src/spec/genome.d.ts +22 -2
- package/dist/src/spec/parameter.d.ts +39 -2
- package/dist/src/spec/root.d.ts +20 -1
- package/dist/src/spec/scale.d.ts +41 -5
- package/dist/src/styles/genome-spy.css +8 -0
- package/dist/src/styles/genome-spy.css.d.ts +1 -1
- package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
- package/dist/src/styles/genome-spy.css.js +8 -0
- package/dist/src/tooltip/dataTooltipHandler.js +59 -10
- package/dist/src/types/embedApi.d.ts +19 -0
- package/dist/src/utils/inferSpecBaseUrl.d.ts +14 -0
- package/dist/src/utils/inferSpecBaseUrl.d.ts.map +1 -0
- package/dist/src/utils/inferSpecBaseUrl.js +73 -0
- package/dist/src/utils/interactionEvent.d.ts +53 -3
- package/dist/src/utils/interactionEvent.d.ts.map +1 -1
- package/dist/src/utils/interactionEvent.js +62 -1
- package/dist/src/utils/radixSort.d.ts.map +1 -1
- package/dist/src/utils/radixSort.js +26 -1
- package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
- package/dist/src/view/containerMutationHelper.js +8 -0
- package/dist/src/view/dataReadiness.d.ts +2 -2
- package/dist/src/view/dataReadiness.d.ts.map +1 -1
- package/dist/src/view/dataReadiness.js +63 -58
- package/dist/src/view/facetView.d.ts +1 -1
- package/dist/src/view/facetView.js +1 -1
- package/dist/src/view/gridView/gridChild.d.ts +7 -0
- package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
- package/dist/src/view/gridView/gridChild.js +180 -11
- package/dist/src/view/gridView/gridView.d.ts.map +1 -1
- package/dist/src/view/gridView/gridView.js +60 -17
- package/dist/src/view/unitView.d.ts +1 -1
- package/dist/src/view/zoom.d.ts +14 -2
- package/dist/src/view/zoom.d.ts.map +1 -1
- package/dist/src/view/zoom.js +373 -76
- package/package.json +5 -2
package/dist/src/view/zoom.js
CHANGED
|
@@ -9,13 +9,27 @@
|
|
|
9
9
|
|
|
10
10
|
import { makeLerpSmoother } from "../utils/animator.js";
|
|
11
11
|
import RingBuffer from "../utils/ringBuffer.js";
|
|
12
|
+
import { isTouchGestureEvent } from "../utils/interactionEvent.js";
|
|
12
13
|
import Point from "./layout/point.js";
|
|
13
14
|
|
|
14
|
-
/**
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {object} ZoomInteractionState
|
|
17
|
+
* @prop {ReturnType<typeof makeLerpSmoother>} smoother
|
|
18
|
+
* @prop {RingBuffer<{point: Point, timestamp: number}>} touchPanEventBuffer
|
|
19
|
+
* @prop {Point | undefined} touchPanLastPoint
|
|
20
|
+
* @prop {0 | 1 | 2} touchPanPointerCount
|
|
21
|
+
*/
|
|
16
22
|
|
|
17
23
|
let lastTimestamp = 0;
|
|
18
24
|
|
|
25
|
+
/** @type {WeakMap<import("../utils/animator.js").default, ZoomInteractionState>} */
|
|
26
|
+
const zoomInteractionStates = new WeakMap();
|
|
27
|
+
|
|
28
|
+
/** @type {ZoomInteractionState} */
|
|
29
|
+
const fallbackInteractionState = createInteractionState();
|
|
30
|
+
|
|
31
|
+
const MIN_LINK_ENDPOINT_SNAP_DISTANCE = 6;
|
|
32
|
+
|
|
19
33
|
export function markZoomActivity() {
|
|
20
34
|
lastTimestamp = performance.now();
|
|
21
35
|
}
|
|
@@ -35,26 +49,25 @@ function recordTimeStamp(fn) {
|
|
|
35
49
|
// @ts-ignore
|
|
36
50
|
return function (...args) {
|
|
37
51
|
markZoomActivity();
|
|
38
|
-
fn(...args);
|
|
52
|
+
return fn(...args);
|
|
39
53
|
};
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
/**
|
|
43
57
|
* @param {import("../utils/interactionEvent.js").default} event
|
|
44
58
|
* @param {import("./layout/rectangle.js").default} coords
|
|
45
|
-
* @param {(zoomEvent: ZoomEvent) => void} handleZoom
|
|
59
|
+
* @param {(zoomEvent: ZoomEvent) => boolean | void} handleZoom
|
|
46
60
|
* @param {import("../types/viewContext.js").Hover} [hover]
|
|
47
61
|
* @param {import("../utils/animator.js").default} [animator]
|
|
48
62
|
*/
|
|
49
63
|
export function interactionToZoom(event, coords, handleZoom, hover, animator) {
|
|
50
64
|
handleZoom = recordTimeStamp(handleZoom);
|
|
65
|
+
const interactionState = getInteractionState(animator);
|
|
51
66
|
|
|
52
67
|
if (event.type == "wheel") {
|
|
53
68
|
// TODO: Wheel-zoom inertia should probably be moved here and the faked wheel
|
|
54
69
|
// events in genomeSpy.js and inertia.js should be retired.
|
|
55
70
|
|
|
56
|
-
event.uiEvent.preventDefault(); // TODO: Only if there was something zoomable
|
|
57
|
-
|
|
58
71
|
const wheelEvent = /** @type {WheelEvent} */ (event.uiEvent);
|
|
59
72
|
const wheelMultiplier = wheelEvent.deltaMode ? 120 : 1;
|
|
60
73
|
|
|
@@ -63,46 +76,73 @@ export function interactionToZoom(event, coords, handleZoom, hover, animator) {
|
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
// Stop drag-to-pan inertia
|
|
66
|
-
smoother?.stop();
|
|
79
|
+
interactionState.smoother?.stop();
|
|
67
80
|
|
|
68
81
|
let { x, y } = event.point;
|
|
69
82
|
|
|
70
83
|
// Snapping to the hovered item:
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
// This allows
|
|
74
|
-
// continuously adjust the cursor position.
|
|
84
|
+
// - Link marks: snap to the nearest endpoint when cursor is near one.
|
|
85
|
+
// - Other marks: snap to the center if only primary positional channels exist.
|
|
86
|
+
// This allows rapid zooming without constantly adjusting cursor position.
|
|
75
87
|
|
|
76
88
|
if (hover) {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
const linkEndpoint = getLinkEndpointSnapPoint(
|
|
90
|
+
event.point,
|
|
91
|
+
coords,
|
|
92
|
+
hover
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
if (linkEndpoint) {
|
|
96
|
+
if (linkEndpoint.x !== undefined) {
|
|
97
|
+
x = linkEndpoint.x;
|
|
98
|
+
}
|
|
99
|
+
if (linkEndpoint.y !== undefined) {
|
|
100
|
+
y = linkEndpoint.y;
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
const e = hover.mark.encoders;
|
|
104
|
+
if (e.x && !e.x2 && !e.x.constant) {
|
|
105
|
+
x =
|
|
106
|
+
getEncoderUnitPosition(e.x, hover.datum) *
|
|
107
|
+
coords.width +
|
|
108
|
+
coords.x;
|
|
109
|
+
}
|
|
110
|
+
if (e.y && !e.y2 && !e.y.constant) {
|
|
111
|
+
y =
|
|
112
|
+
(1 - getEncoderUnitPosition(e.y, hover.datum)) *
|
|
113
|
+
coords.height +
|
|
114
|
+
coords.y;
|
|
115
|
+
}
|
|
83
116
|
}
|
|
84
117
|
}
|
|
85
118
|
|
|
119
|
+
let handled = false;
|
|
86
120
|
if (Math.abs(wheelEvent.deltaX) < Math.abs(wheelEvent.deltaY)) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
121
|
+
handled =
|
|
122
|
+
handleZoom({
|
|
123
|
+
x,
|
|
124
|
+
y,
|
|
125
|
+
xDelta: 0,
|
|
126
|
+
yDelta: 0,
|
|
127
|
+
zDelta: (wheelEvent.deltaY * wheelMultiplier) / 300,
|
|
128
|
+
}) === true;
|
|
94
129
|
} else {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
130
|
+
handled =
|
|
131
|
+
handleZoom({
|
|
132
|
+
x,
|
|
133
|
+
y,
|
|
134
|
+
xDelta: -wheelEvent.deltaX * wheelMultiplier,
|
|
135
|
+
yDelta: 0,
|
|
136
|
+
zDelta: 0,
|
|
137
|
+
}) === true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (handled) {
|
|
141
|
+
wheelEvent.preventDefault();
|
|
102
142
|
}
|
|
103
143
|
} else if (event.type == "mousedown" && event.mouseEvent.button === 0) {
|
|
104
|
-
if (smoother) {
|
|
105
|
-
smoother.stop();
|
|
144
|
+
if (interactionState.smoother) {
|
|
145
|
+
interactionState.smoother.stop();
|
|
106
146
|
}
|
|
107
147
|
|
|
108
148
|
/** @type {RingBuffer<{point: Point, timestamp: number}>} */
|
|
@@ -132,63 +172,320 @@ export function interactionToZoom(event, coords, handleZoom, hover, animator) {
|
|
|
132
172
|
prevPoint = point;
|
|
133
173
|
};
|
|
134
174
|
|
|
135
|
-
const
|
|
136
|
-
|
|
175
|
+
const onMouseup = () => {
|
|
176
|
+
document.removeEventListener("mousemove", onMousemove);
|
|
177
|
+
document.removeEventListener("mouseup", onMouseup);
|
|
178
|
+
startPanInertia(
|
|
179
|
+
interactionState,
|
|
180
|
+
eventBuffer,
|
|
181
|
+
prevPoint,
|
|
182
|
+
handleZoom,
|
|
183
|
+
animator,
|
|
184
|
+
{ minSampleCount: 5 }
|
|
185
|
+
);
|
|
186
|
+
};
|
|
137
187
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
188
|
+
document.addEventListener("mouseup", onMouseup, false);
|
|
189
|
+
document.addEventListener("mousemove", onMousemove, false);
|
|
190
|
+
} else if (event.type == "touchgesture") {
|
|
191
|
+
if (!isTouchGestureEvent(event.uiEvent)) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
142
194
|
|
|
143
|
-
|
|
144
|
-
|
|
195
|
+
const touchGesture = event.uiEvent;
|
|
196
|
+
const { xDelta, yDelta, zDelta } = touchGesture;
|
|
197
|
+
|
|
198
|
+
if (touchGesture.phase === "end") {
|
|
199
|
+
if (touchGesture.pointerCount === 1) {
|
|
200
|
+
startPanInertia(
|
|
201
|
+
interactionState,
|
|
202
|
+
interactionState.touchPanEventBuffer,
|
|
203
|
+
interactionState.touchPanLastPoint,
|
|
204
|
+
handleZoom,
|
|
205
|
+
animator,
|
|
206
|
+
{
|
|
207
|
+
minSampleCount: 2,
|
|
208
|
+
minVelocityPxPerMs: 0.03,
|
|
209
|
+
}
|
|
210
|
+
);
|
|
145
211
|
}
|
|
212
|
+
resetTouchPanState(interactionState);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (
|
|
217
|
+
interactionState.touchPanPointerCount !== touchGesture.pointerCount
|
|
218
|
+
) {
|
|
219
|
+
resetTouchPanState(interactionState);
|
|
220
|
+
interactionState.touchPanPointerCount = touchGesture.pointerCount;
|
|
221
|
+
}
|
|
146
222
|
|
|
147
|
-
|
|
148
|
-
|
|
223
|
+
const currentPoint = new Point(
|
|
224
|
+
event.point.x + xDelta,
|
|
225
|
+
event.point.y + yDelta
|
|
226
|
+
);
|
|
227
|
+
interactionState.touchPanLastPoint = currentPoint;
|
|
149
228
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
229
|
+
if (touchGesture.pointerCount === 1 && (xDelta !== 0 || yDelta !== 0)) {
|
|
230
|
+
interactionState.touchPanEventBuffer.push({
|
|
231
|
+
point: currentPoint,
|
|
232
|
+
timestamp: performance.now(),
|
|
233
|
+
});
|
|
234
|
+
}
|
|
153
235
|
|
|
154
|
-
|
|
155
|
-
|
|
236
|
+
if (xDelta === 0 && yDelta === 0 && zDelta === 0) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
156
239
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
(p) => {
|
|
160
|
-
handleZoom({
|
|
161
|
-
x: p.x,
|
|
162
|
-
y: p.y,
|
|
163
|
-
xDelta: x - p.x,
|
|
164
|
-
yDelta: y - p.y,
|
|
165
|
-
zDelta: 0,
|
|
166
|
-
});
|
|
167
|
-
x = p.x;
|
|
168
|
-
y = p.y;
|
|
169
|
-
},
|
|
170
|
-
150,
|
|
171
|
-
0.5,
|
|
172
|
-
{ x, y }
|
|
173
|
-
);
|
|
240
|
+
// Stop drag-to-pan inertia when touch gestures take over.
|
|
241
|
+
interactionState.smoother?.stop();
|
|
174
242
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
243
|
+
handleZoom({
|
|
244
|
+
x: event.point.x,
|
|
245
|
+
y: event.point.y,
|
|
246
|
+
xDelta,
|
|
247
|
+
yDelta,
|
|
248
|
+
zDelta,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
180
252
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
253
|
+
/**
|
|
254
|
+
* @param {Point} point
|
|
255
|
+
* @param {import("./layout/rectangle.js").default} coords
|
|
256
|
+
* @param {import("../types/viewContext.js").Hover} hover
|
|
257
|
+
*/
|
|
258
|
+
function getLinkEndpointSnapPoint(point, coords, hover) {
|
|
259
|
+
if (hover.mark.getType() !== "link") {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const e = hover.mark.encoders;
|
|
264
|
+
if (!(e.x && e.y && e.x2 && e.y2)) {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const snapX = !e.x.constant && !e.x2.constant;
|
|
269
|
+
const snapY = !e.y.constant && !e.y2.constant;
|
|
270
|
+
|
|
271
|
+
if (!snapX && !snapY) {
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const x1 =
|
|
276
|
+
getEncoderUnitPosition(e.x, hover.datum) * coords.width + coords.x;
|
|
277
|
+
const y1 =
|
|
278
|
+
(1 - getEncoderUnitPosition(e.y, hover.datum)) * coords.height +
|
|
279
|
+
coords.y;
|
|
280
|
+
const x2 =
|
|
281
|
+
getEncoderUnitPosition(e.x2, hover.datum) * coords.width + coords.x;
|
|
282
|
+
const y2 =
|
|
283
|
+
(1 - getEncoderUnitPosition(e.y2, hover.datum)) * coords.height +
|
|
284
|
+
coords.y;
|
|
285
|
+
|
|
286
|
+
let d1Squared = 0;
|
|
287
|
+
let d2Squared = 0;
|
|
288
|
+
|
|
289
|
+
if (snapX) {
|
|
290
|
+
d1Squared += (point.x - x1) ** 2;
|
|
291
|
+
d2Squared += (point.x - x2) ** 2;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (snapY) {
|
|
295
|
+
d1Squared += (point.y - y1) ** 2;
|
|
296
|
+
d2Squared += (point.y - y2) ** 2;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const size = e.size ? +e.size(hover.datum) : 0;
|
|
300
|
+
const snapDistance = Number.isFinite(size)
|
|
301
|
+
? Math.max(size, MIN_LINK_ENDPOINT_SNAP_DISTANCE)
|
|
302
|
+
: MIN_LINK_ENDPOINT_SNAP_DISTANCE;
|
|
303
|
+
const snapDistanceSquared = snapDistance * snapDistance;
|
|
304
|
+
|
|
305
|
+
if (Math.min(d1Squared, d2Squared) > snapDistanceSquared) {
|
|
306
|
+
return undefined;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (d1Squared <= d2Squared) {
|
|
310
|
+
return {
|
|
311
|
+
x: snapX ? x1 : undefined,
|
|
312
|
+
y: snapY ? y1 : undefined,
|
|
313
|
+
};
|
|
314
|
+
} else {
|
|
315
|
+
return {
|
|
316
|
+
x: snapX ? x2 : undefined,
|
|
317
|
+
y: snapY ? y2 : undefined,
|
|
185
318
|
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
186
321
|
|
|
187
|
-
|
|
188
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Returns channel position in unit coordinates using the same band placement
|
|
324
|
+
* convention as mark rendering.
|
|
325
|
+
*
|
|
326
|
+
* @param {import("../types/encoder.js").Encoder} encoder
|
|
327
|
+
* @param {import("../data/flowNode.js").Datum} datum
|
|
328
|
+
*/
|
|
329
|
+
function getEncoderUnitPosition(encoder, datum) {
|
|
330
|
+
const basePosition = +encoder(datum);
|
|
331
|
+
const scale = encoder.scale;
|
|
332
|
+
|
|
333
|
+
if (!scale) {
|
|
334
|
+
return basePosition;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const band = resolveBandPosition(encoder.channelDef);
|
|
338
|
+
|
|
339
|
+
if (scale.type === "band" || scale.type === "point") {
|
|
340
|
+
if (!Number.isFinite(band)) {
|
|
341
|
+
return basePosition;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const typedScale = /** @type {{ bandwidth: () => number }} */ (
|
|
345
|
+
/** @type {any} */ (scale)
|
|
346
|
+
);
|
|
347
|
+
return basePosition + typedScale.bandwidth() * band;
|
|
348
|
+
} else if (scale.type === "index" || scale.type === "locus") {
|
|
349
|
+
if (!Number.isFinite(band)) {
|
|
350
|
+
return basePosition;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const typedScale =
|
|
354
|
+
/** @type {{ step: () => number, align: () => number }} */ (
|
|
355
|
+
/** @type {any} */ (scale)
|
|
356
|
+
);
|
|
357
|
+
return basePosition + typedScale.step() * (band - typedScale.align());
|
|
358
|
+
} else {
|
|
359
|
+
return basePosition;
|
|
189
360
|
}
|
|
190
361
|
}
|
|
191
362
|
|
|
363
|
+
/**
|
|
364
|
+
* @param {import("../spec/channel.js").ChannelDef} channelDef
|
|
365
|
+
*/
|
|
366
|
+
function resolveBandPosition(channelDef) {
|
|
367
|
+
if (channelDef && "band" in channelDef) {
|
|
368
|
+
return channelDef.band ?? 0.5;
|
|
369
|
+
} else {
|
|
370
|
+
return 0.5;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* @returns {ZoomInteractionState}
|
|
376
|
+
*/
|
|
377
|
+
function createInteractionState() {
|
|
378
|
+
return {
|
|
379
|
+
smoother: undefined,
|
|
380
|
+
touchPanEventBuffer: new RingBuffer(30),
|
|
381
|
+
touchPanLastPoint: undefined,
|
|
382
|
+
touchPanPointerCount: 0,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* @param {import("../utils/animator.js").default} [animator]
|
|
388
|
+
*/
|
|
389
|
+
function getInteractionState(animator) {
|
|
390
|
+
if (!animator) {
|
|
391
|
+
return fallbackInteractionState;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
let state = zoomInteractionStates.get(animator);
|
|
395
|
+
if (!state) {
|
|
396
|
+
state = createInteractionState();
|
|
397
|
+
zoomInteractionStates.set(animator, state);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return state;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* @param {ZoomInteractionState} interactionState
|
|
405
|
+
*/
|
|
406
|
+
function resetTouchPanState(interactionState) {
|
|
407
|
+
interactionState.touchPanEventBuffer = new RingBuffer(30);
|
|
408
|
+
interactionState.touchPanLastPoint = undefined;
|
|
409
|
+
interactionState.touchPanPointerCount = 0;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* @param {ZoomInteractionState} interactionState
|
|
414
|
+
* @param {RingBuffer<{point: Point, timestamp: number}>} eventBuffer
|
|
415
|
+
* @param {Point | undefined} lastPoint
|
|
416
|
+
* @param {(zoomEvent: ZoomEvent) => void} handleZoom
|
|
417
|
+
* @param {import("../utils/animator.js").default} [animator]
|
|
418
|
+
* @param {{minSampleCount?: number, minVelocityPxPerMs?: number}} [options]
|
|
419
|
+
*/
|
|
420
|
+
function startPanInertia(
|
|
421
|
+
interactionState,
|
|
422
|
+
eventBuffer,
|
|
423
|
+
lastPoint,
|
|
424
|
+
handleZoom,
|
|
425
|
+
animator,
|
|
426
|
+
options = {}
|
|
427
|
+
) {
|
|
428
|
+
if (!animator || !lastPoint) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const minSampleCount = options.minSampleCount ?? 5;
|
|
433
|
+
const minVelocityPxPerMs = options.minVelocityPxPerMs ?? 0;
|
|
434
|
+
const lastMillisToInclude = 160;
|
|
435
|
+
const now = performance.now();
|
|
436
|
+
const arr = eventBuffer
|
|
437
|
+
.get()
|
|
438
|
+
.filter((point) => now - point.timestamp < lastMillisToInclude);
|
|
439
|
+
|
|
440
|
+
if (arr.length < minSampleCount) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (arr.length >= 5 && isDecelerating(arr)) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const a = arr.at(-1);
|
|
449
|
+
const b = arr[0];
|
|
450
|
+
const v = a.point
|
|
451
|
+
.subtract(b.point)
|
|
452
|
+
.multiply(1 / (a.timestamp - b.timestamp));
|
|
453
|
+
|
|
454
|
+
if (!Number.isFinite(v.x) || !Number.isFinite(v.y)) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (v.length < minVelocityPxPerMs) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
let x = lastPoint.x;
|
|
463
|
+
let y = lastPoint.y;
|
|
464
|
+
|
|
465
|
+
interactionState.smoother = makeLerpSmoother(
|
|
466
|
+
animator,
|
|
467
|
+
(point) => {
|
|
468
|
+
handleZoom({
|
|
469
|
+
x: point.x,
|
|
470
|
+
y: point.y,
|
|
471
|
+
xDelta: x - point.x,
|
|
472
|
+
yDelta: y - point.y,
|
|
473
|
+
zDelta: 0,
|
|
474
|
+
});
|
|
475
|
+
x = point.x;
|
|
476
|
+
y = point.y;
|
|
477
|
+
},
|
|
478
|
+
150,
|
|
479
|
+
0.5,
|
|
480
|
+
{ x, y }
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
interactionState.smoother({
|
|
484
|
+
x: lastPoint.x - v.x * 250,
|
|
485
|
+
y: lastPoint.y - v.y * 250,
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
192
489
|
/**
|
|
193
490
|
* Split the array into two vectors and compare their lengths to find out if
|
|
194
491
|
* the mouse movement is decelerating.
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"contributors": [],
|
|
9
9
|
"license": "MIT",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.73.0",
|
|
11
11
|
"jsdelivr": "dist/bundle/index.js",
|
|
12
12
|
"unpkg": "dist/bundle/index.js",
|
|
13
13
|
"browser": "dist/bundle/index.js",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"dev": "node dev-server.mjs",
|
|
30
|
+
"capture:screenshots": "node scripts/captureScreenshots.mjs",
|
|
30
31
|
"build": "rm -rf dist && mkdir -p dist && node scripts/build.mjs && vite build && npm run build:schema && npm run build:typings",
|
|
31
32
|
"prepublishOnly": "npm run build",
|
|
32
33
|
"test:tsc": "tsc -p tsconfig.json --noEmit",
|
|
@@ -50,12 +51,14 @@
|
|
|
50
51
|
"@types/d3-scale": "^4.0.9",
|
|
51
52
|
"d3-array": "^3.2.4",
|
|
52
53
|
"d3-color": "^3.1.0",
|
|
54
|
+
"d3-dsv": "^3.0.1",
|
|
53
55
|
"d3-ease": "^3.0.1",
|
|
54
56
|
"d3-format": "^3.1.0",
|
|
55
57
|
"events": "^3.3.0",
|
|
56
58
|
"flatqueue": "^3.0.0",
|
|
57
59
|
"generic-filehandle2": "^2.0.14",
|
|
58
60
|
"gff-nostream": "^2.0.0",
|
|
61
|
+
"hyparquet": "^1.25.0",
|
|
59
62
|
"internmap": "^2.0.3",
|
|
60
63
|
"lit": "^3.3.0",
|
|
61
64
|
"twgl.js": "^4.19.1",
|
|
@@ -67,5 +70,5 @@
|
|
|
67
70
|
"devDependencies": {
|
|
68
71
|
"@types/long": "^4.0.1"
|
|
69
72
|
},
|
|
70
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "925d6b740d4bbb3d28a8e6f4a869cfca60c58449"
|
|
71
74
|
}
|