@genome-spy/core 0.46.1 → 0.48.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 (51) hide show
  1. package/dist/bundle/index.es.js +5310 -5113
  2. package/dist/bundle/index.js +105 -94
  3. package/dist/schema.json +38 -0
  4. package/dist/src/genomeSpy.d.ts.map +1 -1
  5. package/dist/src/genomeSpy.js +31 -16
  6. package/dist/src/gl/webGLHelper.d.ts +2 -1
  7. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  8. package/dist/src/gl/webGLHelper.js +8 -1
  9. package/dist/src/marks/mark.d.ts +24 -12
  10. package/dist/src/marks/mark.d.ts.map +1 -1
  11. package/dist/src/marks/mark.js +27 -13
  12. package/dist/src/marks/point.d.ts +0 -1
  13. package/dist/src/marks/point.d.ts.map +1 -1
  14. package/dist/src/marks/point.js +6 -2
  15. package/dist/src/marks/text.d.ts.map +1 -1
  16. package/dist/src/marks/text.js +4 -1
  17. package/dist/src/scale/scale.js +2 -0
  18. package/dist/src/spec/parameter.d.ts +20 -1
  19. package/dist/src/types/embedApi.d.ts +7 -0
  20. package/dist/src/types/rendering.d.ts +6 -0
  21. package/dist/src/utils/animator.d.ts +17 -0
  22. package/dist/src/utils/animator.d.ts.map +1 -1
  23. package/dist/src/utils/animator.js +72 -0
  24. package/dist/src/utils/inertia.d.ts +6 -15
  25. package/dist/src/utils/inertia.d.ts.map +1 -1
  26. package/dist/src/utils/inertia.js +28 -63
  27. package/dist/src/utils/inputBinding.d.ts.map +1 -1
  28. package/dist/src/utils/inputBinding.js +26 -2
  29. package/dist/src/utils/ringBuffer.d.ts +19 -0
  30. package/dist/src/utils/ringBuffer.d.ts.map +1 -0
  31. package/dist/src/utils/ringBuffer.js +43 -0
  32. package/dist/src/utils/ringBuffer.test.js +39 -0
  33. package/dist/src/view/gridView.d.ts +6 -6
  34. package/dist/src/view/gridView.d.ts.map +1 -1
  35. package/dist/src/view/gridView.js +48 -29
  36. package/dist/src/view/layout/point.d.ts +17 -1
  37. package/dist/src/view/layout/point.d.ts.map +1 -1
  38. package/dist/src/view/layout/point.js +36 -1
  39. package/dist/src/view/unitView.d.ts +3 -14
  40. package/dist/src/view/unitView.d.ts.map +1 -1
  41. package/dist/src/view/unitView.js +26 -8
  42. package/dist/src/view/view.d.ts +14 -5
  43. package/dist/src/view/view.d.ts.map +1 -1
  44. package/dist/src/view/view.js +26 -7
  45. package/dist/src/view/zoom.d.ts +4 -10
  46. package/dist/src/view/zoom.d.ts.map +1 -1
  47. package/dist/src/view/zoom.js +126 -9
  48. package/package.json +2 -2
  49. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts +0 -60
  50. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts.map +0 -1
  51. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
@@ -1,4 +1,6 @@
1
1
  import { lerp } from "vega-util";
2
+ import { makeLerpSmoother } from "./animator.js";
3
+ import clamp from "./clamp.js";
2
4
 
3
5
  /**
4
6
  * Creates some inertia, mainly for zooming with a mechanical mouse wheel
@@ -11,35 +13,32 @@ export default class Inertia {
11
13
  constructor(animator, disabled) {
12
14
  this.animator = animator;
13
15
  this.disabled = !!disabled;
14
- this.damping = 0.015;
15
- this.acceleration = 0.3; // per event
16
- /** Use acceleration if the momentum step is greater than X */
17
- this.accelerationThreshold = 100;
18
- this.lowerLimit = 0.5; // When to stop updating
19
- this.loop = false;
20
16
 
21
- this.momentum = 0;
22
- this.timestamp = 0;
17
+ // Limit the velocity by setting the maximum distance the value can travel
18
+ this.maxDistance = 500;
19
+
23
20
  /** @type {function(number):void} */
24
21
  this.callback = null;
25
22
 
