@genome-spy/core 0.46.0 → 0.47.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 (63) hide show
  1. package/dist/bundle/index.es.js +5429 -5306
  2. package/dist/bundle/index.js +104 -93
  3. package/dist/schema.json +38 -0
  4. package/dist/src/data/flowNode.d.ts +22 -7
  5. package/dist/src/data/flowNode.d.ts.map +1 -1
  6. package/dist/src/data/flowNode.js +29 -6
  7. package/dist/src/data/flowTestUtils.d.ts +5 -0
  8. package/dist/src/data/flowTestUtils.d.ts.map +1 -1
  9. package/dist/src/data/flowTestUtils.js +11 -0
  10. package/dist/src/data/transforms/clone.d.ts +1 -0
  11. package/dist/src/data/transforms/clone.d.ts.map +1 -1
  12. package/dist/src/data/transforms/coverage.d.ts +4 -1
  13. package/dist/src/data/transforms/coverage.d.ts.map +1 -1
  14. package/dist/src/data/transforms/coverage.js +44 -31
  15. package/dist/src/data/transforms/filter.d.ts +2 -1
  16. package/dist/src/data/transforms/filter.d.ts.map +1 -1
  17. package/dist/src/data/transforms/filter.js +4 -2
  18. package/dist/src/data/transforms/filter.test.js +2 -6
  19. package/dist/src/data/transforms/formula.d.ts +2 -1
  20. package/dist/src/data/transforms/formula.d.ts.map +1 -1
  21. package/dist/src/data/transforms/formula.js +4 -2
  22. package/dist/src/data/transforms/formula.test.js +9 -9
  23. package/dist/src/genomeSpy.d.ts.map +1 -1
  24. package/dist/src/genomeSpy.js +23 -15
  25. package/dist/src/gl/webGLHelper.d.ts +2 -1
  26. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  27. package/dist/src/gl/webGLHelper.js +8 -1
  28. package/dist/src/marks/mark.d.ts +24 -12
  29. package/dist/src/marks/mark.d.ts.map +1 -1
  30. package/dist/src/marks/mark.js +27 -13
  31. package/dist/src/marks/point.d.ts +0 -1
  32. package/dist/src/marks/point.d.ts.map +1 -1
  33. package/dist/src/marks/point.js +6 -2
  34. package/dist/src/marks/text.d.ts.map +1 -1
  35. package/dist/src/marks/text.js +4 -1
  36. package/dist/src/scale/scale.js +2 -0
  37. package/dist/src/spec/parameter.d.ts +20 -1
  38. package/dist/src/types/embedApi.d.ts +7 -0
  39. package/dist/src/types/rendering.d.ts +6 -0
  40. package/dist/src/utils/animator.d.ts +15 -0
  41. package/dist/src/utils/animator.d.ts.map +1 -1
  42. package/dist/src/utils/animator.js +66 -0
  43. package/dist/src/utils/inertia.d.ts +4 -15
  44. package/dist/src/utils/inertia.d.ts.map +1 -1
  45. package/dist/src/utils/inertia.js +28 -63
  46. package/dist/src/utils/inputBinding.d.ts.map +1 -1
  47. package/dist/src/utils/inputBinding.js +26 -2
  48. package/dist/src/view/gridView.d.ts +4 -6
  49. package/dist/src/view/gridView.d.ts.map +1 -1
  50. package/dist/src/view/gridView.js +45 -27
  51. package/dist/src/view/unitView.d.ts +3 -14
  52. package/dist/src/view/unitView.d.ts.map +1 -1
  53. package/dist/src/view/unitView.js +26 -8
  54. package/dist/src/view/view.d.ts +14 -5
  55. package/dist/src/view/view.d.ts.map +1 -1
  56. package/dist/src/view/view.js +26 -7
  57. package/dist/src/view/zoom.d.ts +2 -2
  58. package/dist/src/view/zoom.d.ts.map +1 -1
  59. package/dist/src/view/zoom.js +1 -1
  60. package/package.json +2 -2
  61. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts +0 -60
  62. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.d.ts.map +0 -1
  63. package/dist/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
package/dist/schema.json CHANGED
@@ -507,6 +507,41 @@
507
507
  ],
508
508
  "type": "object"
509
509
  },
510
+ "BindInput": {
511
+ "additionalProperties": false,
512
+ "properties": {
513
+ "autocomplete": {
514
+ "description": "A hint for form autofill. See the [HTML autocomplete attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for additional information.",
515
+ "type": "string"
516
+ },
517
+ "debounce": {
518
+ "description": "If defined, delays event handling until the specified milliseconds have elapsed since the last event was fired.",
519
+ "type": "number"
520
+ },
521
+ "description": {
522
+ "description": "An optional description or help text that is shown below the input element.",
523
+ "type": "string"
524
+ },
525
+ "input": {
526
+ "description": "The type of input element to use. The valid values are `\"checkbox\"`, `\"radio\"`, `\"range\"`, `\"select\"`, `\"text\"`, `\"number\"`, and `\"color\"`.",
527
+ "enum": [
528
+ "text",
529
+ "number",
530
+ "color"
531
+ ],
532
+ "type": "string"
533
+ },
534
+ "name": {
535
+ "description": "By default, the parameter name is used to label input elements. This `name` property can be used instead to specify a custom label for the bound parameter.",
536
+ "type": "string"
537
+ },
538
+ "placeholder": {
539
+ "description": "Text that appears in the form control when it has no value set.",
540
+ "type": "string"
541
+ }
542
+ },
543
+ "type": "object"
544
+ },
510
545
  "BindRadioSelect": {
511
546
  "additionalProperties": false,
512
547
  "properties": {
@@ -595,6 +630,9 @@
595
630
  },
596
631
  {
597
632
  "$ref": "#/definitions/BindRange"
633
+ },
634
+ {
635
+ "$ref": "#/definitions/BindInput"
598
636
  }
599
637
  ]
