@genome-spy/core 0.76.0 → 0.77.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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bundle/browser-KWU9rWZT.js +123 -0
  3. package/dist/bundle/{esm-BimDEpBb.js → esm-0dYHNV_D.js} +1 -1
  4. package/dist/bundle/{esm-CngqBe45.js → esm-CRMf_I9V.js} +1 -1
  5. package/dist/bundle/esm-CT3ygiMq.js +1084 -0
  6. package/dist/bundle/{esm-D_euN86T.js → esm-CscjKVDc.js} +1 -1
  7. package/dist/bundle/index.es.js +2708 -2601
  8. package/dist/bundle/index.js +91 -83
  9. package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
  10. package/dist/src/data/sources/lazy/bigWigSource.js +31 -11
  11. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts +19 -3
  12. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  13. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +34 -13
  14. package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
  15. package/dist/src/data/transforms/filterScoredLabels.js +3 -2
  16. package/dist/src/embedFactory.d.ts.map +1 -1
  17. package/dist/src/embedFactory.js +2 -0
  18. package/dist/src/genomeSpy/viewContextFactory.d.ts.map +1 -1
  19. package/dist/src/genomeSpy/viewContextFactory.js +1 -0
  20. package/dist/src/genomeSpyBase.d.ts +6 -0
  21. package/dist/src/genomeSpyBase.d.ts.map +1 -1
  22. package/dist/src/genomeSpyBase.js +11 -0
  23. package/dist/src/index.d.ts +1 -0
  24. package/dist/src/index.d.ts.map +1 -1
  25. package/dist/src/index.js +1 -0
  26. package/dist/src/marks/__snapshots__/shaderSnapshot.test.js.snap +2 -2
  27. package/dist/src/marks/mark.d.ts.map +1 -1
  28. package/dist/src/marks/mark.js +0 -6
  29. package/dist/src/marks/rect.vertex.glsl.js +1 -1
  30. package/dist/src/minimal.d.ts +1 -0
  31. package/dist/src/minimal.d.ts.map +1 -1
  32. package/dist/src/minimal.js +1 -0
  33. package/dist/src/paramRuntime/embedParamApi.d.ts +26 -0
  34. package/dist/src/paramRuntime/embedParamApi.d.ts.map +1 -0
  35. package/dist/src/paramRuntime/embedParamApi.js +133 -0
  36. package/dist/src/scales/scaleInteractionController.d.ts +8 -4
  37. package/dist/src/scales/scaleInteractionController.d.ts.map +1 -1
  38. package/dist/src/scales/scaleInteractionController.js +55 -7
  39. package/dist/src/scales/scaleResolution.d.ts +3 -3
  40. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  41. package/dist/src/scales/scaleResolution.js +5 -4
  42. package/dist/src/selection/index.d.ts +8 -0
  43. package/dist/src/selection/index.d.ts.map +1 -0
  44. package/dist/src/selection/index.js +12 -0
  45. package/dist/src/styles/genome-spy.css +8 -0
  46. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  47. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  48. package/dist/src/styles/genome-spy.css.js +8 -0
  49. package/dist/src/types/embedApi.d.ts +54 -0
  50. package/dist/src/types/scaleResolutionApi.d.ts +28 -1
  51. package/dist/src/types/viewContext.d.ts +11 -0
  52. package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
  53. package/dist/src/utils/ui/tooltip.js +22 -0
  54. package/package.json +3 -3
  55. package/dist/bundle/browser-BTgw5ieH.js +0 -126
  56. package/dist/bundle/esm-Bvlm1uVk.js +0 -1015