26
- this._transitionCallback = this.animate.bind(this);
27
- this.clear();
28
- }
29
-
30
- clear() {
31
- /** @type {number} */
32
- this.momentum = 0;
33
- this.timestamp = null;
34
- this.loop = null;
35
- this.callback = null;
23
+ this.targetValue = 0;
24
+ this.lastValue = 0;
25
+
26
+ this.smoother = makeLerpSmoother(
27
+ animator,
28
+ (value) => {
29
+ const delta = value - this.lastValue;
30
+ this.lastValue = value;
31
+ this.callback?.(delta);
32
+ },
33
+ 40,
34
+ 0.1
35
+ );
36
36
  }
37
37
 
38
38
  cancel() {
39
- if (this.loop) {
40
- this.animator.cancelTransition(this._transitionCallback);
41
- this.clear();
42
- }
39
+ // decelelerate rapidly
40
+ this.targetValue = lerp([this.lastValue, this.targetValue], 0.3);
41
+ this.smoother(this.targetValue);
43
42
  }
44
43
 
45
44
  /**
@@ -53,50 +52,16 @@ export default class Inertia {
53
52
  return;
54
53
  }
55
54
 
56
- // This may have some use in the future to improve the behavior of
57
- // a mechanical mouse wheel:
58
- // https://github.com/w3c/uievents/issues/181
59
-
60
- if (value * this.momentum < 0) {
61
- this.momentum = 0; // Stop if the direction changes
62
- } else if (Math.abs(value) > this.accelerationThreshold) {
63
- this.momentum = lerp([this.momentum, value], this.acceleration);
64
- } else {
65
- this.momentum = value;
66
- }
67
-
68
55
  this.callback = callback;
69
56
 
70
- if (!this.loop) {
71
- this.animate();
72
- }
73
- }
74
-
75
- /**
76
- *
77
- * @param {number} [timestamp]
78
- */
79
- animate(timestamp) {
80
- this.callback(this.momentum); // TODO: This is actually a delta, should take the elapsed time into account
57
+ const delta = clamp(
58
+ this.targetValue + value - this.lastValue,
59
+ -this.maxDistance,
60
+ this.maxDistance
61
+ );
62
+ this.targetValue = this.lastValue + delta;
81
63
 
82
- const timeDelta = timestamp - this.timestamp || 0;
83
- this.timestamp = timestamp;
84
-
85
- const velocity = Math.abs(this.momentum);
86
-
87
- this.momentum =
88
- Math.sign(this.momentum) *
89
- Math.max(
90
- 0,
91
- velocity - ((velocity * this.damping) ** 1.5 + 0.04) * timeDelta
92
- );
93
-
94
- if (Math.abs(this.momentum) > this.lowerLimit) {
95
- this.loop = true;
96
- this.animator.requestTransition(this._transitionCallback);
97
- } else {
98
- this.clear();
99
- }
64
+ this.smoother(this.targetValue);
100
65
  }
101
66
  }
102
67
 