600
638
  },
@@ -23,6 +23,9 @@ export const BEHAVIOR_MODIFIES: number;
23
23
  * The collected data objects must not be modified by downstream transforms.
24
24
  */
25
25
  export const BEHAVIOR_COLLECTS: number;
26
+ /**
27
+ * @typedef {{paramMediator: import("../view/paramMediator.js").default}} ParamMediatorProvider
28
+ */
26
29
  /**
27
30
  * This is heavily inspired by Vega's and Vega-Lite's data flow system.
28
31
  *
@@ -30,6 +33,17 @@ export const BEHAVIOR_COLLECTS: number;
30
33
  * @typedef {Datum[]} Data
31
34
  */
32
35
  export default class FlowNode {
36
+ /**
37
+ * @param {ParamMediatorProvider} [paramMediatorProvider]
38
+ */
39
+ constructor(paramMediatorProvider?: ParamMediatorProvider);
40
+ /**
41
+ * An object that provides a paramMediator. (Most likely a View)
42
+ *
43
+ * @type {ParamMediatorProvider}
44
+ * @protected
45
+ */
46
+ protected paramMediatorProvider: ParamMediatorProvider;
33
47
  get behavior(): number;
34
48
  /** @type {FlowNode[]} */
35
49
  children: FlowNode[];
@@ -47,16 +61,12 @@ export default class FlowNode {
47
61
  * built and optimized. Must be called before any data are to be propagated.
48
62
  */
49
63
  initialize(): void;
50
- /**
51
- * Dynamically updates the propagator method to allow the JavaScript engine
52
- * to employ optimizations such as inlining.
53
- */
54
- _updatePropagator(): void;
55
64
  /**
56
65
  *
57
66
  * @param {any} datum
67
+ * @protected
58
68
  */
59
- _propagate(datum: any): void;
69
+ protected _propagate(datum: any): void;
60
70
  /**
61
71
  *
62
72
  * @param {FlowNode} parent
@@ -124,9 +134,14 @@ export default class FlowNode {
124
134
  /**
125
135
  * Repropagates the stored data. If this node has no stored data,
126
136
  * find the nearest ancestor that has and repropagate from there.
137
+ * @protected
127
138
  */
128
- repropagate(): void;
139
+ protected repropagate(): void;
140
+ #private;
129
141
  }
142
+ export type ParamMediatorProvider = {
143
+ paramMediator: import("../view/paramMediator.js").default;
144
+ };
130
145
  /**
131
146
  * This is heavily inspired by Vega's and Vega-Lite's data flow system.
132
147
  */
@@ -1 +1 @@
1
- {"version":3,"file":"flowNode.d.ts","sourceRoot":"","sources":["../../../src/data/flowNode.js"],"names":[],"mappings":"AAyRA;;;GAGG;AACH,uCAHW,OAAO,uBAAuB,EAAE,SAAS,0DAKnD;AAED;;;GAGG;AACH,wCAHW,OAAO,uBAAuB,EAAE,SAAS,2DAKnD;AArSD;;;GAGG;AACH,qCAAsC;AAEtC;;;GAGG;AACH,uCAAwC;AAExC;;;GAGG;AACH,uCAAwC;AAExC;;;;;GAKG;AACH;IACI,uBAEC;IAGG,yBAAyB;IACzB,UADW,QAAQ,EAAE,CACH;IAElB,uBAAuB;IACvB,QADW,QAAQ,CACI;IAEvB,2CAA2C;IAC3C,mBAAsB;IAG1B;;;OAGG;IACH,cAMC;IAED;;;OAGG;IACH,mBAEC;IAED;;;OAGG;IACH,0BAUC;IAoMD;;;OAGG;IACH,kBAFW,GAAG,QAIb;IAxMD;;;OAGG;IACH,kBAFW,QAAQ,QAIlB;IAED;;;OAGG;IACH,gBAFW,QAAQ,QAUlB;IAED;;OAEG;IACH,YAFW,QAAQ,QAQlB;IAED;;OAEG;IACH,6BAFW,QAAQ,QAMlB;IAED;;OAEG;IACH,0BAFW,QAAQ,QAalB;IAED;;;OAGG;IACH,mBAFW,QAAQ,QAWlB;IAED;;OAEG;IACH,eAiBC;IAED,kBAEC;IAED,uBAEC;IAED,sBAEC;IAED;;;;OAIG;IACH,eAFW,QAAU,QAAQ,KAAE,IAAI,CAAC,GAAG;QAAE,aAAa,CAAC,SAAW,QAAQ,KAAE,IAAI,CAAA;KAAC,QAchF;IAED;;;OAGG;IACH,wBAHW,MAAM,GACJ,MAAM,CAWlB;IAED;;;OAGG;IACH,cAFW,KAAK,QAKf;IAED,iBAMC;IAED;;;;OAIG;IACH,sBAFW,OAAO,uBAAuB,EAAE,SAAS,QAMnD;IAED;;;OAGG;IACH,0EAKC;IAED;;;OAGG;IACH,oBAQC;CASJ;;;;oBAhQY,OAAO,MAAM,EAAE,GAAG,CAAC;;;;mBACnB,KAAK,EAAE"}
1
+ {"version":3,"file":"flowNode.d.ts","sourceRoot":"","sources":["../../../src/data/flowNode.js"],"names":[],"mappings":"AAgTA;;;GAGG;AACH,uCAHW,OAAO,uBAAuB,EAAE,SAAS,0DAKnD;AAED;;;GAGG;AACH,wCAHW,OAAO,uBAAuB,EAAE,SAAS,2DAKnD;AA5TD;;;GAGG;AACH,qCAAsC;AAEtC;;;GAGG;AACH,uCAAwC;AAExC;;;GAGG;AACH,uCAAwC;AAExC;;GAEG;AAEH;;;;;GAKG;AACH;IAaI;;OAEG;IACH,oCAFW,qBAAqB,EAa/B;IA1BD;;;;;OAKG;IACH,iCAHU,qBAAqB,CAGF;IAE7B,uBAEC;IAQG,yBAAyB;IACzB,UADW,QAAQ,EAAE,CACH;IAElB,uBAAuB;IACvB,QADW,QAAQ,CACI;IAEvB,2CAA2C;IAC3C,mBAAsB;IAG1B;;;OAGG;IACH,cAMC;IAED;;;OAGG;IACH,mBAEC;IAyND;;;;OAIG;IACH,4BAHW,GAAG,QAKb;IA9MD;;;OAGG;IACH,kBAFW,QAAQ,QAIlB;IAED;;;OAGG;IACH,gBAFW,QAAQ,QAUlB;IAED;;OAEG;IACH,YAFW,QAAQ,QAQlB;IAED;;OAEG;IACH,6BAFW,QAAQ,QAMlB;IAED;;OAEG;IACH,0BAFW,QAAQ,QAalB;IAED;;;OAGG;IACH,mBAFW,QAAQ,QAWlB;IAED;;OAEG;IACH,eAiBC;IAED,kBAEC;IAED,uBAEC;IAED,sBAEC;IAED;;;;OAIG;IACH,eAFW,QAAU,QAAQ,KAAE,IAAI,CAAC,GAAG;QAAE,aAAa,CAAC,SAAW,QAAQ,KAAE,IAAI,CAAA;KAAC,QAchF;IAED;;;OAGG;IACH,wBAHW,MAAM,GACJ,MAAM,CAWlB;IAED;;;OAGG;IACH,cAFW,KAAK,QAKf;IAED,iBAMC;IAED;;;;OAIG;IACH,sBAFW,OAAO,uBAAuB,EAAE,SAAS,QAMnD;IAED;;;OAGG;IACH,0EASC;IAED;;;;OAIG;IACH,8BAQC;;CAUJ;oCAzRY;IAAC,aAAa,EAAE,OAAO,0BAA0B,EAAE,OAAO,CAAA;CAAC;;;;oBAM3D,OAAO,MAAM,EAAE,GAAG,CAAC;;;;mBACnB,KAAK,EAAE"}
@@ -18,6 +18,10 @@ export const BEHAVIOR_MODIFIES = 1 << 1;
18
18
  */
19
19
  export const BEHAVIOR_COLLECTS = 1 << 2;
20
20
 
21
+ /**
22
+ * @typedef {{paramMediator: import("../view/paramMediator.js").default}} ParamMediatorProvider
23
+ */
24
+
21
25
  /**
22
26
  * This is heavily inspired by Vega's and Vega-Lite's data flow system.
23
27
  *
@@ -25,11 +29,24 @@ export const BEHAVIOR_COLLECTS = 1 << 2;
25
29
  * @typedef {Datum[]} Data
26
30
  */
27
31
  export default class FlowNode {
32
+ /**
33
+ * An object that provides a paramMediator. (Most likely a View)
34
+ *
35
+ * @type {ParamMediatorProvider}
36
+ * @protected
37
+ */
38
+ paramMediatorProvider = null;
39
+
28
40
  get behavior() {
29
41
  return 0;
30
42
  }
31
43
 
32
- constructor() {
44
+ /**
45
+ * @param {ParamMediatorProvider} [paramMediatorProvider]
46
+ */
47
+ constructor(paramMediatorProvider) {
48
+ this.paramMediatorProvider = paramMediatorProvider;
49
+
33
50
  /** @type {FlowNode[]} */
34
51
  this.children = [];
35
52
 
@@ -64,7 +81,7 @@ export default class FlowNode {
64
81
  * Dynamically updates the propagator method to allow the JavaScript engine
65
82
  * to employ optimizations such as inlining.
66
83
  */
67
- _updatePropagator() {
84
+ #updatePropagator() {
68
85
  this._propagate = Function(
69
86
  "children",
70
87
  range(this.children.length)
@@ -94,7 +111,7 @@ export default class FlowNode {
94
111
  }
95
112
  this.children.push(child);
96
113
  child.setParent(this);
97
- this._updatePropagator();
114
+ this.#updatePropagator();
98
115
  return this;
99
116
  }
100
117
 
@@ -129,7 +146,7 @@ export default class FlowNode {
129
146
 
130
147
  newParent.parent = this.parent;
131
148
  this.parent.children[this.parent.children.indexOf(this)] = newParent;
132
- this.parent._updatePropagator();
149
+ this.parent.#updatePropagator();
133
150
  this.parent = undefined;
134
151
  newParent.addChild(this);
135
152
  }
@@ -143,7 +160,7 @@ export default class FlowNode {
143
160
  if (index > -1) {
144
161
  this.children.splice(index, 1);
145
162
  child.parent = undefined;
146
- this._updatePropagator();
163
+ this.#updatePropagator();
147
164
  } else {
148
165
  throw new Error("Trying to remove an unknown child node!");
149
166
  }
@@ -162,7 +179,7 @@ export default class FlowNode {
162
179
  const child = this.children[0];
163
180
  child.setParent(this.parent);
164
181
  this.parent.children[this.parent.children.indexOf(this)] = child;
165
- this.parent._updatePropagator();
182
+ this.parent.#updatePropagator();
166
183
  this.setParent(undefined);
167
184
  this.children.length = 0;
168
185
  } else {
@@ -250,6 +267,10 @@ export default class FlowNode {
250
267
  * @protected
251
268
  */
252
269
  get paramMediator() {
270
+ if (this.paramMediatorProvider) {
271
+ return this.paramMediatorProvider.paramMediator;
272
+ }
273
+
253
274
  if (!this.parent) {
254
275
  throw new Error("Cannot find paramMediator!");
255
276
  }
@@ -259,6 +280,7 @@ export default class FlowNode {
259
280
  /**
260
281
  * Repropagates the stored data. If this node has no stored data,
261
282
  * find the nearest ancestor that has and repropagate from there.
283
+ * @protected
262
284
  */
263
285
  repropagate() {
264
286
  if (this.parent) {
@@ -273,6 +295,7 @@ export default class FlowNode {
273
295
  /**
274
296
  *
275
297
  * @param {any} datum
298
+ * @protected
276
299
  */
277
300
  _propagate(datum) {
278
301
  // Implementation is set dynamically in add/removeChild
@@ -1,3 +1,8 @@
1
+ /**
2
+ *
3
+ * @returns {import("./flowNode.js").ParamMediatorProvider}
4
+ */
5
+ export function makeParamMediatorProvider(): import("./flowNode.js").ParamMediatorProvider;
1
6
  /**
2
7
  *
3
8
  * @param {import("./flowNode.js").default} flowNode
@@ -1 +1 @@
1
- {"version":3,"file":"flowTestUtils.d.ts","sourceRoot":"","sources":["../../../src/data/flowTestUtils.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,sCAHW,OAAO,eAAe,EAAE,OAAO,QAC/B,GAAG,EAAE,mCAcf;AAED;;GAEG;AACH;IACI;;;OAGG;IACH,kBAFW,GAAG,EAAE,EAKf;IADG,YAAgB;IAGpB,iBAMC;CACJ;AAED;;GAEG;AACH;IACI;;;OAGG;IACH,eAFW,MAAM,EAWhB;CACJ;qBA7DoB,eAAe"}
1
+ {"version":3,"file":"flowTestUtils.d.ts","sourceRoot":"","sources":["../../../src/data/flowTestUtils.js"],"names":[],"mappings":"AAIA;;;GAGG;AACH,6CAFa,OAAO,eAAe,EAAE,qBAAqB,CAMzD;AAED;;;;GAIG;AACH,sCAHW,OAAO,eAAe,EAAE,OAAO,QAC/B,GAAG,EAAE,mCAcf;AAED;;GAEG;AACH;IACI;;;OAGG;IACH,kBAFW,GAAG,EAAE,EAKf;IADG,YAAgB;IAGpB,iBAMC;CACJ;AAED;;GAEG;AACH;IACI;;;OAGG;IACH,eAFW,MAAM,EAWhB;CACJ;qBAvEoB,eAAe"}
@@ -1,6 +1,17 @@
1
+ import ParamMediator from "../view/paramMediator.js";
1
2
  import Collector from "./collector.js";
2
3
  import FlowNode from "./flowNode.js";
3
4
 
5
+ /**
6
+ *
7
+ * @returns {import("./flowNode.js").ParamMediatorProvider}
8
+ */
9
+ export function makeParamMediatorProvider() {
10
+ return {
11
+ paramMediator: new ParamMediator(),
12
+ };
13
+ }
14
+
4
15
  /**
5
16
  *
6
17
  * @param {import("./flowNode.js").default} flowNode
@@ -2,6 +2,7 @@
2
2
  * Clones the data objects that pass through.
3
3
  */
4
4
  export default class CloneTransform extends FlowNode {
5
+ constructor();
5
6
  /** @param {any} datum */
6
7
  handle: (datum: any) => void;
7
8
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"clone.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/clone.js"],"names":[],"mappings":"AAGA;;GAEG;AACH;IAYY,yBAAyB;IACzB,gBALQ,GAAG,UAK2C;IAO1D;;;;OAIG;IACH,yBAFW,OAAO,0BAA0B,EAAE,SAAS,UAQtD;CAER;qBAtCsD,gBAAgB"}
1
+ {"version":3,"file":"clone.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/clone.js"],"names":[],"mappings":"AAGA;;GAEG;AACH;IAKI,cA2BC;IApBO,yBAAyB;IACzB,gBALQ,GAAG,UAK2C;IAO1D;;;;OAIG;IACH,yBAFW,OAAO,0BAA0B,EAAE,SAAS,UAQtD;CAER;qBAtCsD,gBAAgB"}
@@ -8,6 +8,9 @@
8
8
  * segments and calculates weighted averages.
9
9
  */
10
10
  export default class CoverageTransform extends FlowNode {
11
+ /**
12
+ * @typedef {import("../flowNode.js").Datum} Datum
13
+ */
11
14
  /**
12
15
  * @param {import("../../spec/transform.js").CoverageParams} params
13
16
  */
@@ -25,7 +28,7 @@ export default class CoverageTransform extends FlowNode {
25
28
  end: string;
26
29
  chrom: string;
27
30
  };
28
- createSegment: Function;
31
+ createSegment: (start: number, end: number, coverage: number, chrom?: string) => import("../flowNode.js").Datum;
29
32
  /**
30
33
  * End pos as priority, weight as value
31
34
  *
@@ -1 +1 @@
1
- {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/coverage.js"],"names":[],"mappings":";AAKA;;;;;;;GAOG;AACH;IAKI;;OAEG;IACH,oBAFW,OAAO,yBAAyB,EAAE,cAAc,EAgD1D;IA5CG,yDAAoB;IAEpB,mDAAwC;IACxC,iDAAoC;IAEpC,mCAAmC;IACnC,sBADoB,GAAG,KAAE,MAAM,CAGT;IACtB,mCAAmC;IACnC,uBADoB,GAAG,KAAE,MAAM,CACsC;IAErE;;;;;MAKC;IAGD,wBAgBC;IAED;;;;OAIG;IACH,MAFU,UAAU,MAAM,CAAC,CAEA;CAiIlC;qBAhMyC,gBAAgB;sBAHpC,WAAW"}
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/coverage.js"],"names":[],"mappings":";AAKA;;;;;;;GAOG;AACH;IAKI;;OAEG;IAEH;;OAEG;IACH,oBAFW,OAAO,yBAAyB,EAAE,cAAc,EAgD1D;IA5CG,yDAAoB;IAEpB,mDAAwC;IACxC,iDAAoC;IAEpC,mCAAmC;IACnC,sBADoB,GAAG,KAAE,MAAM,CAGT;IACtB,mCAAmC;IACnC,uBADoB,GAAG,KAAE,MAAM,CACsC;IAErE;;;;;MAKC;IAED,sEACsE,MAAM,oCAgBvE;IAEL;;;;OAIG;IACH,MAFU,UAAU,MAAM,CAAC,CAEA;CA0IlC;qBA7MyC,gBAAgB;sBAHpC,WAAW"}
@@ -16,6 +16,10 @@ export default class CoverageTransform extends FlowNode {
16
16
  return BEHAVIOR_CLONES;
17
17
  }
18
18
 
19
+ /**
20
+ * @typedef {import("../flowNode.js").Datum} Datum
21
+ */
22
+
19
23
  /**
20
24
  * @param {import("../../spec/transform.js").CoverageParams} params
21
25
  */
@@ -34,30 +38,30 @@ export default class CoverageTransform extends FlowNode {
34
38
  this.weightAccessor = params.weight ? field(params.weight) : (d) => 1;
35
39
 
36
40
  this.as = {
37
- coverage: params.as || "coverage",
38
- start: params.asStart || params.start,
39
- end: params.asEnd || params.end,
40
- chrom: params.asChrom || params.chrom,
41
+ coverage: params.as ?? "coverage",
42
+ start: params.asStart ?? params.start,
43
+ end: params.asEnd ?? params.end,
44
+ chrom: params.asChrom ?? params.chrom,
41
45
  };
42
46
 
43
- // eslint-disable-next-line no-new-func
44
- this.createSegment = /** @type {function} */ (
45
- new Function(
46
- "start",
47
- "end",
48
- "coverage",
49
- "chrom",
50
- "return {" +
51
- Object.entries(this.as)
52
- .filter(([param, prop]) => prop)
53
- .map(
54
- ([param, prop]) =>
55
- `${JSON.stringify(prop)}: ${param}`
56
- )
57
- .join(", ") +
58
- "};"
59
- )
60
- );
47
+ this.createSegment =
48
+ /** @type {(start: Number, end: Number, coverage: Number, chrom?: string) => Datum} */ (
49
+ new Function(
50
+ "start",
51
+ "end",
52
+ "coverage",
53
+ "chrom",
54
+ "return {" +
55
+ Object.entries(this.as)
56
+ .filter(([param, prop]) => prop)
57
+ .map(
58
+ ([param, prop]) =>
59
+ `${JSON.stringify(prop)}: ${param}`
60
+ )
61
+ .join(", ") +
62
+ "};"
63
+ )
64
+ );
61
65
 
62
66
  /**
63
67
  * End pos as priority, weight as value
@@ -82,7 +86,7 @@ export default class CoverageTransform extends FlowNode {
82
86
  const chromAccessor = this.chromAccessor;
83
87
  const weightAccessor = this.weightAccessor;
84
88
 
85
- /** @type {import("../flowNode.js").Datum} used for merging adjacent segment */
89
+ /** @type {Datum} used for merging adjacent segment */
86
90
  let bufferedSegment;
87
91
 
88
92
  /** @type {string} */
@@ -96,12 +100,20 @@ export default class CoverageTransform extends FlowNode {
96
100
  let coverage = 0;
97
101
 
98
102
  /** @type {number} */
99
- let prevEdge;
103
+ let prevEdge = NaN;
100
104
 
101
105
  /** End pos as priority, weight as value */
102
106
  const ends = this.ends;
103
107
  ends.clear();
104
108
 
109
+ /**
110
+ * @param {Datum} segment
111
+ */
112
+ const propagate = (segment) => {
113
+ this._propagate(segment);
114
+ bufferedSegment = null;
115
+ };
116
+
105
117
  /**
106
118
  * @param {number} start
107
119
  * @param {number} end
@@ -119,7 +131,7 @@ export default class CoverageTransform extends FlowNode {
119
131
  bufferedSegment[asEnd] = end;
120
132
  extended = true;
121
133
  } else if (bufferedSegment[asCoverage] != 0) {
122
- this._propagate(bufferedSegment);
134
+ propagate(bufferedSegment);
123
135
  }
124
136
  }
125
137
 
@@ -140,15 +152,16 @@ export default class CoverageTransform extends FlowNode {
140
152
  prevEdge = edge;
141
153
  coverage -= ends.pop();
142
154
  }
143
- prevEdge = undefined;
155
+ prevEdge = NaN;
144
156
 
145
157
  if (bufferedSegment) {
146
- this._propagate(bufferedSegment);
147
- bufferedSegment = undefined;
158
+ propagate(bufferedSegment);
148
159
  }
149
160
  };
150
161
 
151
- /** @param {Record<string, any>} datum */
162
+ /**
163
+ * @param {Datum} datum
164
+ */
152
165
  this.handle = (datum) => {
153
166
  const start = startAccessor(datum);
154
167
 
@@ -168,7 +181,7 @@ export default class CoverageTransform extends FlowNode {
168
181
  }
169
182
  }
170
183
 
171
- if (prevEdge !== undefined) {
184
+ if (!isNaN(prevEdge)) {
172
185
  pushSegment(prevEdge, start, coverage);
173
186
  }
174
187
  prevEdge = start;
@@ -189,7 +202,7 @@ export default class CoverageTransform extends FlowNode {
189
202
  */
190
203
  this.beginBatch = (flowBatch) => {
191
204
  flushQueue();
192
- prevChrom = undefined;
205
+ prevChrom = null;
193
206
  super.beginBatch(flowBatch);
194
207
  };
195
208
  }
@@ -2,8 +2,9 @@ export default class FilterTransform extends FlowNode {
2
2
  /**
3
3
  *
4
4
  * @param {import("../../spec/transform.js").FilterParams} params
5
+ * @param {import("../flowNode.js").ParamMediatorProvider} paramMediatorProvider
5
6
  */
6
- constructor(params: import("../../spec/transform.js").FilterParams);
7
+ constructor(params: import("../../spec/transform.js").FilterParams, paramMediatorProvider: import("../flowNode.js").ParamMediatorProvider);
7
8
  params: import("../../spec/transform.js").FilterParams;
8
9
  /** @type {import("../../view/paramMediator.js").ExprRefFunction} */
9
10
  predicate: import("../../view/paramMediator.js").ExprRefFunction;
@@ -1 +1 @@
1
- {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/filter.js"],"names":[],"mappings":"AAEA;IACI;;;OAGG;IACH,oBAFW,OAAO,yBAAyB,EAAE,YAAY,EAQxD;IAJG,uDAAoB;IAEpB,oEAAoE;IACpE,WADW,OAAO,6BAA6B,EAAE,eAAe,CACtC;CAiBjC;qBA7BoB,gBAAgB"}
1
+ {"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/filter.js"],"names":[],"mappings":"AAEA;IACI;;;;OAIG;IACH,oBAHW,OAAO,yBAAyB,EAAE,YAAY,yBAC9C,OAAO,gBAAgB,EAAE,qBAAqB,EASxD;IAJG,uDAAoB;IAEpB,oEAAoE;IACpE,WADW,OAAO,6BAA6B,EAAE,eAAe,CACtC;CAiBjC;qBA/BoB,gBAAgB"}
@@ -4,9 +4,11 @@ export default class FilterTransform extends FlowNode {
4
4
  /**
5
5
  *
6
6
  * @param {import("../../spec/transform.js").FilterParams} params
7
+ * @param {import("../flowNode.js").ParamMediatorProvider} paramMediatorProvider
7
8
  */
8
- constructor(params) {
9
- super();
9
+ constructor(params, paramMediatorProvider) {
10
+ super(paramMediatorProvider);
11
+
10
12
  this.params = params;
11
13
 
12
14
  /** @type {import("../../view/paramMediator.js").ExprRefFunction} */
@@ -1,5 +1,5 @@
1
1
  import { expect, test } from "vitest";
2
- import { processData } from "../flowTestUtils.js";
2
+ import { makeParamMediatorProvider, processData } from "../flowTestUtils.js";
3
3
  import FilterTransform from "./filter.js";
4
4
 
5
5
  test.todo("Implement stub for ParamMediator");
@@ -13,12 +13,8 @@ test("FilterTransform filter rows", () => {
13
13
  expr: "datum.x > 3 && datum.x != 5",
14
14
  };
15
15
 
16
- /* TODO: Enable this test, implement stub for ParamMediator
17
-
18
- const t = new FilterTransform(filterParams);
16
+ const t = new FilterTransform(filterParams, makeParamMediatorProvider());
19
17
  t.initialize();
20
18
 
21
19
  expect(processData(t, data)).toEqual([4, 6].map((x) => ({ x })));
22
-
23
- */
24
20
  });
@@ -2,8 +2,9 @@ export default class FormulaTransform extends FlowNode {
2
2
  /**
3
3
  *
4
4
  * @param {import("../../spec/transform.js").FormulaParams} params
5
+ * @param {import("../flowNode.js").ParamMediatorProvider} paramMediatorProvider
5
6
  */
6
- constructor(params: import("../../spec/transform.js").FormulaParams);
7
+ constructor(params: import("../../spec/transform.js").FormulaParams, paramMediatorProvider: import("../flowNode.js").ParamMediatorProvider);
7
8
  params: import("../../spec/transform.js").FormulaParams;
8
9
  as: string;
9
10
  /** @type {import("../../view/paramMediator.js").ExprRefFunction} */
@@ -1 +1 @@
1
- {"version":3,"file":"formula.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/formula.js"],"names":[],"mappings":"AAEA;IAKI;;;OAGG;IACH,oBAFW,OAAO,yBAAyB,EAAE,aAAa,EAUzD;IANG,wDAAoB;IAEpB,WAAmB;IAEnB,oEAAoE;IACpE,IADW,OAAO,6BAA6B,EAAE,eAAe,CAC7C;CAgB1B;qBAlC2C,gBAAgB"}
1
+ {"version":3,"file":"formula.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/formula.js"],"names":[],"mappings":"AAEA;IAKI;;;;OAIG;IACH,oBAHW,OAAO,yBAAyB,EAAE,aAAa,yBAC/C,OAAO,gBAAgB,EAAE,qBAAqB,EAWxD;IANG,wDAAoB;IAEpB,WAAmB;IAEnB,oEAAoE;IACpE,IADW,OAAO,6BAA6B,EAAE,eAAe,CAC7C;CAgB1B;qBApC2C,gBAAgB"}
@@ -8,9 +8,11 @@ export default class FormulaTransform extends FlowNode {
8
8
  /**
9
9
  *
10
10
  * @param {import("../../spec/transform.js").FormulaParams} params
11
+ * @param {import("../flowNode.js").ParamMediatorProvider} paramMediatorProvider
11
12
  */
12
- constructor(params) {
13
- super();
13
+ constructor(params, paramMediatorProvider) {
14
+ super(paramMediatorProvider);
15
+
14
16
  this.params = params;
15
17
 
16
18
  this.as = params.as;
@@ -1,5 +1,5 @@
1
1
  import { expect, test, test } from "vitest";
2
- import { processData } from "../flowTestUtils.js";
2
+ import { makeParamMediatorProvider, processData } from "../flowTestUtils.js";
3
3
  import FormulaTransform from "./formula.js";
4
4
 
5
5
  test.todo("Implement stub for ParamMediator");
@@ -7,19 +7,19 @@ test.todo("Implement stub for ParamMediator");
7
7
  test("FormulaTransform", () => {
8
8
  const data = [{ a: 2 }, { a: 3 }];
9
9
 
10
- /* TODO: Enable this test, implement stub for ParamMediator
10
+ const t = new FormulaTransform(
11
+ {
12
+ type: "formula",
13
+ expr: "datum.a * 2",
14
+ as: "b",
15
+ },
16
+ makeParamMediatorProvider()
17
+ );
11
18
 
12
- const t = new FormulaTransform({
13
- type: "formula",
14
- expr: "datum.a * 2",
15
- as: "b",
16
- });
17
19
  t.initialize();
18
20
 
19
21
  expect(processData(t, data)).toEqual([
20
22
  { a: 2, b: 4 },
21
23
  { a: 3, b: 6 },
22
24
  ]);
23
-
24
- */
25
25
  });
@@ -1 +1 @@
1
- {"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA8CA;IACI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA2FpD;IAxFG,uBAA0B;IAC1B,oDAAsB;IAItB,6BAA6B;IAC7B,uBADW,CAAC,MAAM,IAAI,CAAC,EAAE,CACM;IAE/B,sCAAsC;IACtC,wCAAgB;IAEhB,iCAA4C;IAC5C,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,QAAU,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,qEAF0B,OAAO,CAE8B;IAE/D,2CAA2C;IAC3C,mBADW,4BAA4B,CACL;IAClC,2CAA2C;IAC3C,iBADW,4BAA4B,CACP;IAEhC,oDAAoD;IACpD,6BAAgC;IAEhC;;;OAGG;IACH,eAFU;QAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,oBAAoB,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAEpF;IAE9B,uBAA+C;IAE/C;;;OAGG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAU,aAAa,KAAE,IAAI,CAAC,EAAE,CAAC,CAEpB;IAEnC;;;;;;OAMG;IACH,yCAFkC,GAAG,KAAK,IAAI,GAEd;IAEhC;;;OAGG;IACH,kDAFkC,GAAG,KAAK,IAAI,GAEL;IAEzC,oFAAoF;IACpF,iBADW,OAAO,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAEzB;;;;OAIG;IACH;gBAF8B,OAAO,wBAAwB,EAAE,iBAAiB;iBAAW,MAAM;OAEnE;IAE9B;;OAEG;IACH,wBAFU,WAAW,CAEkB;IA2C3C;;;OAGG;IACH,2CAFkB,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAaf;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAQb;IAED;;;OAGG;IACH,iCAqDC;IA0DG,uBAOC;IAGD,mCAGE;IAOF,sCAEE;IAGF,iBAAyC;IAW7C;;OAEG;IACH,gBAuBC;IAED,sCA8MC;IAED;;;OAGG;IACH,UAFa,QAAQ,OAAO,CAAC,CA6B5B;IAED,4BA6IC;IAjIe,iCAAoC;IAmIpD;;;OAGG;IACH,kBAHW,MAAM,KACN,MAAM,QAiEhB;IAED;;;;;;;OAOG;IACH,oDAHuB,QAAQ,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAYlF;IAED,sBA6CC;IAED,kBAIC;IAED,iCAOC;IAED,iCASC;IAED,qFAWC;;CACJ;;;;iCA16BY,eAAe,GAAG,YAAY,GAAG,QAAQ,GAAG,gBAAgB;4BAjC7C,uBAAuB;4BA2BP,uBAAuB;qBAZ9C,qBAAqB;wBAIlB,yBAAyB;yCARR,yDAAyD;oBAYvD,oBAAoB;wBAdvC,qBAAqB;oBAXzB,uBAAuB;qBAStB,oBAAoB"}
1
+ {"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA8CA;IACI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA2FpD;IAxFG,uBAA0B;IAC1B,oDAAsB;IAItB,6BAA6B;IAC7B,uBADW,CAAC,MAAM,IAAI,CAAC,EAAE,CACM;IAE/B,sCAAsC;IACtC,wCAAgB;IAEhB,iCAA4C;IAC5C,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,QAAU,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,qEAF0B,OAAO,CAE8B;IAE/D,2CAA2C;IAC3C,mBADW,4BAA4B,CACL;IAClC,2CAA2C;IAC3C,iBADW,4BAA4B,CACP;IAEhC,oDAAoD;IACpD,6BAAgC;IAEhC;;;OAGG;IACH,eAFU;QAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,oBAAoB,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAEpF;IAE9B,uBAA+C;IAE/C;;;OAGG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAU,aAAa,KAAE,IAAI,CAAC,EAAE,CAAC,CAEpB;IAEnC;;;;;;OAMG;IACH,yCAFkC,GAAG,KAAK,IAAI,GAEd;IAEhC;;;OAGG;IACH,kDAFkC,GAAG,KAAK,IAAI,GAEL;IAEzC,oFAAoF;IACpF,iBADW,OAAO,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAEzB;;;;OAIG;IACH;gBAF8B,OAAO,wBAAwB,EAAE,iBAAiB;iBAAW,MAAM;OAEnE;IAE9B;;OAEG;IACH,wBAFU,WAAW,CAEkB;IA2C3C;;;OAGG;IACH,2CAFkB,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAaf;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAQb;IAED;;;OAGG;IACH,iCAqDC;IA0DG,uBAQC;IAGD,mCAGE;IAOF,sCAEE;IAGF,iBAAyC;IAW7C;;OAEG;IACH,gBAuBC;IAED,sCA8MC;IAED;;;OAGG;IACH,UAFa,QAAQ,OAAO,CAAC,CA6B5B;IAED,4BA+IC;IAxHe,iCAAoC;IA0HpD;;;OAGG;IACH,kBAHW,MAAM,KACN,MAAM,QAsEhB;IAED;;;;;;;OAOG;IACH,oDAHuB,QAAQ,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAYlF;IAED,sBA6CC;IAED,kBAIC;IAED,iCAOC;IAED,iCASC;IAED,qFAWC;;CACJ;;;;iCAl7BY,eAAe,GAAG,YAAY,GAAG,QAAQ,GAAG,gBAAgB;4BAjC7C,uBAAuB;4BA2BP,uBAAuB;qBAZ9C,qBAAqB;wBAIlB,yBAAyB;yCARR,yDAAyD;oBAYvD,oBAAoB;wBAdvC,qBAAqB;oBAXzB,uBAAuB;qBAStB,oBAAoB"}
@@ -362,7 +362,8 @@ export default class GenomeSpy {
362
362
  this.viewRoot
363
363
  ? calculateCanvasSize(calculateViewRootSize(this.viewRoot))
364
364
  : { width: undefined, height: undefined },
365
- this.spec.background
365
+ this.spec.background,
366
+ { powerPreference: this.options.powerPreference ?? "default" }
366
367
  );
367
368
 
368
369
  // The initial loading message that is shown until the first frame is rendered
@@ -668,25 +669,31 @@ export default class GenomeSpy {
668
669
  // that would also contain state-related stuff that currently pollute the
669
670
  // GenomeSpy class.
670
671
 
672
+ let lastWheelEvent = performance.now();
673
+
671
674
  /** @param {Event} event */
672
675
  const listener = (event) => {
676
+ const now = performance.now();
677
+ const wheeling = now - lastWheelEvent < 200;
678
+
673
679
  if (event instanceof MouseEvent) {
674
- if (event.type == "mousemove") {
680
+ const rect = canvas.getBoundingClientRect();
681
+ const point = new Point(
682
+ event.clientX - rect.left - canvas.clientLeft,
683
+ event.clientY - rect.top - canvas.clientTop
684
+ );
685
+
686
+ if (event.type == "mousemove" && !wheeling) {
675
687
  this.tooltip.handleMouseMove(event);
676
688
  this._tooltipUpdateRequested = false;
677
689
 
678
690
  if (event.buttons == 0) {
679
691
  // Disable during dragging
680
692
  this.renderPickingFramebuffer();
693
+ this._handlePicking(point.x, point.y);
681
694
  }
682
695
  }
683
696
 
684
- const rect = canvas.getBoundingClientRect();
685
- const point = new Point(
686
- event.clientX - rect.left - canvas.clientLeft,
687
- event.clientY - rect.top - canvas.clientTop
688
- );
689
-
690
697
  /**
691
698
  * @param {MouseEvent} event
692
699
  */
@@ -704,14 +711,10 @@ export default class GenomeSpy {
704
711
  this._wheelInertia.cancel();
705
712
  }
706
713
 
707
- if (event.type == "mousemove") {
708
- this._handlePicking(point.x, point.y);
709
- } else if (
710
- event.type == "mousedown" ||
711
- event.type == "mouseup"
712
- ) {
714
+ if (event.type == "mousedown" || event.type == "mouseup") {
713
715
  this.renderPickingFramebuffer();
714
716
  } else if (event.type == "wheel") {
717
+ lastWheelEvent = now;
715
718
  this._tooltipUpdateRequested = false;
716
719
 
717
720
  const wheelEvent = /** @type {WheelEvent} */ (event);
@@ -830,7 +833,12 @@ export default class GenomeSpy {
830
833
 
831
834
  this.viewRoot.visit((view) => {
832
835
  if (view instanceof UnitView) {
833
- if (view.mark.isPickingParticipant()) {
836
+ if (
837
+ view.mark.isPickingParticipant() &&
838
+ [...view.facetCoords.values()].some((coords) =>
839
+ coords.containsPoint(x, y)
840
+ )
841
+ ) {
834
842
  const accessor = view.mark.encoders.uniqueId.accessor;
835
843
  view.getCollector().visitData((d) => {
836
844
  if (accessor(d) == uniqueId) {