@@ -1 +1 @@
1
- {"version":3,"file":"bigWigSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/bigWigSource.js"],"names":[],"mappings":"AAQA;;GAEG;AACH;IAOI;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,UAAU,QAC1C,OAAO,uBAAuB,EAAE,OAAO,EAoCjD;IArBG,mDAYC;IA+DL;;;;OAIG;IACH,wBAFW,MAAM,EAAE,iBAqBlB;IAED;;;OAGG;IAEH,uBAJW,MAAM,EAAE,kBACR,MAAM,iBA2BhB;;CACJ;qCAhKoC,+BAA+B"}
1
+ {"version":3,"file":"bigWigSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/bigWigSource.js"],"names":[],"mappings":"AAQA;;GAEG;AACH;IAOI;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,UAAU,QAC1C,OAAO,uBAAuB,EAAE,OAAO,EAoCjD;IArBG,mDAYC;IA+DL;;;;OAIG;IACH,wBAFW,MAAM,EAAE,iBAqBlB;IAED;;;OAGG;IAEH,uBAJW,MAAM,EAAE,kBACR,MAAM,iBAkChB;;CACJ;qCAvKoC,+BAA+B"}
@@ -142,23 +142,30 @@ export default class BigWigSource extends SingleAxisWindowedSource {
142
142
  async loadInterval(interval, reductionLevel) {
143
143
  const scale =
144
144
  1 / 2 / reductionLevel / withoutExprRef(this.params.pixelsPerBin);
145
- const featureChunks = await this.discretizeAndLoad(
146
- interval,
147
- (d, signal) =>
145
+ const featureChunks = await this.discretizeAndLoad(interval, {
146
+ load: (d, signal) =>
148
147
  this.#bbi
149
148
  .getFeatures(d.chrom, d.startPos, d.endPos, {
150
149
  scale,
151
150
  signal,
152
151
  })
153
- .then((features) =>
154
- features.map((f) => ({
155
- chrom: d.chrom,
156
- start: f.start,
157
- end: f.end,
158
- score: f.score,
159
- }))
152
+ .then((features) => mapFeatures(d.chrom, features)),
153
+ loadBatch: (intervals, signal) =>
154
+ this.#bbi
155
+ .getFeaturesMulti(
156
+ intervals.map((d) => ({
157
+ refName: d.chrom,
158
+ start: d.startPos,
159
+ end: d.endPos,
160
+ })),
161
+ { scale, signal }
160
162
  )
161
- );
163
+ .then((featureChunks) =>
164
+ featureChunks.map((features, i) =>
165
+ mapFeatures(intervals[i].chrom, features)
166
+ )
167
+ ),
168
+ });
162
169
 
163
170
  if (featureChunks) {
164
171
  this.publishData(featureChunks);
@@ -176,6 +183,19 @@ function isBigWigSource(params) {
176
183
 
177
184
  registerBuiltInLazyDataSource(isBigWigSource, BigWigSource);
178
185
 
186
+ /**
187
+ * @param {string} chrom
188
+ * @param {import("@gmod/bbi").Feature[]} features
189
+ */
190
+ function mapFeatures(chrom, features) {
191
+ return features.map((f) => ({
192
+ chrom,
193
+ start: f.start,
194
+ end: f.end,
195
+ score: f.score,
196
+ }));
197
+ }
198
+
179
199
  /**
180
200
  * @param {number[]} domain
181
201
  * @param {number} widthInPixels view width in pixels
@@ -1,3 +1,13 @@
1
+ /**
2
+ * @template T
3
+ * @typedef {(discreteInterval: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval, signal: AbortSignal) => Promise<T>} DiscreteIntervalLoader
4
+ */
5
+ /**
6
+ * @template T
7
+ * @typedef {object} DiscreteIntervalLoaders
8
+ * @prop {DiscreteIntervalLoader<T>} load
9
+ * @prop {(discreteIntervals: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval[], signal: AbortSignal) => Promise<T[]>} [loadBatch]
10
+ */
1
11
  /**
2
12
  * Divides the domain into windows and loads the data for one or two consecutive windows
3
13
  * that cover the visible interval.
@@ -36,15 +46,16 @@ export default class SingleAxisWindowedSource extends SingleAxisLazySource {
36
46
  protected reloadLastDomain(): void;
37
47
  /**
38
48
  * Splits the interval into discrete chromosomal intervals – one for each chromosome –
39
- * and loads the data for each of them. Handles abort signals and errors.
49
+ * and loads the data using a batched loader when available. Handles abort signals
50
+ * and errors.
40
51
  *
41
52
  * @param {number[]} interval
42
- * @param {(discreteInteval: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval, signal: AbortSignal) => Promise<T>} loader
53
+ * @param {DiscreteIntervalLoader<T> | DiscreteIntervalLoaders<T>} loader
43
54
  * @return {Promise<T[]>}
44
55
  * @template T
45
56
  * @protected
46
57
  */
47
- protected discretizeAndLoad<T>(interval: number[], loader: (discreteInteval: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval, signal: AbortSignal) => Promise<T>): Promise<T[]>;
58
+ protected discretizeAndLoad<T>(interval: number[], loader: DiscreteIntervalLoader<T> | DiscreteIntervalLoaders<T>): Promise<T[]>;
48
59
  /**
49
60
  *
50
61
  * @param {number[]} interval Domain
@@ -55,5 +66,10 @@ export default class SingleAxisWindowedSource extends SingleAxisLazySource {
55
66
  protected callIfWindowsChanged(interval: number[], windowSize: number, callback: (arg0: number[]) => void): void;
56
67
  #private;
57
68
  }
69
+ export type DiscreteIntervalLoader<T> = (discreteInterval: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval, signal: AbortSignal) => Promise<T>;
70
+ export type DiscreteIntervalLoaders<T> = {
71
+ load: DiscreteIntervalLoader<T>;
72
+ loadBatch?: (discreteIntervals: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval[], signal: AbortSignal) => Promise<T[]>;
73
+ };
58
74
  import SingleAxisLazySource from "./singleAxisLazySource.js";
59
75
  //# sourceMappingURL=singleAxisWindowedSource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"singleAxisWindowedSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/singleAxisWindowedSource.js"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH;IAWI;;;OAGG;IACH,kBAHU;QAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,4BAA4B,EAAE,OAAO,CAAA;KAAC,CAGvE;IAEP;;;OAGG;IACH,0CAHW,OAAO,uBAAuB,EAAE,aAAa,QAqBvD;IAED;;;;OAIG;IACH,wBAFW,MAAM,EAAE,QAqBlB;IAeD;;;;;OAKG;IACH,iCAHW,MAAM,EAAE,iBAKlB;IArBD;;OAEG;IACH,mCAQC;IAyBD;;;;;;;;;OASG;IACH,4BAHa,CAAC,YAHH,MAAM,EAAE,UACR,CAAC,eAAe,EAAE,OAAO,mCAAmC,EAAE,0BAA0B,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAC3H,OAAO,CAAC,CAAC,EAAE,CAAC,CAyCvB;IAED;;;;;;OAMG;IACH,yCALW,MAAM,EAAE,cACR,MAAM,YACN,CAAS,IAAQ,EAAR,MAAM,EAAE,KAAE,IAAI,QAyBjC;;CACJ;iCA9LgC,2BAA2B"}
1
+ {"version":3,"file":"singleAxisWindowedSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/singleAxisWindowedSource.js"],"names":[],"mappings":"AAIA;;;GAGG;AAEH;;;;;GAKG;AAEH;;;;;GAKG;AACH;IAWI;;;OAGG;IACH,kBAHU;QAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,4BAA4B,EAAE,OAAO,CAAA;KAAC,CAGvE;IAEP;;;OAGG;IACH,0CAHW,OAAO,uBAAuB,EAAE,aAAa,QAqBvD;IAED;;;;OAIG;IACH,wBAFW,MAAM,EAAE,QAqBlB;IAeD;;;;;OAKG;IACH,iCAHW,MAAM,EAAE,iBAKlB;IArBD;;OAEG;IACH,mCAQC;IAyBD;;;;;;;;;;OAUG;IACH,4BAHa,CAAC,YAHH,MAAM,EAAE,UACR,sBAAsB,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC,CAAC,CAAC,GACrD,OAAO,CAAC,CAAC,EAAE,CAAC,CAiDvB;IAED;;;;;;OAMG;IACH,yCALW,MAAM,EAAE,cACR,MAAM,YACN,CAAS,IAAQ,EAAR,MAAM,EAAE,KAAE,IAAI,QAyBjC;;CACJ;mCAhNY,CAAC,IACD,CAAC,gBAAgB,EAAE,OAAO,mCAAmC,EAAE,0BAA0B,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;oCAI7H,CAAC;UAEJ,sBAAsB,CAAC,CAAC,CAAC;gBACzB,CAAC,iBAAiB,EAAE,OAAO,mCAAmC,EAAE,0BAA0B,EAAE,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC;;iCAX3G,2BAA2B"}
@@ -2,6 +2,18 @@ import { withoutExprRef } from "../../../paramRuntime/paramUtils.js";
2
2
  import { debounce } from "../../../utils/debounce.js";
3
3
  import SingleAxisLazySource from "./singleAxisLazySource.js";
4
4
 
5
+ /**
6
+ * @template T
7
+ * @typedef {(discreteInterval: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval, signal: AbortSignal) => Promise<T>} DiscreteIntervalLoader
8
+ */
9
+
10
+ /**
11
+ * @template T
12
+ * @typedef {object} DiscreteIntervalLoaders
13
+ * @prop {DiscreteIntervalLoader<T>} load
14
+ * @prop {(discreteIntervals: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval[], signal: AbortSignal) => Promise<T[]>} [loadBatch]
15
+ */
16
+
5
17
  /**
6
18
  * Divides the domain into windows and loads the data for one or two consecutive windows
7
19
  * that cover the visible interval.
@@ -113,10 +125,11 @@ export default class SingleAxisWindowedSource extends SingleAxisLazySource {
113
125
 
114
126
  /**
115
127
  * Splits the interval into discrete chromosomal intervals – one for each chromosome –
116
- * and loads the data for each of them. Handles abort signals and errors.
128
+ * and loads the data using a batched loader when available. Handles abort signals
129
+ * and errors.
117
130
  *
118
131
  * @param {number[]} interval
119
- * @param {(discreteInteval: import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval, signal: AbortSignal) => Promise<T>} loader
132
+ * @param {DiscreteIntervalLoader<T> | DiscreteIntervalLoaders<T>} loader
120
133
  * @return {Promise<T[]>}
121
134
  * @template T
122
135
  * @protected
@@ -130,21 +143,29 @@ export default class SingleAxisWindowedSource extends SingleAxisLazySource {
130
143
  this.#abortController = new AbortController();
131
144
  const signal = this.#abortController.signal;
132
145
 
133
- // GMOD libraries expect a single chromosome/sequence for each request.
134
- // Thus, we split the interval into discrete intervals representing
135
- // individual chromosomes and load the data for each of them separately
136
- // but in parallel.
146
+ // Lazy sources load data using chromosome coordinates. The continuous
147
+ // scale domain must be split before it can be passed to the source.
137
148
  const discreteChromosomeIntervals =
138
149
  this.genome.continuousToDiscreteChromosomeIntervals(interval);
139
150
 
151
+ const loaders = typeof loader == "function" ? { load: loader } : loader;
152
+
140
153
  try {
141
- const resultByChrom = await Promise.all(
142
- discreteChromosomeIntervals.map(
143
- async (
144
- /** @type {import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval} */ d
145
- ) => loader(d, signal)
146
- )
147
- );
154
+ const resultByChrom = loaders.loadBatch
155
+ ? await loaders.loadBatch(discreteChromosomeIntervals, signal)
156
+ : await Promise.all(
157
+ discreteChromosomeIntervals.map(
158
+ async (
159
+ /** @type {import("@genome-spy/core/genome/genome.js").DiscreteChromosomeInterval} */ d
160
+ ) => loaders.load(d, signal)
161
+ )
162
+ );
163
+
164
+ if (resultByChrom.length !== discreteChromosomeIntervals.length) {
165
+ throw new Error(
166
+ "Batched lazy loader must return one chunk per interval."
167
+ );
168
+ }
148
169
 
149
170
  if (!signal.aborted) {
150
171
  this.setLoadingStatus("complete");
@@ -1 +1 @@
1
- {"version":3,"file":"filterScoredLabels.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/filterScoredLabels.js"],"names":[],"mappings":"AAOA;IAcI;;;;OAIG;IACH,oBAHW,OAAO,yBAAyB,EAAE,wBAAwB,QAC1D,OAAO,oBAAoB,EAAE,OAAO,EAkD9C;IA9DD;;;;OAIG;IACH,kDAEC;IAUG,mEAAoB;IAEpB,oBAAoB;IACpB,OADW,GAAG,EAAE,CACD;IAEf,mBAAoC;IAMpC,sDAA8C;IAC9C,oDAAgE;IAChE,wDAAuD;IACvD,sDAAmD;IACnD,mDAA6C;IAC7C,mDAA6C;IAC7C,gCAAgC;IAChC,cADW,CAAS,IAAG,EAAH,GAAG,KAAE,GAAG,CAGd;IACd,gBAAuC;IAEvC,uCAAuC;IACvC,iBADW,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CACH;IAEhC,8DAAuD;IAIvD,qBAAuE;IA8B3E,4BAsEC;IAKG,sBAAuB;CAU9B;sBAzKqB,gBAAgB;2BAFX,+BAA+B"}
1
+ {"version":3,"file":"filterScoredLabels.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/filterScoredLabels.js"],"names":[],"mappings":"AAOA;IAcI;;;;OAIG;IACH,oBAHW,OAAO,yBAAyB,EAAE,wBAAwB,QAC1D,OAAO,oBAAoB,EAAE,OAAO,EAmD9C;IA/DD;;;;OAIG;IACH,kDAEC;IAUG,mEAAoB;IAEpB,oBAAoB;IACpB,OADW,GAAG,EAAE,CACD;IAEf,mBAAoC;IAMpC,sDAA8C;IAC9C,oDAAgE;IAChE,wDAAuD;IACvD,sDAAmD;IACnD,mDAA6C;IAC7C,mDAA6C;IAC7C,gCAAgC;IAChC,cADW,CAAS,IAAG,EAAH,GAAG,KAAE,GAAG,CAGd;IACd,gBAAuC;IAEvC,uCAAuC;IACvC,iBADW,GAAG,CAAC,GAAG,EAAE,cAAc,CAAC,CACH;IAEhC,8DAAuD;IAIvD,qBAAuE;IA+B3E,4BAsEC;IAKG,sBAAuB;CAU9B;sBA1KqB,gBAAgB;2BAFX,+BAA+B"}
@@ -59,8 +59,9 @@ export default class FilterScoredLabelsTransform extends Transform {
59
59
  const callback = () => this._filterAndPropagate();
60
60
  this.schedule = () => view.context.animator.requestTransition(callback);
61
61
 
62
- // Propagate when the domain changes
63
- const domainListener = () => this.schedule();
62
+ // Propagate immediately when the domain changes so inertial zoom frames
63
+ // render with labels computed for the current scale domain.
64
+ const domainListener = () => this._filterAndPropagate();
64
65
  this.resolution.addEventListener("domain", domainListener);
65
66
  this.registerDisposer(() =>
66
67
  this.resolution.removeEventListener("domain", domainListener)
@@ -1 +1 @@
1
- {"version":3,"file":"embedFactory.d.ts","sourceRoot":"","sources":["../../src/embedFactory.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH,uCAHW,KAAK,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,gBAAgB,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,qBAAqB,EAAE,YAAY,KAAK,OAAO,gBAAgB,EAAE,OAAO,GAC7J,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE,OAAO,gBAAgB,EAAE,QAAQ,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,qBAAqB,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,qBAAqB,EAAE,WAAW,CAAC,CAmFpM;AAaD;;;;;GAKG;AACH,8BAFW,MAAM,gBAmBhB"}
1
+ {"version":3,"file":"embedFactory.d.ts","sourceRoot":"","sources":["../../src/embedFactory.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH,uCAHW,KAAK,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,gBAAgB,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,OAAO,qBAAqB,EAAE,YAAY,KAAK,OAAO,gBAAgB,EAAE,OAAO,GAC7J,CAAC,EAAE,EAAE,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE,OAAO,gBAAgB,EAAE,QAAQ,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,qBAAqB,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,qBAAqB,EAAE,WAAW,CAAC,CAqFpM;AAaD;;;;;GAKG;AACH,8BAFW,MAAM,gBAmBhB"}
@@ -79,6 +79,8 @@ export function createEmbed(GenomeSpy) {
79
79
  return genomeSpy.getNamedScaleResolutions().get(name);
80
80
  },
81
81
 
82
+ getParam: genomeSpy.getParam.bind(genomeSpy),
83
+
82
84
  awaitVisibleLazyData:
83
85
  genomeSpy.awaitVisibleLazyData.bind(genomeSpy),
84
86
  getRenderedBounds: genomeSpy.getRenderedBounds.bind(genomeSpy),
@@ -1 +1 @@
1
- {"version":3,"file":"viewContextFactory.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/viewContextFactory.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;GAUG;AACH,2CANW,OAAO,CAAC,WAAW,CAAC,GAAG;IAC7B,6BAA6B,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,QAAQ,GAAG,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,OAAO,0BAA0B,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,iBAAiB,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,QAAQ,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,yBAAyB,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAA;IACrb,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,GACS,WAAW,CAwEvB;0BApFY,OAAO,yBAAyB,EAAE,OAAO"}
1
+ {"version":3,"file":"viewContextFactory.d.ts","sourceRoot":"","sources":["../../../src/genomeSpy/viewContextFactory.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;GAUG;AACH,2CANW,OAAO,CAAC,WAAW,CAAC,GAAG;IAC7B,6BAA6B,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,QAAQ,GAAG,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,EAAE,OAAO,0BAA0B,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,OAAO,iBAAiB,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,iBAAiB,EAAE,QAAQ,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,yBAAyB,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,iBAAiB,EAAE,OAAO,CAAC,CAAA;IACrb,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B,GACS,WAAW,CAyEvB;0BArFY,OAAO,yBAAyB,EAAE,OAAO"}
@@ -60,6 +60,7 @@ export function createViewContext(options) {
60
60
  /** @type {(keyof ViewContext)[]} */
61
61
  const methodNames = [
62
62
  "requestLayoutReflow",
63
+ "renderImmediately",
63
64
  "updateTooltip",
64
65
  "getNamedDataFromProvider",
65
66
  "getCurrentHover",
@@ -53,6 +53,12 @@ export default class GenomeSpy {
53
53
  * @param {any[]} data
54
54
  */
55
55
  updateNamedData(name: string, data: any[]): void;
56
+ /**
57
+ * Returns a handle for a named parameter.
58
+ *
59
+ * @param {string} name
60
+ */
61
+ getParam(name: string): import("./types/embedApi.js").ParamApi<import("./types/embedApi.js").ParamValue>;
56
62
  /**
57
63
  * @param {string} type
58
64
  * @param {(event: any) => void} listener
@@ -1 +1 @@
1
- {"version":3,"file":"genomeSpyBase.d.ts","sourceRoot":"","sources":["../../src/genomeSpyBase.js"],"names":[],"mappings":"AA8CA;;;GAGG;AAEH;IAoBI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA0CpD;IAvCG,uBAA0B;IAC1B,oDAAsB;IAItB,sCAAsC;IACtC,wCAAgB;IAEhB,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,CAAC,CAAS,IAAM,EAAN,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,yBAFU,CAAC,IAAI,qEAAM,KAAK,OAAO,CAE8B;IAE/D,oFAAoF;IACpF,iBADW,MAAM,CAAC,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,8EAAyB;IAIzB,YAAkC;IAatC;;;OAGG;IACH,oCAFW,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAYf;IAED;;;OAGG;IACH,uBAHW,MAAM,YACN,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,QAI9B;IAED;;;OAGG;IACH,0BAHW,MAAM,YACN,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,QAI9B;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAMb;IAmEG,iDAAsB;IAQ1B;;OAEG;IACH,gBAqBC;IAyND;;;OAGG;IACH,UAFa,OAAO,CAAC,OAAO,CAAC,CAyC5B;IAED,2CAiBC;IAED;;;;;OAKG;IACH,8BAFW,WAAW,iBAerB;IAED;;;;;;;OAOG;IACH,cAFa,CAAC,SAFH,CAAC,cACD,CAAS,IAAC,EAAD,CAAC,KAAE,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAKlF;IAED;;;;;;;;OAQG;IACH,4BANW,MAAM,kBACN,MAAM,qBACN,MAAM,eACN,MAAM,UAuBhB;IAED;;;MAEC;IAED;eACwB,MAAM,GAAG,SAAS;gBAAU,MAAM,GAAG,SAAS;MAcrE;IAED,sBAGC;IAED,kBAEC;IAED,iCAEC;IAED,oEAYC;IAED,uFAWC;;CACJ;;;;iCA/oBY,eAAe,GAAG,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB;4BAtBnC,uBAAuB;qBAP9C,qBAAqB;wBAElB,yBAAyB;qBAL5B,oBAAoB"}
1
+ {"version":3,"file":"genomeSpyBase.d.ts","sourceRoot":"","sources":["../../src/genomeSpyBase.js"],"names":[],"mappings":"AA+CA;;;GAGG;AAEH;IAoBI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA0CpD;IAvCG,uBAA0B;IAC1B,oDAAsB;IAItB,sCAAsC;IACtC,wCAAgB;IAEhB,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,CAAC,CAAS,IAAM,EAAN,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,yBAFU,CAAC,IAAI,qEAAM,KAAK,OAAO,CAE8B;IAE/D,oFAAoF;IACpF,iBADW,MAAM,CAAC,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,8EAAyB;IAIzB,YAAkC;IAatC;;;OAGG;IACH,oCAFW,CAAC,IAAI,EAAE,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAYf;IAED;;;;OAIG;IACH,eAFW,MAAM,oFAIhB;IAED;;;OAGG;IACH,uBAHW,MAAM,YACN,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,QAI9B;IAED;;;OAGG;IACH,0BAHW,MAAM,YACN,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,QAI9B;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAMb;IAmEG,iDAAsB;IAQ1B;;OAEG;IACH,gBAqBC;IA0ND;;;OAGG;IACH,UAFa,OAAO,CAAC,OAAO,CAAC,CAyC5B;IAED,2CAiBC;IAED;;;;;OAKG;IACH,8BAFW,WAAW,iBAerB;IAED;;;;;;;OAOG;IACH,cAFa,CAAC,SAFH,CAAC,cACD,CAAS,IAAC,EAAD,CAAC,KAAE,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAKlF;IAED;;;;;;;;OAQG;IACH,4BANW,MAAM,kBACN,MAAM,qBACN,MAAM,eACN,MAAM,UAuBhB;IAED;;;MAEC;IAED;eACwB,MAAM,GAAG,SAAS;gBAAU,MAAM,GAAG,SAAS;MAcrE;IAED,sBAGC;IAED,kBAEC;IAED,iCAEC;IAED,oEAYC;IAED,uFAWC;;CACJ;;;;iCAzpBY,eAAe,GAAG,QAAQ,GAAG,gBAAgB,GAAG,kBAAkB;4BAvBnC,uBAAuB;qBAP9C,qBAAqB;wBAElB,yBAAyB;qBAL5B,oBAAoB"}
@@ -31,6 +31,7 @@ import { createViewContext } from "./genomeSpy/viewContextFactory.js";
31
31
  import { prepareViewHierarchy } from "./genomeSpy/headlessBootstrap.js";
32
32
  import { exportCanvas } from "./genomeSpy/canvasExport.js";
33
33
  import { validateSelectorConstraints } from "./view/viewSelectors.js";
34
+ import { resolveEmbedParam } from "./paramRuntime/embedParamApi.js";
34
35
  import SingleAxisWindowedSource from "./data/sources/lazy/singleAxisWindowedSource.js";
35
36
  import { ensureAssembliesForView } from "./genome/assemblyPreflight.js";
36
37
  import { resolveRootGenomeConfig } from "./genome/rootGenomeConfig.js";
@@ -171,6 +172,15 @@ export default class GenomeSpy {
171
172
  this.animator.requestRender();
172
173
  }
173
174
 
175
+ /**
176
+ * Returns a handle for a named parameter.
177
+ *
178
+ * @param {string} name
179
+ */
180
+ getParam(name) {
181
+ return resolveEmbedParam(this.viewRoot, name);
182
+ }
183
+
174
184
  /**
175
185
  * @param {string} type
176
186
  * @param {(event: any) => void} listener
@@ -360,6 +370,7 @@ export default class GenomeSpy {
360
370
  this.#extraBroadcastListeners.add(type, listener),
361
371
  removeBroadcastListener: (type, listener) =>
362
372
  this.#extraBroadcastListeners.remove(type, listener),
373
+ renderImmediately: this.renderAll.bind(this),
363
374
  isViewConfiguredVisible: this.viewVisibilityPredicate,
364
375
  isViewSpec: (spec) => this.viewFactory.isViewSpec(spec),
365
376
  getBaseConfig: () => baseConfig,
@@ -1,4 +1,5 @@
1
1
  export const embed: (el: HTMLElement | string, spec: import("./spec/root.js").RootSpec | string, options?: import("./types/embedApi.js").EmbedOptions) => Promise<import("./types/embedApi.js").EmbedResult>;
2
+ export { intervalSelection } from "./selection/index.js";
2
3
  import GenomeSpy from "./genomeSpy.js";
3
4
  import { html } from "lit";
4
5
  import icon from "./img/bowtie.svg";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":"AAWA,6MAA4C;sBAPtB,gBAAgB;qBAJjB,KAAK;iBAKT,kBAAkB;oBACf,6BAA6B;yBACX,mBAAmB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":"AAWA,6MAA4C;;sBAPtB,gBAAgB;qBAJjB,KAAK;iBAKT,kBAAkB;oBACf,6BAA6B;yBACX,mBAAmB"}
package/dist/src/index.js CHANGED
@@ -12,3 +12,4 @@ export { GenomeSpy, html, icon, favIcon };
12
12
  export const embed = createEmbed(GenomeSpy);
13
13
 
14
14
  export { loadSpec };
15
+ export { intervalSelection } from "./selection/index.js";
@@ -5488,8 +5488,8 @@ void main(void) {
5488
5488
 
5489
5489
  vec2 size = pos2 - pos1;
5490
5490
 
5491
- if (size.x <= 0.0 || size.y <= 0.0) {
5492
- // Early exit. May increase performance or not...
5491
+ if (size.x < 0.0 || size.y < 0.0) {
5492
+ // Keep zero-sized rects alive so min-size clamping can stabilize them.
5493
5493
  gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
5494
5494
  return;
5495
5495
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mark.d.ts","sourceRoot":"","sources":["../../../src/marks/mark.js"],"names":[],"mappings":"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"}
@@ -1118,12 +1118,6 @@ export default class Mark {
1118
1118
  }
1119
1119
 
1120
1120
  if (this.bufferInfo) {
1121
- // A hack to prevent WebGL: INVALID_OPERATION: drawArrays: no buffer is bound to enabled attribute
1122
- // TODO: Consider using bufferSubData or DYNAMIC_DRAW etc...
1123
- for (let i = 0; i < 8; i++) {
1124
- gl.disableVertexAttribArray(i);
1125
- }
1126
-
1127
1121
  Object.values(this.bufferInfo.attribs).forEach((attribInfo) =>
1128
1122
  this.gl.deleteBuffer(attribInfo.buffer)
1129
1123
  );
@@ -1,2 +1,2 @@
1
- const shader = "flat out lowp vec4 vFillColor;flat out lowp vec4 vStrokeColor;flat out float vHalfStrokeWidth;flat out vec4 vCornerRadii;\n#if defined(ROUNDED_CORNERS) || defined(STROKED) || defined(SHADOW)\nout vec2 vPosInPixels;\n#endif\nflat out vec2 vHalfSizeInPixels;/***Adjusts the vertex position to ensure that the rectangle is at least `minSpan`*wide or high. Returns a value that reflects the amount of clamping and can be*used to adjust the opacity of the rectangle.**pos: vertex position*frac: vertex position within the rectangle,[0,1]*size: width or height of the rectangle*minSize: minimum width or height of the rectangle*/float clampMinSize(inout float pos,float frac,float size,float minSize){if(minSize>0.0&&size<minSize){pos+=(frac-0.5)*(minSize-size);return size/minSize;}return 1.0;}void sort(inout float a,inout float b){if(a>b){float tmp=b;b=a;a=tmp;}}/***The vertex position wrt the rectangle specified by(x,x2,y,y2).*[0,0]=[x,y],[1,1]=[x2,y2].*The x or y component may contain fractional values if the rectangle*have been tessellated.*/vec2 getVertexPos(){int index=gl_VertexID % 6;return vec2(index==0||index==1||index==3 ? 0.0 : 1.0,index==0||index==1||index==2 ? 0.0 : 1.0);}void main(void){vec2 frac=getVertexPos();vec2 normalizedMinSize=vec2(uMinWidth,uMinHeight)/uViewportSize;vec4 cornerRadii=vec4(uCornerRadiusTopRight,uCornerRadiusBottomRight,uCornerRadiusTopLeft,uCornerRadiusBottomLeft);float x=getScaled_x();float x2=getScaled_x2();float y=getScaled_y();float y2=getScaled_y2();sort(x,x2);sort(y,y2);float clampMargin=1.0;vec2 pos1=vec2(clamp(x,0.0-clampMargin,1.0+clampMargin),y);vec2 pos2=vec2(clamp(x2,0.0-clampMargin,1.0+clampMargin),y2);vec2 size=pos2-pos1;if(size.x<=0.0||size.y<=0.0){gl_Position=vec4(0.0,0.0,0.0,1.0);return;}vec2 pos=pos1+frac*size;size.y*=getSampleFacetHeight(pos);float opaFactor=uViewOpacity*max(uMinOpacity,clampMinSize(pos.x,frac.x,size.x,normalizedMinSize.x)*clampMinSize(pos.y,frac.y,size.y,normalizedMinSize.y));size=max(size,normalizedMinSize);pos=applySampleFacet(pos);\n#if defined(ROUNDED_CORNERS) || defined(STROKED) || defined(SHADOW)\nfloat aaPadding=1.0/uDevicePixelRatio;float shadowPadding=uShadowBlur+max(abs(uShadowOffsetX),abs(uShadowOffsetY));float strokeWidth=getScaled_strokeWidth();float strokeOpacity=getScaled_strokeOpacity()*opaFactor;vec2 centeredFrac=frac-0.5;vec2 expand=centeredFrac*(strokeWidth+aaPadding+shadowPadding*2.0)/uViewportSize;pos+=expand;vec2 sizeInPixels=size*uViewportSize;vPosInPixels=(centeredFrac+expand/size)*sizeInPixels;vHalfSizeInPixels=sizeInPixels/2.0;vCornerRadii=min(cornerRadii,min(vHalfSizeInPixels.x,vHalfSizeInPixels.y));vHalfStrokeWidth=strokeWidth/2.0;vStrokeColor=vec4(getScaled_stroke()*strokeOpacity,strokeOpacity);\n#endif\ngl_Position=unitToNdc(pos);float fillOpacity=getScaled_fillOpacity()*opaFactor;vFillColor=vec4(getScaled_fill()*fillOpacity,fillOpacity);setupPicking();}";
1
+ const shader = "flat out lowp vec4 vFillColor;flat out lowp vec4 vStrokeColor;flat out float vHalfStrokeWidth;flat out vec4 vCornerRadii;\n#if defined(ROUNDED_CORNERS) || defined(STROKED) || defined(SHADOW)\nout vec2 vPosInPixels;\n#endif\nflat out vec2 vHalfSizeInPixels;/***Adjusts the vertex position to ensure that the rectangle is at least `minSpan`*wide or high. Returns a value that reflects the amount of clamping and can be*used to adjust the opacity of the rectangle.**pos: vertex position*frac: vertex position within the rectangle,[0,1]*size: width or height of the rectangle*minSize: minimum width or height of the rectangle*/float clampMinSize(inout float pos,float frac,float size,float minSize){if(minSize>0.0&&size<minSize){pos+=(frac-0.5)*(minSize-size);return size/minSize;}return 1.0;}void sort(inout float a,inout float b){if(a>b){float tmp=b;b=a;a=tmp;}}/***The vertex position wrt the rectangle specified by(x,x2,y,y2).*[0,0]=[x,y],[1,1]=[x2,y2].*The x or y component may contain fractional values if the rectangle*have been tessellated.*/vec2 getVertexPos(){int index=gl_VertexID % 6;return vec2(index==0||index==1||index==3 ? 0.0 : 1.0,index==0||index==1||index==2 ? 0.0 : 1.0);}void main(void){vec2 frac=getVertexPos();vec2 normalizedMinSize=vec2(uMinWidth,uMinHeight)/uViewportSize;vec4 cornerRadii=vec4(uCornerRadiusTopRight,uCornerRadiusBottomRight,uCornerRadiusTopLeft,uCornerRadiusBottomLeft);float x=getScaled_x();float x2=getScaled_x2();float y=getScaled_y();float y2=getScaled_y2();sort(x,x2);sort(y,y2);float clampMargin=1.0;vec2 pos1=vec2(clamp(x,0.0-clampMargin,1.0+clampMargin),y);vec2 pos2=vec2(clamp(x2,0.0-clampMargin,1.0+clampMargin),y2);vec2 size=pos2-pos1;if(size.x<0.0||size.y<0.0){gl_Position=vec4(0.0,0.0,0.0,1.0);return;}vec2 pos=pos1+frac*size;size.y*=getSampleFacetHeight(pos);float opaFactor=uViewOpacity*max(uMinOpacity,clampMinSize(pos.x,frac.x,size.x,normalizedMinSize.x)*clampMinSize(pos.y,frac.y,size.y,normalizedMinSize.y));size=max(size,normalizedMinSize);pos=applySampleFacet(pos);\n#if defined(ROUNDED_CORNERS) || defined(STROKED) || defined(SHADOW)\nfloat aaPadding=1.0/uDevicePixelRatio;float shadowPadding=uShadowBlur+max(abs(uShadowOffsetX),abs(uShadowOffsetY));float strokeWidth=getScaled_strokeWidth();float strokeOpacity=getScaled_strokeOpacity()*opaFactor;vec2 centeredFrac=frac-0.5;vec2 expand=centeredFrac*(strokeWidth+aaPadding+shadowPadding*2.0)/uViewportSize;pos+=expand;vec2 sizeInPixels=size*uViewportSize;vPosInPixels=(centeredFrac+expand/size)*sizeInPixels;vHalfSizeInPixels=sizeInPixels/2.0;vCornerRadii=min(cornerRadii,min(vHalfSizeInPixels.x,vHalfSizeInPixels.y));vHalfStrokeWidth=strokeWidth/2.0;vStrokeColor=vec4(getScaled_stroke()*strokeOpacity,strokeOpacity);\n#endif\ngl_Position=unitToNdc(pos);float fillOpacity=getScaled_fillOpacity()*opaFactor;vFillColor=vec4(getScaled_fill()*fillOpacity,fillOpacity);setupPicking();}";
2
2
  export default shader;
@@ -1,4 +1,5 @@
1
1
  export const embed: (el: HTMLElement | string, spec: import("./spec/root.js").RootSpec | string, options?: import("./types/embedApi.js").EmbedOptions) => Promise<import("./types/embedApi.js").EmbedResult>;
2
+ export { intervalSelection } from "./selection/index.js";
2
3
  import GenomeSpy from "./genomeSpyBase.js";
3
4
  import { html } from "lit";
4
5
  import icon from "./img/bowtie.svg";
@@ -1 +1 @@
1
- {"version":3,"file":"minimal.d.ts","sourceRoot":"","sources":["../../src/minimal.js"],"names":[],"mappings":"AAmBA,6MAA4C;sBARtB,oBAAoB;qBAJrB,KAAK;iBAKT,kBAAkB;oBACf,6BAA6B;yBACX,mBAAmB"}
1
+ {"version":3,"file":"minimal.d.ts","sourceRoot":"","sources":["../../src/minimal.js"],"names":[],"mappings":"AAmBA,6MAA4C;;sBARtB,oBAAoB;qBAJrB,KAAK;iBAKT,kBAAkB;oBACf,6BAA6B;yBACX,mBAAmB"}
@@ -20,3 +20,4 @@ export { GenomeSpy, html, icon, favIcon };
20
20
  export const embed = createEmbed(GenomeSpy);
21
21
 
22
22
  export { loadSpec };
23
+ export { intervalSelection } from "./selection/index.js";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @typedef {import("../view/view.js").default} View
3
+ * @typedef {import("../spec/parameter.js").Parameter} Parameter
4
+ * @typedef {import("../types/embedApi.js").ParamApi} ParamApi
5
+ */
6
+ /**
7
+ * Returns a parameter handle for an explicit parameter exposed by the embed API.
8
+ *
9
+ * Current limitations:
10
+ *
11
+ * - Parameters are addressed by name only. Independent same-name parameters
12
+ * throw an ambiguity error.
13
+ * - Computed `expr` parameters are readable but cannot be written.
14
+ * - Point selection parameters are readable but cannot be written through this
15
+ * API because valid values require GenomeSpy-generated datum ids.
16
+ * - Projected selections are not supported.
17
+ *
18
+ * @param {View} root
19
+ * @param {string} name
20
+ * @returns {ParamApi}
21
+ */
22
+ export function resolveEmbedParam(root: View, name: string): ParamApi;
23
+ export type View = import("../view/view.js").default;
24
+ export type Parameter = import("../spec/parameter.js").Parameter;
25
+ export type ParamApi = import("../types/embedApi.js").ParamApi;
26
+ //# sourceMappingURL=embedParamApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedParamApi.d.ts","sourceRoot":"","sources":["../../../src/paramRuntime/embedParamApi.js"],"names":[],"mappings":"AAKA;;;;GAIG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,wCAJW,IAAI,QACJ,MAAM,GACJ,QAAQ,CA8DpB;mBAjFY,OAAO,iBAAiB,EAAE,OAAO;wBACjC,OAAO,sBAAsB,EAAE,SAAS;uBACxC,OAAO,sBAAsB,EAAE,QAAQ"}
@@ -0,0 +1,133 @@
1
+ import {
2
+ asSelectionConfig,
3
+ isPointSelectionConfig,
4
+ } from "../selection/selection.js";
5
+
6
+ /**
7
+ * @typedef {import("../view/view.js").default} View
8
+ * @typedef {import("../spec/parameter.js").Parameter} Parameter
9
+ * @typedef {import("../types/embedApi.js").ParamApi} ParamApi
10
+ */
11
+
12
+ /**
13
+ * Returns a parameter handle for an explicit parameter exposed by the embed API.
14
+ *
15
+ * Current limitations:
16
+ *
17
+ * - Parameters are addressed by name only. Independent same-name parameters
18
+ * throw an ambiguity error.
19
+ * - Computed `expr` parameters are readable but cannot be written.
20
+ * - Point selection parameters are readable but cannot be written through this
21
+ * API because valid values require GenomeSpy-generated datum ids.
22
+ * - Projected selections are not supported.
23
+ *
24
+ * @param {View} root
25
+ * @param {string} name
26
+ * @returns {ParamApi}
27
+ */
28
+ export function resolveEmbedParam(root, name) {
29
+ const matches = collectParamMatches(root, name);
30
+ if (!matches.length) {
31
+ throw new Error('Parameter "' + name + '" not found.');
32
+ }
33
+
34
+ const effectiveMatches = new Map();
35
+ for (const match of matches) {
36
+ const runtime = match.view.paramRuntime.findRuntimeForParam(name);
37
+ if (!runtime) {
38
+ throw new Error('Parameter "' + name + '" has no runtime value.');
39
+ }
40
+
41
+ effectiveMatches.set(runtime, {
42
+ runtime,
43
+ readOnly: hasExprParam(effectiveMatches.get(runtime), match),
44
+ pointSelection: hasPointSelectionParam(
45
+ effectiveMatches.get(runtime),
46
+ match
47
+ ),
48
+ });
49
+ }
50
+
51
+ if (effectiveMatches.size > 1) {
52
+ throw new Error('Parameter "' + name + '" is ambiguous.');
53
+ }
54
+
55
+ const { runtime, readOnly, pointSelection } = effectiveMatches
56
+ .values()
57
+ .next().value;
58
+
59
+ return {
60
+ getValue() {
61
+ return runtime.getValue(name);
62
+ },
63
+
64
+ setValue(value) {
65
+ if (readOnly) {
66
+ throw new Error(
67
+ 'Cannot set computed parameter "' + name + '".'
68
+ );
69
+ }
70
+ if (pointSelection) {
71
+ throw new Error(
72
+ 'Cannot set point selection parameter "' +
73
+ name +
74
+ '" through the embed API.'
75
+ );
76
+ }
77
+
78
+ runtime.setValue(name, value);
79
+ root.context.animator.requestRender();
80
+ },
81
+
82
+ subscribe(listener) {
83
+ return runtime.subscribe(name, () => {
84
+ listener(runtime.getValue(name));
85
+ });
86
+ },
87
+ };
88
+ }
89
+
90
+ /**
91
+ * @param {{ readOnly: boolean } | undefined} previous
92
+ * @param {{ param: Parameter }} match
93
+ * @returns {boolean}
94
+ */
95
+ function hasExprParam(previous, match) {
96
+ return Boolean(previous?.readOnly || "expr" in match.param);
97
+ }
98
+
99
+ /**
100
+ * @param {{ pointSelection: boolean } | undefined} previous
101
+ * @param {{ param: Parameter }} match
102
+ * @returns {boolean}
103
+ */
104
+ function hasPointSelectionParam(previous, match) {
105
+ if (previous?.pointSelection) {
106
+ return true;
107
+ }
108
+
109
+ const param = match.param;
110
+ return (
111
+ "select" in param &&
112
+ isPointSelectionConfig(asSelectionConfig(param.select))
113
+ );
114
+ }
115
+
116
+ /**
117
+ * @param {View} root
118
+ * @param {string} name
119
+ * @returns {{ view: View, param: Parameter }[]}
120
+ */
121
+ function collectParamMatches(root, name) {
122
+ /** @type {{ view: View, param: Parameter }[]} */
123
+ const matches = [];
124
+
125
+ root.visit((view) => {
126
+ const param = view.paramRuntime.paramConfigs.get(name);
127
+ if (param) {
128
+ matches.push({ view, param });
129
+ }
130
+ });
131
+
132
+ return matches;
133
+ }
@@ -4,6 +4,7 @@
4
4
  * @typedef {import("../spec/scale.js").ComplexDomain} ComplexDomain
5
5
  * @typedef {import("../spec/scale.js").ZoomParams} ZoomParams
6
6
  * @typedef {import("../types/encoder.js").VegaScale} VegaScale
7
+ * @typedef {import("../types/scaleResolutionApi.js").ZoomToOptions} ZoomToOptions
7
8
  * @typedef {VegaScale & { props: import("../spec/scale.js").Scale }} ScaleWithProps
8
9
  */
9
10
  export default class ScaleInteractionController {
@@ -11,14 +12,16 @@ export default class ScaleInteractionController {
11
12
  * @param {object} options
12
13
  * @param {() => ScaleWithProps} options.getScale
13
14
  * @param {() => import("../utils/animator.js").default} options.getAnimator
15
+ * @param {() => void} options.renderImmediately
14
16
  * @param {() => number[]} options.getInitialDomainSnapshot
15
17
  * @param {() => number[]} options.getResetDomain
16
18
  * @param {(domain: ScalarDomain | ComplexDomain) => number[]} options.fromComplexInterval
17
19
  * @param {() => number[]} options.getGenomeExtent
18
20
  */
19
- constructor({ getScale, getAnimator, getInitialDomainSnapshot, getResetDomain, fromComplexInterval, getGenomeExtent, }: {
21
+ constructor({ getScale, getAnimator, renderImmediately, getInitialDomainSnapshot, getResetDomain, fromComplexInterval, getGenomeExtent, }: {
20
22
  getScale: () => ScaleWithProps;
21
23
  getAnimator: () => import("../utils/animator.js").default;
24
+ renderImmediately: () => void;
22
25
  getInitialDomainSnapshot: () => number[];
23
26
  getResetDomain: () => number[];
24
27
  fromComplexInterval: (domain: ScalarDomain | ComplexDomain) => number[];
@@ -52,10 +55,10 @@ export default class ScaleInteractionController {
52
55
  * Immediately zooms to the given interval.
53
56
  *
54
57
  * @param {NumericDomain | ComplexDomain} domain
55
- * @param {boolean | number} [duration] an approximate duration for transition.
56
- * Zero duration zooms immediately. Boolean `true` indicates a default duration.
58
+ * @param {ZoomToOptions | boolean | number} [options] Zoom options.
59
+ * Passing the duration directly as a boolean or number is deprecated.
57
60
  */
58
- zoomTo(domain: NumericDomain | ComplexDomain, duration?: boolean | number): Promise<void>;
61
+ zoomTo(domain: NumericDomain | ComplexDomain, options?: ZoomToOptions | boolean | number): Promise<void>;
59
62
  /**
60
63
  * Resets the current domain to the initial one
61
64
  *
@@ -73,6 +76,7 @@ export type ScalarDomain = import("../spec/scale.js").ScalarDomain;
73
76
  export type ComplexDomain = import("../spec/scale.js").ComplexDomain;
74
77
  export type ZoomParams = import("../spec/scale.js").ZoomParams;
75
78
  export type VegaScale = import("../types/encoder.js").VegaScale;
79
+ export type ZoomToOptions = import("../types/scaleResolutionApi.js").ZoomToOptions;
76
80
  export type ScaleWithProps = VegaScale & {
77
81
  props: import("../spec/scale.js").Scale;
78
82
  };
@@ -1 +1 @@
1
- {"version":3,"file":"scaleInteractionController.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInteractionController.js"],"names":[],"mappings":"AAuBA;;;;;;;GAOG;AAEH;IAsBI;;;;;;;;OAQG;IACH,wHAPG;QAAsC,QAAQ,EAAtC,MAAM,cAAc;QACkC,WAAW,EAAjE,MAAM,OAAO,sBAAsB,EAAE,OAAO;QACpB,wBAAwB,EAAhD,MAAM,MAAM,EAAE;QACU,cAAc,EAAtC,MAAM,MAAM,EAAE;QAC8C,mBAAmB,EAA/E,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,KAAK,MAAM,EAAE;QAC1B,eAAe,EAAvC,MAAM,MAAM,EAAE;KACxB,EAeA;IAED,0BAUC;IAED,sBAEC;IAED,8BAGC;IAED;;;;OAIG;IACH,sCAJW,MAAM,EAAE,aACR,MAAM,EAAE,GACN,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAarD;IAED;;;;OAIG;IACH,oBAQC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CA2BnB;IAED;;;;;;OAMG;IACH,eAJW,aAAa,GAAG,aAAa,aAC7B,OAAO,GAAG,MAAM,iBAkE1B;IASD;;;;OAIG;IACH,qBAcC;IAED;;OAEG;IACH,uBAOC;;CACJ;4BA/PY,OAAO,kBAAkB,EAAE,aAAa;2BACxC,OAAO,kBAAkB,EAAE,YAAY;4BACvC,OAAO,kBAAkB,EAAE,aAAa;yBACxC,OAAO,kBAAkB,EAAE,UAAU;wBACrC,OAAO,qBAAqB,EAAE,SAAS;6BACvC,SAAS,GAAG;IAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;CAAE"}
1
+ {"version":3,"file":"scaleInteractionController.d.ts","sourceRoot":"","sources":["../../../src/scales/scaleInteractionController.js"],"names":[],"mappings":"AAuBA;;;;;;;;GAQG;AAEH;IAyBI;;;;;;;;;OASG;IACH,2IARG;QAAsC,QAAQ,EAAtC,MAAM,cAAc;QACkC,WAAW,EAAjE,MAAM,OAAO,sBAAsB,EAAE,OAAO;QACxB,iBAAiB,EAArC,MAAM,IAAI;QACc,wBAAwB,EAAhD,MAAM,MAAM,EAAE;QACU,cAAc,EAAtC,MAAM,MAAM,EAAE;QAC8C,mBAAmB,EAA/E,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,KAAK,MAAM,EAAE;QAC1B,eAAe,EAAvC,MAAM,MAAM,EAAE;KACxB,EAiBA;IAED,0BAUC;IAED,sBAEC;IAED,8BAGC;IAED;;;;OAIG;IACH,sCAJW,MAAM,EAAE,aACR,MAAM,EAAE,GACN,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAarD;IAED;;;;OAIG;IACH,oBAQC;IAED;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CA2BnB;IAED;;;;;;OAMG;IACH,eAJW,aAAa,GAAG,aAAa,YAC7B,aAAa,GAAG,OAAO,GAAG,MAAM,iBA0E1C;IASD;;;;OAIG;IACH,qBAcC;IAED;;OAEG;IACH,uBAOC;;CACJ;4BA9QY,OAAO,kBAAkB,EAAE,aAAa;2BACxC,OAAO,kBAAkB,EAAE,YAAY;4BACvC,OAAO,kBAAkB,EAAE,aAAa;yBACxC,OAAO,kBAAkB,EAAE,UAAU;wBACrC,OAAO,qBAAqB,EAAE,SAAS;4BACvC,OAAO,gCAAgC,EAAE,aAAa;6BACtD,SAAS,GAAG;IAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,KAAK,CAAA;CAAE"}