@@ -1 +1 @@
1
- {"version":3,"file":"inputBinding.d.ts","sourceRoot":"","sources":["../../../src/utils/inputBinding.js"],"names":[],"mappings":"AAIA;;GAEG;AACH,sDAFW,OAAO,0BAA0B,EAAE,OAAO,8CA6GpD"}
1
+ {"version":3,"file":"inputBinding.d.ts","sourceRoot":"","sources":["../../../src/utils/inputBinding.js"],"names":[],"mappings":"AAIA;;GAEG;AACH,sDAFW,OAAO,0BAA0B,EAAE,OAAO,8CAqIpD"}
@@ -32,7 +32,6 @@ export default function createBindingInputs(mediator) {
32
32
  const id = `${random}-param-${name}`;
33
33
 
34
34
  if (bind.input == "range") {
35
- // TODO: Show the value next to the slider
36
35
  inputs.push(
37
36
  html`<label for=${id}>${label}</label>
38
37
  <div>
@@ -99,8 +98,33 @@ export default function createBindingInputs(mediator) {
99
98
  )}
100
99
  </select> `
101
100
  );
101
+ } else if (
102
+ bind.input == "text" ||
103
+ bind.input == "number" ||
104
+ bind.input == "color"
105
+ ) {
106
+ inputs.push(
107
+ html`<label for=${id}>${label}</label>
108
+ <div>
109
+ <input
110
+ id=${id}
111
+ type=${bind.input}
112
+ placeholder=${bind.placeholder ?? ""}
113
+ autocomplete=${bind.autocomplete ?? "off"}
114
+ .value=${value}
115
+ @focus=${(/** @type {any} */ e) =>
116
+ e.target.select()}
117
+ @input=${(/** @type {any} */ e) => {
118
+ debouncedSetter(
119
+ bind.input == "number"
120
+ ? e.target.valueAsNumber
121
+ : e.target.value
122
+ );
123
+ }}
124
+ />
125
+ </div>`
126
+ );
102
127
  } else {
103
- // TODO: Support other types: "text", "number", "color".
104
128
  throw new Error("Unsupported input type: " + bind.input);
105
129
  }
106
130
 
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @template T
3
+ */
4
+ export default class RingBuffer<T> {
5
+ /**
6
+ * @param {number} size
7
+ */
8
+ constructor(size: number);
9
+ /** @param {T} value */
10
+ push(value: T): void;
11
+ /**
12
+ * @returns {T[]}
13
+ */
14
+ get(): T[];
15
+ get size(): number;
16
+ get length(): number;
17
+ #private;
18
+ }
19
+ //# sourceMappingURL=ringBuffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ringBuffer.d.ts","sourceRoot":"","sources":["../../../src/utils/ringBuffer.js"],"names":[],"mappings":"AAAA;;GAEG;AACH;IAQI;;OAEG;IACH,kBAFW,MAAM,EAIhB;IAED,uBAAuB;IACvB,YADY,CAAC,QAKZ;IAED;;OAEG;IACH,OAFa,CAAC,EAAE,CAOf;IAED,mBAEC;IAED,qBAEC;;CACJ"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @template T
3
+ */
4
+ export default class RingBuffer {
5
+ /** @type {T[]} */
6
+ #buffer;
7
+
8
+ #index = 0;
9
+
10
+ #length = 0;
11
+
12
+ /**
13
+ * @param {number} size
14
+ */
15
+ constructor(size) {
16
+ this.#buffer = new Array(size);
17
+ }
18
+
19
+ /** @param {T} value */
20
+ push(value) {
21
+ this.#buffer[this.#index] = value;
22
+ this.#index = (this.#index + 1) % this.size;
23
+ this.#length = Math.min(this.#length + 1, this.size);
24
+ }
25
+
26
+ /**
27
+ * @returns {T[]}
28
+ */
29
+ get() {
30
+ const b = this.#buffer;
31
+ return this.#length < this.size
32
+ ? b.slice(0, this.#length)
33
+ : b.slice(this.#index, this.size).concat(b.slice(0, this.#index));
34
+ }
35
+
36
+ get size() {
37
+ return this.#buffer.length;
38
+ }
39
+
40
+ get length() {
41
+ return this.#length;
42
+ }
43
+ }
@@ -0,0 +1,39 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import RingBuffer from "./ringBuffer.js";
3
+
4
+ describe("ringBuffer", () => {
5
+ test("Empty buffer", () => {
6
+ const buffer = new RingBuffer(10);
7
+ expect(buffer.length).toBe(0);
8
+ expect(buffer.get()).toEqual([]);
9
+ });
10
+
11
+ test("Partially filled buffer", () => {
12
+ const buffer = new RingBuffer(10);
13
+ buffer.push(1);
14
+ buffer.push(2);
15
+ buffer.push(3);
16
+ expect(buffer.length).toBe(3);
17
+ expect(buffer.get()).toEqual([1, 2, 3]);
18
+ });
19
+
20
+ test("Full buffer", () => {
21
+ const buffer = new RingBuffer(3);
22
+ buffer.push(1);
23
+ buffer.push(2);
24
+ buffer.push(3);
25
+ expect(buffer.length).toBe(3);
26
+ expect(buffer.get()).toEqual([1, 2, 3]);
27
+ });
28
+
29
+ test("Overfilled buffer", () => {
30
+ const buffer = new RingBuffer(3);
31
+ buffer.push(1);
32
+ buffer.push(2);
33
+ buffer.push(3);
34
+ buffer.push(4);
35
+ buffer.push(5);
36
+ expect(buffer.length).toBe(3);
37
+ expect(buffer.get()).toEqual([3, 4, 5]);
38
+ });
39
+ });
@@ -117,22 +117,22 @@ declare class Scrollbar extends UnitView {
117
117
  * @param {ScrollDirection} scrollDirection
118
118
  */
119
119
  constructor(gridChild: GridChild, scrollDirection: "vertical" | "horizontal");
120
+ viewportOffset: number;
120
121
  config: {
121
122
  scrollbarSize: number;
122
123
  scrollbarPadding: number;
123
124
  };
124
- scrollDirection: "vertical" | "horizontal";
125
- viewportOffset: number;
126
- maxScrollOffset: number;
127
- scrollbarCoords: Rectangle;
128
- getScrollOffset(): number;
125
+ interpolateViewportOffset: ((target: number) => void) & {
126
+ stop: () => void;
127
+ };
128
+ get scrollOffset(): number;
129
129
  /**
130
130
  *
131
131
  * @param {Rectangle} viewportCoords
132
132
  * @param {Rectangle} coords
133
133
  */
134
134
  updateScrollbar(viewportCoords: Rectangle, coords: Rectangle): void;
135
- maxViewportOffset: number;
135
+ #private;
136
136
  }
137
137
  import Padding from "./layout/padding.js";
138
138
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"gridView.d.ts","sourceRoot":"","sources":["../../../src/view/gridView.js"],"names":[],"mappings":"AAowBA;;;GAGG;AACH,iDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CAwB9C;AAED;;;GAGG;AACH,uDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CA6C9C;AA2BD;;GAEG;AACH,8EAUC;AAED;;;;;GAKG;AACH,4CAJW,OAAO,uBAAuB,EAAE,OAAO,UACvC,OAAO,iBAAiB,EAAE,UAAU,YACpC,QAAQ,aAmBlB;AA33BD;;;;;;;;;;;;;;;GAeG;AACH;IA6BI;;;;;;;;;OASG;IACH,kBARW,OAAO,iBAAiB,EAAE,aAAa,WACvC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,iDAEb,MAAM,WACN,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAoBzC;IARG,8CAAgB;IAOhB,uBAA0B;IAG9B;;OAEG;IACH,qDAIC;IAeD;;OAEG;IACH,wDAKC;IAqBD;;OAEG;IACH,8CAEC;IAED,yBAEC;IAED;;OAEG;IACH,wCAmCC;IA2OD;;;;OAIG;IAEH,gBALW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QA6O1D;;CAmGJ;AAgJD;IACI;;;;OAIG;IACH,6DAHW,aAAa,UACb,MAAM,EAoFhB;IAjFG,4BAAgC;IAChC,kCAAgB;IAChB,eAAoB;IAEpB,uBAAuB;IACvB,YADW,QAAQ,CACQ;IAE3B,uBAAuB;IACvB,kBADW,QAAQ,CACc;IAEjC,mFAAmF;IACnF,MADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAC5D;IAEd,4FAA4F;IAC5F,WADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAC3D;IAEnB,0DAA0D;IAC1D,kEAAoB;IAEpB,uBAAuB;IACvB,OADW,QAAQ,CACG;IAEtB,wBAAwB;IACxB,QADW,SAAS,CACQ;IA4DhC,uEAcC;IAED;;OAEG;IACH,4BAkKC;IAED,uBAqBC;IAED,iCAEC;CACJ;qBAhrC0D,eAAe;sBAFpD,uBAAuB;0BAGnB,oBAAoB;qBAGzB,eAAe;yBALX,mBAAmB;AAmrC5C;IACI;;;OAGG;IACH,uBAHW,SAAS,8CAyFnB;IAtDG;;;MAAoB;IACpB,2CAAsC;IAKtC,uBAAuB;IAEvB,wBAAwB;IACxB,2BAAqC;IA+CzC,0BAKC;IAWD;;;;OAIG;IACH,gCAHW,SAAS,UACT,SAAS,QA8CnB;IA7BG,0BAAsE;CA8B7E;oBAp1CmB,qBAAqB"}
1
+ {"version":3,"file":"gridView.d.ts","sourceRoot":"","sources":["../../../src/view/gridView.js"],"names":[],"mappings":"AAswBA;;;GAGG;AACH,iDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CAwB9C;AAED;;;GAGG;AACH,uDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CA6C9C;AA2BD;;GAEG;AACH,8EAUC;AAED;;;;;GAKG;AACH,4CAJW,OAAO,uBAAuB,EAAE,OAAO,UACvC,OAAO,iBAAiB,EAAE,UAAU,YACpC,QAAQ,aAmBlB;AA53BD;;;;;;;;;;;;;;;GAeG;AACH;IA6BI;;;;;;;;;OASG;IACH,kBARW,OAAO,iBAAiB,EAAE,aAAa,WACvC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,iDAEb,MAAM,WACN,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAoBzC;IARG,8CAAgB;IAOhB,uBAA0B;IAG9B;;OAEG;IACH,qDAIC;IAeD;;OAEG;IACH,wDAKC;IAqBD;;OAEG;IACH,8CAEC;IAED,yBAEC;IAED;;OAEG;IACH,wCAmCC;IA2OD;;;;OAIG;IAEH,gBALW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QA6O1D;;CAoGJ;AAgJD;IACI;;;;OAIG;IACH,6DAHW,aAAa,UACb,MAAM,EAoFhB;IAjFG,4BAAgC;IAChC,kCAAgB;IAChB,eAAoB;IAEpB,uBAAuB;IACvB,YADW,QAAQ,CACQ;IAE3B,uBAAuB;IACvB,kBADW,QAAQ,CACc;IAEjC,mFAAmF;IACnF,MADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAC5D;IAEd,4FAA4F;IAC5F,WADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAC3D;IAEnB,0DAA0D;IAC1D,kEAAoB;IAEpB,uBAAuB;IACvB,OADW,QAAQ,CACG;IAEtB,wBAAwB;IACxB,QADW,SAAS,CACQ;IA4DhC,uEAcC;IAED;;OAEG;IACH,4BAkKC;IAED,uBAqBC;IAED,iCAEC;CACJ;qBAlrC0D,eAAe;sBAFpD,uBAAuB;0BAGnB,oBAAoB;qBAGzB,eAAe;yBALX,mBAAmB;AAqrC5C;IAeI;;;OAGG;IACH,uBAHW,SAAS,8CA4FnB;IA/FD,uBAAmB;IAsCf;;;MAAoB;IAIpB;;MAQC;IA+CL,2BAKC;IAWD;;;;OAIG;IACH,gCAHW,SAAS,UACT,SAAS,QA8CnB;;CACJ;oBAv2CmB,qBAAqB"}
@@ -16,8 +16,9 @@ import ContainerView from "./containerView.js";
16
16
  import LayerView from "./layerView.js";
17
17
  import createTitle from "./title.js";
18
18
  import UnitView from "./unitView.js";
19
- import interactionToZoom from "./zoom.js";
19
+ import { interactionToZoom } from "./zoom.js";
20
20
  import clamp from "../utils/clamp.js";
21
+ import { makeLerpSmoother } from "../utils/animator.js";
21
22
 
22
23
  /**
23
24
  * Modeled after: https://vega.github.io/vega/docs/layout/
@@ -711,7 +712,8 @@ export default class GridView extends ContainerView {
711
712
  pointedChild.view,
712
713
  zoomEvent
713
714
  ),
714
- this.context.getCurrentHover()
715
+ this.context.getCurrentHover(),
716
+ this.context.animator
715
717
  );
716
718
  }
717
719
  }
@@ -1214,6 +1216,20 @@ export class GridChild {
1214
1216
  }
1215
1217
 
1216
1218
  class Scrollbar extends UnitView {
1219
+ /** @type {ScrollDirection} */
1220
+ #scrollDirection;
1221
+
1222
+ #scrollbarCoords = Rectangle.ZERO;
1223
+
1224
+ #maxScrollOffset = 0;
1225
+
1226
+ #maxViewportOffset = 0;
1227
+
1228
+ // This is the actual state of the scrollbar. It's better to keep track of
1229
+ // the viewport offset rather than the scrollbar offset because the former
1230
+ // is more stable when the viewport size changes.
1231
+ viewportOffset = 0;
1232
+
1217
1233
  /**
1218
1234
  * @param {GridChild} gridChild
1219
1235
  * @param {ScrollDirection} scrollDirection
@@ -1251,20 +1267,23 @@ class Scrollbar extends UnitView {
1251
1267
  );
1252
1268
 
1253
1269
  this.config = config;
1254
- this.scrollDirection = scrollDirection;
1270
+ this.#scrollDirection = scrollDirection;
1255
1271
 
1256
- // This is the actual state of the scrollbar. It's better to keep track of
1257
- // the viewport offset rather than the scrollbar offset because the former
1258
- // is more stable when the viewport size changes.
1259
- this.viewportOffset = 0;
1260
-
1261
- this.maxScrollOffset = 0;
1262
- this.scrollbarCoords = Rectangle.ZERO;
1272
+ // Make it smooth!
1273
+ this.interpolateViewportOffset = makeLerpSmoother(
1274
+ this.context.animator,
1275
+ (value) => {
1276
+ this.viewportOffset = value;
1277
+ },
1278
+ 50,
1279
+ 0.4,
1280
+ this.viewportOffset
1281
+ );
1263
1282
 
1264
1283
  this.addInteractionEventListener("mousedown", (coords, event) => {
1265
1284
  event.stopPropagation();
1266
1285
 
1267
- if (this.maxScrollOffset <= 0) {
1286
+ if (this.#maxScrollOffset <= 0) {
1268
1287
  return;
1269
1288
  }
1270
1289
 
@@ -1276,7 +1295,7 @@ class Scrollbar extends UnitView {
1276
1295
  const mouseEvent = /** @type {MouseEvent} */ (event.uiEvent);
1277
1296
  mouseEvent.preventDefault();
1278
1297
 
1279
- const initialScrollOffset = this.getScrollOffset();
1298
+ const initialScrollOffset = this.scrollOffset;
1280
1299
  const initialOffset = getMouseOffset(mouseEvent);
1281
1300
 
1282
1301
  const onMousemove = /** @param {MouseEvent} moveEvent */ (
@@ -1287,13 +1306,13 @@ class Scrollbar extends UnitView {
1287
1306
  initialOffset +
1288
1307
  initialScrollOffset,
1289
1308
  0,
1290
- this.maxScrollOffset
1309
+ this.#maxScrollOffset
1291
1310
  );
1292
1311
 
1293
- this.viewportOffset =
1294
- (scrollOffset / this.maxScrollOffset) *
1295
- this.maxViewportOffset;
1296
- this.context.animator.requestRender();
1312
+ this.interpolateViewportOffset(
1313
+ (scrollOffset / this.#maxScrollOffset) *
1314
+ this.#maxViewportOffset
1315
+ );
1297
1316
  };
1298
1317
 
1299
1318
  const onMouseup = () => {
@@ -1306,10 +1325,10 @@ class Scrollbar extends UnitView {
1306
1325
  });
1307
1326
  }
1308
1327
 
1309
- getScrollOffset() {
1328
+ get scrollOffset() {
1310
1329
  return (
1311
- (this.viewportOffset / this.maxViewportOffset) *
1312
- this.maxScrollOffset
1330
+ (this.viewportOffset / this.#maxViewportOffset) *
1331
+ this.#maxScrollOffset
1313
1332
  );
1314
1333
  }
1315
1334
 
@@ -1319,7 +1338,7 @@ class Scrollbar extends UnitView {
1319
1338
  * @param {import("../types/rendering.js").RenderingOptions} [options]
1320
1339
  */
1321
1340
  render(context, coords, options) {
1322
- super.render(context, this.scrollbarCoords, options);
1341
+ super.render(context, this.#scrollbarCoords, options);
1323
1342
  }
1324
1343
 
1325
1344
  /**
@@ -1332,7 +1351,7 @@ class Scrollbar extends UnitView {
1332
1351
  const sSize = this.config.scrollbarSize;
1333
1352
 
1334
1353
  const dimension =
1335
- this.scrollDirection == "horizontal" ? "width" : "height";
1354
+ this.#scrollDirection == "horizontal" ? "width" : "height";
1336
1355
 
1337
1356
  const visibleFraction = Math.min(
1338
1357
  1,
@@ -1341,28 +1360,28 @@ class Scrollbar extends UnitView {
1341
1360
  const maxScrollLength = viewportCoords[dimension] - 2 * sPad;
1342
1361
  const scrollLength = visibleFraction * maxScrollLength;
1343
1362
 
1344
- this.maxScrollOffset = maxScrollLength - scrollLength;
1345
- this.maxViewportOffset = coords[dimension] - viewportCoords[dimension];
1363
+ this.#maxScrollOffset = maxScrollLength - scrollLength;
1364
+ this.#maxViewportOffset = coords[dimension] - viewportCoords[dimension];
1346
1365
  this.viewportOffset = clamp(
1347
1366
  this.viewportOffset,
1348
1367
  0,
1349
- this.maxViewportOffset
1368
+ this.#maxViewportOffset
1350
1369
  );
1351
1370
 
1352
- this.scrollbarCoords =
1353
- this.scrollDirection == "vertical"
1371
+ this.#scrollbarCoords =
1372
+ this.#scrollDirection == "vertical"
1354
1373
  ? new Rectangle(
1355
1374
  () =>
1356
1375
  viewportCoords.x +
1357
1376
  viewportCoords.width -
1358
1377
  sSize -
1359
1378
  sPad,
1360
- () => viewportCoords.y + sPad + this.getScrollOffset(),
1379
+ () => viewportCoords.y + sPad + this.scrollOffset,
1361
1380
  () => sSize,
1362
1381
  () => scrollLength
1363
1382
  )
1364
1383
  : new Rectangle(
1365
- () => viewportCoords.x + sPad + this.getScrollOffset(),
1384
+ () => viewportCoords.x + sPad + this.scrollOffset,
1366
1385
  () =>
1367
1386
  viewportCoords.y +
1368
1387
  viewportCoords.height -
@@ -1,4 +1,8 @@
1
1
  export default class Point {
2
+ /**
3
+ * @param {MouseEvent} event
4
+ */
5
+ static fromMouseEvent(event: MouseEvent): Point;
2
6
  /**
3
7
  *
4
8
  * @param {number} x
@@ -8,7 +12,19 @@ export default class Point {
8
12
  /** @readonly */ readonly x: number;
9
13
  /** @readonly */ readonly y: number;
10
14
  /**
11
- *
15
+ * @param {Point} point
16
+ */
17
+ subtract(point: Point): Point;
18
+ /**
19
+ * @param {Point} point
20
+ */
21
+ add(point: Point): Point;
22
+ /**
23
+ * @param {number} scalar
24
+ */
25
+ multiply(scalar: number): Point;
26
+ get length(): number;
27
+ /**
12
28
  * @param {Point} point
13
29
  */
14
30
  equals(point: Point): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../../src/view/layout/point.js"],"names":[],"mappings":"AAAA;IACI;;;;OAIG;IACH,eAHW,MAAM,KACN,MAAM,EAKhB;IAFG,gBAAgB,CAAC,mBAAU;IAC3B,gBAAgB,CAAC,mBAAU;IAG/B;;;OAGG;IACH,cAFW,KAAK,WAQf;CACJ"}
1
+ {"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../../src/view/layout/point.js"],"names":[],"mappings":"AAIA;IACI;;OAEG;IACH,6BAFW,UAAU,SAIpB;IAED;;;;OAIG;IACH,eAHW,MAAM,KACN,MAAM,EAKhB;IAFG,gBAAgB,CAAC,mBAAU;IAC3B,gBAAgB,CAAC,mBAAU;IAG/B;;OAEG;IACH,gBAFW,KAAK,SAIf;IAED;;OAEG;IACH,WAFW,KAAK,SAIf;IAED;;OAEG;IACH,iBAFW,MAAM,SAIhB;IAED,qBAEC;IAED;;OAEG;IACH,cAFW,KAAK,WAQf;CACJ"}
@@ -1,4 +1,15 @@
1
+ /*
2
+ * Hmm. This looks quite a bit like a two-dimensional vector.
3
+ * Maybe we should use a vector instead?
4
+ */
1
5
  export default class Point {
6
+ /**
7
+ * @param {MouseEvent} event
8
+ */
9
+ static fromMouseEvent(event) {
10
+ return new Point(event.clientX, event.clientY);
11
+ }
12
+
2
13
  /**
3
14
  *
4
15
  * @param {number} x
@@ -10,7 +21,31 @@ export default class Point {
10
21
  }
11
22
 
12
23
  /**
13
- *
24
+ * @param {Point} point
25
+ */
26
+ subtract(point) {
27
+ return new Point(this.x - point.x, this.y - point.y);
28
+ }
29
+
30
+ /**
31
+ * @param {Point} point
32
+ */
33
+ add(point) {
34
+ return new Point(this.x - point.x, this.y - point.y);
35
+ }
36
+
37
+ /**
38
+ * @param {number} scalar
39
+ */
40
+ multiply(scalar) {
41
+ return new Point(this.x * scalar, this.y * scalar);
42
+ }
43
+
44
+ get length() {
45
+ return Math.sqrt(this.x ** 2 + this.y ** 2);
46
+ }
47
+
48
+ /**
14
49
  * @param {Point} point
15
50
  */
16
51
  equals(point) {
@@ -6,15 +6,7 @@
6
6
  export const markTypes: {
7
7
  [x: string]: typeof import("../marks/mark.js").default;
8
8
  };
9
- export default class UnitView extends ContainerView {
10
- /**
11
- * @typedef {import("../spec/channel.js").Channel} Channel
12
- * @typedef {import("./view.js").default} View
13
- * @typedef {import("./layerView.js").default} LayerView
14
- * @typedef {import("../utils/domainArray.js").DomainArray} DomainArray
15
- * @typedef {import("../spec/view.js").ResolutionTarget} ResolutionTarget
16
- *
17
- */
9
+ export default class UnitView extends View {
18
10
  /**
19
11
  *
20
12
  * @param {import("../spec/view.js").UnitSpec} spec
@@ -51,10 +43,6 @@ export default class UnitView extends ContainerView {
51
43
  * Returns a collector that is associated with this view.
52
44
  */
53
45
  getCollector(): import("../data/collector.js").default;
54
- /**
55
- * @param {Channel} channel A primary channel
56
- */
57
- _validateDomainQuery(channel: import("../spec/channel.js").Channel): import("../spec/channel.js").MarkPropExprDef<import("../spec/channel.js").Type> | import("../spec/channel.js").MarkPropDatumDef<import("../spec/channel.js").Type> | import("../spec/channel.js").ChromPosDef | import("../spec/channel.js").PositionDatumDef | (import("../spec/channel.js").ChromPosDefBase & import("../spec/channel.js").TitleMixins & import("../spec/channel.js").PositionMixins & import("../spec/channel.js").TypeMixins<"locus"> & import("../spec/channel.js").ScaleMixins & import("../spec/channel.js").XIndexDef) | (import("../spec/channel.js").ScaleMixins & import("../spec/channel.js").DatumDefBase & import("../spec/channel.js").TitleMixins & import("../spec/channel.js").TypeMixins<import("../spec/channel.js").Type> & import("../spec/channel.js").PositionMixins & import("../spec/channel.js").XIndexDef) | import("../spec/channel.js").MarkPropDatumDef<import("../spec/channel.js").TypeForShape> | import("../spec/channel.js").MarkPropFieldDef<string, import("../spec/channel.js").Type> | import("../spec/channel.js").PositionFieldDef<string> | (import("../spec/channel.js").FieldDefBase<string> & import("../spec/channel.js").TitleMixins & import("../spec/channel.js").TypeMixins<import("../spec/channel.js").Type> & import("../spec/channel.js").ScaleMixins & import("../spec/channel.js").PositionMixins & import("../spec/channel.js").XIndexDef) | import("../spec/channel.js").MarkPropFieldDef<string, import("../spec/channel.js").TypeForShape>;
58
46
  /**
59
47
  * Returns the domain of the specified channel of this domain/mark.
60
48
  *
@@ -83,6 +71,7 @@ export default class UnitView extends ContainerView {
83
71
  * @returns {import("../spec/view.js").ResolutionBehavior}
84
72
  */
85
73
  getDefaultResolution(channel: string, resolutionType: import("../spec/view.js").ResolutionTarget): import("../spec/view.js").ResolutionBehavior;
74
+ #private;
86
75
  }
87
- import ContainerView from "./containerView.js";
76
+ import View from "./view.js";
88
77
  //# sourceMappingURL=unitView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"unitView.d.ts","sourceRoot":"","sources":["../../../src/view/unitView.js"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH;QAHkB,MAAM,GAAE,cAAc,kBAAkB,EAAE,OAAO;EASjE;AAEF;IACI;;;;;;;OAOG;IACH;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,QAAQ,WAClC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAkBzC;IAbG,yCAAgB;IAIZ,iDAAiD;IACjD,MADW,OAAO,kBAAkB,EAAE,OAAO,CACnB;IAUlC;;;;OAIG;IACH,gBAJW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QAY1D;IAED,kDAIC;IAED;;;;;OAKG;IACH,iEAgFC;IAED;;;OAGG;IACH,mGASC;IAkBD;;OAEG;IACH,uDAEC;IAED;;OAEG;IACH,6/CAcC;IAED;;;;;OAKG;IACH,6BAHW,OAAO,oBAAoB,EAAE,gBAAgB,iDAkBvD;IAED;;;;;;;;;;;;OAYG;IACH,gHA2CC;IAED,uBAQC;IAgBD;;;;OAIG;IACH,8BAJW,MAAM,+DAEJ,OAAO,iBAAiB,EAAE,kBAAkB,CAKxD;CACJ;0BA1VyB,oBAAoB"}
1
+ {"version":3,"file":"unitView.d.ts","sourceRoot":"","sources":["../../../src/view/unitView.js"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH;QAHkB,MAAM,GAAE,cAAc,kBAAkB,EAAE,OAAO;EASjE;AAEF;IAcI;;;;;;;;OAQG;IACH,kBAPW,OAAO,iBAAiB,EAAE,QAAQ,WAClC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,WAAW,EAAE,OAAO,QAC3B,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EA+BzC;IA1BG,yCAAgB;IAIZ,iDAAiD;IACjD,MADW,OAAO,kBAAkB,EAAE,OAAO,CACnB;IAuBlC;;;;OAIG;IACH,gBAJW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QAY1D;IAED,kDAIC;IAED;;;;;OAKG;IACH,iEAgFC;IAED;;;OAGG;IACH,mGASC;IAkBD;;OAEG;IACH,uDAEC;IAqBD;;;;;OAKG;IACH,6BAHW,OAAO,oBAAoB,EAAE,gBAAgB,iDAkBvD;IAED;;;;;;;;;;;;OAYG;IACH,gHA2CC;IAED,uBAQC;IAgBD;;;;OAIG;IACH,8BAJW,MAAM,+DAEJ,OAAO,iBAAiB,EAAE,kBAAkB,CAKxD;;CACJ;iBA/VgB,WAAW"}