@genome-spy/core 0.41.0 → 0.42.1

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 (117) hide show
  1. package/dist/bundle/index--cKb-dKG.js +615 -0
  2. package/dist/bundle/{index-gn8bhQ8w.js → index-d7k3kkin.js} +365 -366
  3. package/dist/bundle/index.es.js +4225 -4040
  4. package/dist/bundle/index.js +122 -79
  5. package/dist/schema.json +58 -6
  6. package/dist/src/data/sources/dynamic/axisGenomeSource.js +1 -1
  7. package/dist/src/data/sources/dynamic/axisTickSource.js +3 -3
  8. package/dist/src/data/sources/dynamic/bamSource.d.ts +3 -21
  9. package/dist/src/data/sources/dynamic/bamSource.d.ts.map +1 -1
  10. package/dist/src/data/sources/dynamic/bamSource.js +38 -55
  11. package/dist/src/data/sources/dynamic/bigBedSource.d.ts +2 -38
  12. package/dist/src/data/sources/dynamic/bigBedSource.d.ts.map +1 -1
  13. package/dist/src/data/sources/dynamic/bigBedSource.js +14 -71
  14. package/dist/src/data/sources/dynamic/bigWigSource.d.ts +4 -42
  15. package/dist/src/data/sources/dynamic/bigWigSource.d.ts.map +1 -1
  16. package/dist/src/data/sources/dynamic/bigWigSource.js +23 -60
  17. package/dist/src/data/sources/dynamic/gff3Source.d.ts.map +1 -1
  18. package/dist/src/data/sources/dynamic/gff3Source.js +1 -0
  19. package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts +2 -20
  20. package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts.map +1 -1
  21. package/dist/src/data/sources/dynamic/indexedFastaSource.js +23 -41
  22. package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts +23 -4
  23. package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts.map +1 -1
  24. package/dist/src/data/sources/dynamic/singleAxisLazySource.js +29 -4
  25. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.d.ts +60 -0
  26. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.d.ts.map +1 -0
  27. package/dist/src/data/sources/dynamic/singleAxisWindowedSource.js +152 -0
  28. package/dist/src/data/sources/dynamic/tabixSource.d.ts +6 -40
  29. package/dist/src/data/sources/dynamic/tabixSource.d.ts.map +1 -1
  30. package/dist/src/data/sources/dynamic/tabixSource.js +29 -78
  31. package/dist/src/data/transforms/regexFold.d.ts.map +1 -1
  32. package/dist/src/data/transforms/regexFold.js +8 -0
  33. package/dist/src/data/transforms/regexFold.test.js +28 -0
  34. package/dist/src/encoder/encoder.d.ts +6 -1
  35. package/dist/src/encoder/encoder.d.ts.map +1 -1
  36. package/dist/src/encoder/encoder.js +10 -0
  37. package/dist/src/genomeSpy.d.ts +14 -0
  38. package/dist/src/genomeSpy.d.ts.map +1 -1
  39. package/dist/src/genomeSpy.js +114 -8
  40. package/dist/src/gl/arrayBuilder.js +1 -1
  41. package/dist/src/gl/colorUtils.d.ts.map +1 -0
  42. package/dist/src/{scale → gl}/colorUtils.js +1 -1
  43. package/dist/src/gl/dataToVertices.d.ts +1 -9
  44. package/dist/src/gl/dataToVertices.d.ts.map +1 -1
  45. package/dist/src/gl/dataToVertices.js +33 -73
  46. package/dist/src/{scale → gl}/glslScaleGenerator.d.ts +23 -1
  47. package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -0
  48. package/dist/src/{scale → gl}/glslScaleGenerator.js +59 -8
  49. package/dist/src/gl/webGLHelper.d.ts +6 -21
  50. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  51. package/dist/src/gl/webGLHelper.js +8 -39
  52. package/dist/src/img/90-ring-with-bg.svg +1 -0
  53. package/dist/src/img/README.md +5 -0
  54. package/dist/src/marks/link.d.ts +7 -0
  55. package/dist/src/marks/link.d.ts.map +1 -1
  56. package/dist/src/marks/link.js +74 -39
  57. package/dist/src/marks/mark.d.ts +2 -1
  58. package/dist/src/marks/mark.d.ts.map +1 -1
  59. package/dist/src/marks/mark.js +31 -2
  60. package/dist/src/marks/{pointMark.d.ts → point.d.ts} +1 -1
  61. package/dist/src/marks/point.d.ts.map +1 -0
  62. package/dist/src/marks/{pointMark.js → point.js} +3 -3
  63. package/dist/src/marks/{rectMark.d.ts → rect.d.ts} +1 -1
  64. package/dist/src/marks/rect.d.ts.map +1 -0
  65. package/dist/src/marks/{rectMark.js → rect.js} +2 -3
  66. package/dist/src/marks/rect.vertex.glsl.js +2 -0
  67. package/dist/src/marks/rule.js +3 -3
  68. package/dist/src/marks/text.d.ts.map +1 -1
  69. package/dist/src/marks/text.js +19 -20
  70. package/dist/src/spec/data.d.ts +28 -13
  71. package/dist/src/spec/mark.d.ts +0 -8
  72. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  73. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  74. package/dist/src/styles/genome-spy.css.js +33 -4
  75. package/dist/src/styles/genome-spy.scss +40 -4
  76. package/dist/src/types/viewContext.d.ts +9 -0
  77. package/dist/src/utils/binnedIndex.d.ts +2 -0
  78. package/dist/src/utils/binnedIndex.d.ts.map +1 -1
  79. package/dist/src/utils/binnedIndex.js +59 -10
  80. package/dist/src/utils/binnedIndex.test.js +46 -0
  81. package/dist/src/utils/indexer.d.ts.map +1 -1
  82. package/dist/src/utils/indexer.js +10 -1
  83. package/dist/src/utils/indexer.test.js +2 -0
  84. package/dist/src/view/gridView.d.ts.map +1 -1
  85. package/dist/src/view/gridView.js +2 -0
  86. package/dist/src/view/layerView.d.ts.map +1 -1
  87. package/dist/src/view/layerView.js +2 -0
  88. package/dist/src/view/unitView.d.ts +1 -7
  89. package/dist/src/view/unitView.d.ts.map +1 -1
  90. package/dist/src/view/unitView.js +4 -11
  91. package/dist/src/view/view.d.ts +6 -0
  92. package/dist/src/view/view.d.ts.map +1 -1
  93. package/dist/src/view/view.js +11 -0
  94. package/dist/src/view/view.test.js +1 -1
  95. package/package.json +3 -3
  96. package/dist/bundle/index-Cbz74kpR.js +0 -638
  97. package/dist/src/data/sources/dynamic/windowedMixin.d.ts +0 -32
  98. package/dist/src/data/sources/dynamic/windowedMixin.d.ts.map +0 -1
  99. package/dist/src/data/sources/dynamic/windowedMixin.js +0 -53
  100. package/dist/src/gl/rect.vertex.glsl.js +0 -2
  101. package/dist/src/marks/pointMark.d.ts.map +0 -1
  102. package/dist/src/marks/rectMark.d.ts.map +0 -1
  103. package/dist/src/scale/colorUtils.d.ts.map +0 -1
  104. package/dist/src/scale/glslScaleGenerator.d.ts.map +0 -1
  105. /package/dist/src/{scale → gl}/colorUtils.d.ts +0 -0
  106. /package/dist/src/{gl → marks}/link.fragment.glsl.js +0 -0
  107. /package/dist/src/{gl → marks}/link.vertex.glsl.js +0 -0
  108. /package/dist/src/{gl → marks}/point.common.glsl.js +0 -0
  109. /package/dist/src/{gl → marks}/point.fragment.glsl.js +0 -0
  110. /package/dist/src/{gl → marks}/point.vertex.glsl.js +0 -0
  111. /package/dist/src/{gl → marks}/rect.fragment.glsl.js +0 -0
  112. /package/dist/src/{gl → marks}/rule.common.glsl.js +0 -0
  113. /package/dist/src/{gl → marks}/rule.fragment.glsl.js +0 -0
  114. /package/dist/src/{gl → marks}/rule.vertex.glsl.js +0 -0
  115. /package/dist/src/{gl → marks}/text.common.glsl.js +0 -0
  116. /package/dist/src/{gl → marks}/text.fragment.glsl.js +0 -0
  117. /package/dist/src/{gl → marks}/text.vertex.glsl.js +0 -0
@@ -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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"}
@@ -14,6 +14,7 @@ import createEncoders, {
14
14
  isChannelDefWithScale,
15
15
  isChannelWithScale,
16
16
  isDatumDef,
17
+ isFieldDef,
17
18
  isValueDef,
18
19
  } from "../encoder/encoder.js";
19
20
  import {
@@ -25,7 +26,8 @@ import {
25
26
  isHighPrecisionScale,
26
27
  toHighPrecisionDomainUniform,
27
28
  splitHighPrecision,
28
- } from "../scale/glslScaleGenerator.js";
29
+ dedupeEncodingFields,
30
+ } from "../gl/glslScaleGenerator.js";
29
31
  import GLSL_COMMON from "../gl/includes/common.glsl.js";
30
32
  import GLSL_SCALES from "../gl/includes/scales.glsl.js";
31
33
  import GLSL_SAMPLE_FACET from "../gl/includes/sampleFacet.glsl.js";
@@ -316,6 +318,7 @@ export default class Mark {
316
318
  * @param {string} vertexShader
317
319
  * @param {string} fragmentShader
318
320
  * @param {string[]} [extraHeaders]
321
+ * @protected
319
322
  */
320
323
  createAndLinkShaders(vertexShader, fragmentShader, extraHeaders = []) {
321
324
  const attributes = this.getAttributes();
@@ -330,6 +333,15 @@ export default class Mark {
330
333
  /** @type {string[]} */
331
334
  let scaleCode = [];
332
335
 
336
+ /**
337
+ * Attribute definitions. Using set to prevent duplicates caused by
338
+ * multiple channels using the same shared quantitative field.
339
+ * @type {Set<string>}
340
+ */
341
+ const attributeCode = new Set();
342
+
343
+ const dedupedEncodingFields = dedupeEncodingFields(this.encoders);
344
+
333
345
  const sampleFacetMode = this.getSampleFacetMode();
334
346
  if (sampleFacetMode) {
335
347
  extraHeaders.push(`#define ${sampleFacetMode}`);
@@ -364,12 +376,28 @@ export default class Mark {
364
376
  .getScale()
365
377
  : scaleNull();
366
378
 
367
- const generated = generateScaleGlsl(channel, scale, channelDef);
379
+ // Channels that share the same quantitative field
380
+ // TODO: It should be ok to share a categorical field if the channels
381
+ // share the same scale, e.g., primary and secondary positional channels
382
+ const sharedChannels =
383
+ isFieldDef(channelDef) && !isDiscrete(scale.type)
384
+ ? dedupedEncodingFields.get([channelDef.field, true])
385
+ : [channel];
386
+
387
+ const generated = generateScaleGlsl(
388
+ channel,
389
+ scale,
390
+ channelDef,
391
+ sharedChannels
392
+ );
368
393
 
369
394
  scaleCode.push(generated.glsl);
370
395
  if (generated.domainUniform) {
371
396
  this.domainUniforms.push(generated.domainUniform);
372
397
  }
398
+ if (generated.attributeGlsl) {
399
+ attributeCode.add(generated.attributeGlsl);
400
+ }
373
401
  }
374
402
  }
375
403
 
@@ -388,6 +416,7 @@ export default class Mark {
388
416
  GLSL_COMMON,
389
417
  GLSL_SCALES,
390
418
  domainUniformBlock,
419
+ [...attributeCode].join("\n"),
391
420
  ...scaleCode,
392
421
  GLSL_SAMPLE_FACET,
393
422
  GLSL_PICKING_VERTEX,
@@ -8,4 +8,4 @@ export default class PointMark extends Mark {
8
8
  getSemanticThreshold(): number;
9
9
  }
10
10
  import Mark from "./mark.js";
11
- //# sourceMappingURL=pointMark.d.ts.map
11
+ //# sourceMappingURL=point.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../../src/marks/point.js"],"names":[],"mappings":"AAkBA;IAsGY,oCAMC;IA2CT,mCAQC;IAED;;OAEG;IACH,wDASC;IAED,+BAoBC;CAiDJ;iBA3PgB,WAAW"}
@@ -5,9 +5,9 @@ import {
5
5
  } from "twgl.js";
6
6
  import { quantileSorted } from "d3-array";
7
7
  import { PointVertexBuilder } from "../gl/dataToVertices.js";
8
- import VERTEX_SHADER from "../gl/point.vertex.glsl.js";
9
- import FRAGMENT_SHADER from "../gl/point.fragment.glsl.js";
10
- import COMMON_SHADER from "../gl/point.common.glsl.js";
8
+ import VERTEX_SHADER from "./point.vertex.glsl.js";
9
+ import FRAGMENT_SHADER from "./point.fragment.glsl.js";
10
+ import COMMON_SHADER from "./point.common.glsl.js";
11
11
 
12
12
  import Mark from "./mark.js";
13
13
  import { sampleIterable } from "../data/transforms/sample.js";
@@ -14,4 +14,4 @@ export default class RectMark extends Mark {
14
14
  #private;
15
15
  }
16
16
  import Mark from "./mark.js";
17
- //# sourceMappingURL=rectMark.d.ts.map
17
+ //# sourceMappingURL=rect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"AAYA;IA0NI;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;;CACJ;iBAnQgB,WAAW"}
@@ -1,6 +1,6 @@
1
1
  import { drawBufferInfo, setBuffersAndAttributes } from "twgl.js";
2
- import VERTEX_SHADER from "../gl/rect.vertex.glsl.js";
3
- import FRAGMENT_SHADER from "../gl/rect.fragment.glsl.js";
2
+ import VERTEX_SHADER from "./rect.vertex.glsl.js";
3
+ import FRAGMENT_SHADER from "./rect.fragment.glsl.js";
4
4
  import { RectVertexBuilder } from "../gl/dataToVertices.js";
5
5
 
6
6
  import Mark from "./mark.js";
@@ -179,7 +179,6 @@ export default class RectMark extends Mark {
179
179
  const collector = this.unitView.getCollector();
180
180
  const numItems = collector.getItemCount();
181
181
 
182
- // TODO: Disable tessellation on SimpleTrack - no need for it
183
182
  const builder = new RectVertexBuilder({
184
183
  encoders: this.encoders,
185
184
  attributes: this.getAttributes(),
@@ -0,0 +1,2 @@
1
+ const shader = "uniform Mark{uniform float uMinWidth;uniform float uMinHeight;uniform float uMinOpacity;uniform float uCornerRadiusTopRight;uniform float uCornerRadiusBottomRight;uniform float uCornerRadiusTopLeft;uniform float uCornerRadiusBottomLeft;};out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out float vHalfStrokeWidth;out vec4 vCornerRadii;\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\nout vec2 vPosInPixels;\n#endif\nout vec2 vHalfSizeInPixels;/***Clamps the minimumSize and returns an opacity that reflects the amount of clamping.*/float clampMinSize(inout float pos,float frac,float size,float minSize){if(minSize>0.0&&abs(size)<minSize){pos+=(frac-0.5)*(minSize*sign(size)-size);return abs(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,uCornerRadiusBottomLeft,uCornerRadiusTopLeft);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));pos=applySampleFacet(pos);\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\nfloat aaPadding=1.0/uDevicePixelRatio;float strokeWidth=getScaled_strokeWidth();float strokeOpacity=getScaled_strokeOpacity()*opaFactor;vec2 centeredFrac=frac-0.5;vec2 expand=centeredFrac*(strokeWidth+aaPadding)/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
+ export default shader;
@@ -6,9 +6,9 @@ import {
6
6
  setBuffersAndAttributes,
7
7
  setUniforms,
8
8
  } from "twgl.js";
9
- import VERTEX_SHADER from "../gl/rule.vertex.glsl.js";
10
- import FRAGMENT_SHADER from "../gl/rule.fragment.glsl.js";
11
- import COMMON_SHADER from "../gl/rule.common.glsl.js";
9
+ import VERTEX_SHADER from "./rule.vertex.glsl.js";
10
+ import FRAGMENT_SHADER from "./rule.fragment.glsl.js";
11
+ import COMMON_SHADER from "./rule.common.glsl.js";
12
12
  import { RuleVertexBuilder } from "../gl/dataToVertices.js";
13
13
  import { isChannelDefWithScale } from "../encoder/encoder.js";
14
14
 
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAsDQ,oDAMmD;CAiM1D;iBAxRgB,WAAW"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAsDQ,oDAMmD;CAgM1D;iBAvRgB,WAAW"}
@@ -6,9 +6,9 @@ import {
6
6
  setBuffersAndAttributes,
7
7
  setUniforms,
8
8
  } from "twgl.js";
9
- import VERTEX_SHADER from "../gl/text.vertex.glsl.js";
10
- import FRAGMENT_SHADER from "../gl/text.fragment.glsl.js";
11
- import COMMON_SHADER from "../gl/text.common.glsl.js";
9
+ import VERTEX_SHADER from "./text.vertex.glsl.js";
10
+ import FRAGMENT_SHADER from "./text.fragment.glsl.js";
11
+ import COMMON_SHADER from "./text.common.glsl.js";
12
12
  import { TextVertexBuilder } from "../gl/dataToVertices.js";
13
13
 
14
14
  import Mark from "./mark.js";
@@ -160,6 +160,22 @@ export default class TextMark extends Mark {
160
160
 
161
161
  const props = this.properties;
162
162
 
163
+ this.registerMarkUniform(
164
+ "uSdfNumerator",
165
+ /** @type {import("../spec/mark.js").ExprRef | number} */
166
+ ({ expr: "devicePixelRatio" }),
167
+ (dpr) => {
168
+ let q = 0.35; // TODO: Ensure that this makes sense. Now chosen by trial & error
169
+ if (this.properties.logoLetters) {
170
+ // Adjust to make stretched letters a bit less blurry
171
+ // A proper solution would probably be to compute gradients in the fragment shader
172
+ // to find a suitable divisor.
173
+ q /= 2;
174
+ }
175
+ return this.font.metrics.common.base / (dpr / q);
176
+ }
177
+ );
178
+
163
179
  // TODO: Use uniform block.
164
180
  setBlockUniforms(this.markUniformInfo, {
165
181
  uPaddingX: props.paddingX,
@@ -237,24 +253,7 @@ export default class TextMark extends Mark {
237
253
  prepareRender(options) {
238
254
  const ops = super.prepareRender(options);
239
255
 
240
- let q = 0.35; // TODO: Ensure that this makes sense. Now chosen by trial & error
241
- if (this.properties.logoLetters) {
242
- // Adjust to make stretched letters a bit less blurry
243
- // A proper solution would probably be to compute gradients in the fragment shader
244
- // to find a suitable divisor.
245
- q /= 2;
246
- }
247
- const uSdfNumerator =
248
- this.font.metrics.common.base /
249
- (this.unitView.context.devicePixelRatio / q);
250
-
251
256
  ops.push(() => {
252
- // TODO: only set if dpr changed
253
- setBlockUniforms(this.markUniformInfo, {
254
- uSdfNumerator,
255
- });
256
- this.markUniformsAltered = true;
257
-
258
257
  setUniforms(this.programInfo, {
259
258
  uTexture: this.font.texture,
260
259
  });
@@ -202,6 +202,29 @@ export type LazyDataParams =
202
202
  | BamData
203
203
  | Gff3Data;
204
204
 
205
+ export interface DebouncedData {
206
+ /**
207
+ * Debounce time for data updates, in milliseconds. Debouncing prevents
208
+ * excessive data updates when the user is zooming or panning around.
209
+ *
210
+ * __Default value:__ `200`
211
+ */
212
+ debounce?: number;
213
+
214
+ /**
215
+ * The debounce mode for data updates. If set to `"domain"`, domain change
216
+ * events (panning and zooming) will be debounced. If set to `"window"`,
217
+ * the data fetches initiated by the changes to the visible window (or tile)
218
+ * will be debounced. If your data is small, the `"window"` is better as
219
+ * it will start fetching data while the user is still panning around,
220
+ * resulting in a shorter perceived latency.
221
+ *
222
+ * __Default value:__ `"window"`
223
+ *
224
+ */
225
+ debounceMode?: "domain" | "window";
226
+ }
227
+
205
228
  export interface AxisTicksData {
206
229
  type: "axisTicks";
207
230
 
@@ -219,7 +242,7 @@ export interface AxisGenomeData {
219
242
  channel: PrimaryPositionalChannel;
220
243
  }
221
244
 
222
- export interface IndexedFastaData {
245
+ export interface IndexedFastaData extends DebouncedData {
223
246
  type: "indexedFasta";
224
247
 
225
248
  /**
@@ -250,7 +273,7 @@ export interface IndexedFastaData {
250
273
  windowSize?: number;
251
274
  }
252
275
 
253
- export interface BigWigData {
276
+ export interface BigWigData extends DebouncedData {
254
277
  type: "bigwig";
255
278
 
256
279
  /**
@@ -273,7 +296,7 @@ export interface BigWigData {
273
296
  pixelsPerBin?: number;
274
297
  }
275
298
 
276
- export interface BigBedData {
299
+ export interface BigBedData extends DebouncedData {
277
300
  type: "bigbed";
278
301
 
279
302
  /**
@@ -297,7 +320,7 @@ export interface BigBedData {
297
320
  windowSize?: number;
298
321
  }
299
322
 
300
- export interface BamData {
323
+ export interface BamData extends DebouncedData {
301
324
  type: "bam";
302
325
 
303
326
  /**
@@ -328,7 +351,7 @@ export interface BamData {
328
351
  windowSize?: number;
329
352
  }
330
353
 
331
- export interface TabixData {
354
+ export interface TabixData extends DebouncedData {
332
355
  /**
333
356
  * Which channel's scale domain to monitor.
334
357
  *
@@ -355,14 +378,6 @@ export interface TabixData {
355
378
  * __Default value:__ `30000000`
356
379
  */
357
380
  windowSize?: number;
358
-
359
- /**
360
- * The debounce time for domain changes, in milliseconds. Debouncing prevents
361
- * data fetches while the user is still panning around.
362
- *
363
- * __Default value:__ `200`
364
- */
365
- debounceDomainChange?: number;
366
381
  }
367
382
 
368
383
  export interface Gff3Data extends TabixData {
@@ -472,14 +472,6 @@ export interface MarkConfig
472
472
  * This property is intended for internal use.
473
473
  */
474
474
  minBufferSize?: number;
475
-
476
- /**
477
- * Builds and index for efficient rendering of subsets of the data.
478
- * The data must be sorted by the x coordinate.
479
- *
480
- * TODO: This should be enabled automatically if the data are sorted.
481
- */
482
- buildIndex?: boolean;
483
475
  }
484
476
 
485
477
  export interface MarkConfigAndType extends MarkConfig {
@@ -1,3 +1,3 @@
1
1
  export default css;
2
- declare const css: ".genome-spy {\n font-family: system-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n position: relative;\n}\n.genome-spy canvas {\n transform: scale(1, 1);\n opacity: 1;\n transition: transform 0.6s, opacity 0.6s;\n}\n.genome-spy .loading-message {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-message .message {\n color: #666;\n opacity: 0;\n transition: opacity 0.7s;\n}\n.genome-spy.loading canvas {\n transform: scale(0.95, 0.95);\n opacity: 0;\n}\n.genome-spy.loading .loading-message .message {\n opacity: 1;\n}\n.genome-spy.loading .ellipsis {\n animation: blinker 1s linear infinite;\n}\n@keyframes blinker {\n 50% {\n opacity: 0;\n }\n}\n.genome-spy .tooltip {\n position: absolute;\n max-width: 450px;\n overflow: hidden;\n background: #f6f6f6;\n padding: 10px;\n font-size: 13px;\n box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);\n pointer-events: none;\n z-index: 100;\n}\n.genome-spy .tooltip > :last-child {\n margin-bottom: 0;\n}\n.genome-spy .tooltip > .title {\n padding-bottom: 5px;\n margin-bottom: 5px;\n border-bottom: 1px dashed #b6b6b6;\n}\n.genome-spy .tooltip .summary {\n font-size: 12px;\n}\n.genome-spy .tooltip table {\n border-collapse: collapse;\n}\n.genome-spy .tooltip table:first-child {\n margin-top: 0;\n}\n.genome-spy .tooltip table th,\n.genome-spy .tooltip table td {\n padding: 2px 0.4em;\n vertical-align: top;\n}\n.genome-spy .tooltip table th:first-child,\n.genome-spy .tooltip table td:first-child {\n padding-left: 0;\n}\n.genome-spy .tooltip table th {\n text-align: left;\n font-weight: bold;\n}\n.genome-spy .tooltip .color-legend {\n display: inline-block;\n width: 0.8em;\n height: 0.8em;\n margin-left: 0.4em;\n box-shadow: 0px 0px 3px 1px white;\n}\n.genome-spy .tooltip .attributes .hovered {\n background-color: #e0e0e0;\n}\n.genome-spy .tooltip .na {\n color: #aaa;\n font-style: italic;\n font-size: 80%;\n}\n.genome-spy .gene-track-tooltip .summary {\n font-size: 90%;\n}\n.genome-spy .message-box {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n top: 0;\n height: 100%;\n width: 100%;\n}\n.genome-spy .message-box > div {\n border: 1px solid red;\n padding: 10px;\n background: #fff0f0;\n}";
2
+ declare const css: ".genome-spy {\n font-family: system-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n position: relative;\n}\n.genome-spy canvas {\n transform: scale(1, 1);\n opacity: 1;\n transition: transform 0.6s, opacity 0.6s;\n}\n.genome-spy .loading-message {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-message .message {\n color: #666;\n opacity: 0;\n transition: opacity 0.7s;\n}\n.genome-spy.loading canvas {\n transform: scale(0.95, 0.95);\n opacity: 0;\n}\n.genome-spy.loading .loading-message .message {\n opacity: 1;\n}\n.genome-spy.loading .ellipsis {\n animation: blinker 1s linear infinite;\n}\n@keyframes blinker {\n 50% {\n opacity: 0;\n }\n}\n.genome-spy .loading-indicators {\n position: absolute;\n inset: 0;\n user-select: none;\n pointer-events: none;\n}\n.genome-spy .loading-indicators div {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-indicators div > div {\n font-size: 11px;\n transition: opacity 0.2s;\n background: white;\n padding: 2px 5px;\n display: flex;\n border-radius: 3px;\n gap: 0.5em;\n opacity: 0;\n}\n.genome-spy .loading-indicators div > div.loading {\n opacity: 0.5;\n}\n.genome-spy .loading-indicators div > div > * {\n display: block;\n}\n.genome-spy .loading-indicators div > div img {\n width: 1.5em;\n height: 1.5em;\n}\n.genome-spy .tooltip {\n position: absolute;\n max-width: 450px;\n overflow: hidden;\n background: #f6f6f6;\n padding: 10px;\n font-size: 13px;\n box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);\n pointer-events: none;\n z-index: 100;\n}\n.genome-spy .tooltip > :last-child {\n margin-bottom: 0;\n}\n.genome-spy .tooltip > .title {\n padding-bottom: 5px;\n margin-bottom: 5px;\n border-bottom: 1px dashed #b6b6b6;\n}\n.genome-spy .tooltip .summary {\n font-size: 12px;\n}\n.genome-spy .tooltip table {\n border-collapse: collapse;\n}\n.genome-spy .tooltip table:first-child {\n margin-top: 0;\n}\n.genome-spy .tooltip table th,\n.genome-spy .tooltip table td {\n padding: 2px 0.4em;\n vertical-align: top;\n}\n.genome-spy .tooltip table th:first-child,\n.genome-spy .tooltip table td:first-child {\n padding-left: 0;\n}\n.genome-spy .tooltip table th {\n text-align: left;\n font-weight: bold;\n}\n.genome-spy .tooltip .color-legend {\n display: inline-block;\n width: 0.8em;\n height: 0.8em;\n margin-left: 0.4em;\n box-shadow: 0px 0px 3px 1px white;\n}\n.genome-spy .tooltip .attributes .hovered {\n background-color: #e0e0e0;\n}\n.genome-spy .tooltip .na {\n color: #aaa;\n font-style: italic;\n font-size: 80%;\n}\n.genome-spy .gene-track-tooltip .summary {\n font-size: 90%;\n}\n.genome-spy .message-box {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n top: 0;\n height: 100%;\n width: 100%;\n}\n.genome-spy .message-box > div {\n border: 1px solid red;\n padding: 10px;\n background: #fff0f0;\n}";
3
3
  //# sourceMappingURL=genome-spy.css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"genome-spy.css.d.ts","sourceRoot":"","sources":["../../../src/styles/genome-spy.css.js"],"names":[],"mappings":";AAAA,q6EA+GG"}
1
+ {"version":3,"file":"genome-spy.css.d.ts","sourceRoot":"","sources":["../../../src/styles/genome-spy.css.js"],"names":[],"mappings":";AAAA,0jGA4IG"}
@@ -9,10 +9,7 @@ const css = `.genome-spy {
9
9
  }
10
10
  .genome-spy .loading-message {
11
11
  position: absolute;
12
- top: 0;
13
- bottom: 0;
14
- left: 0;
15
- right: 0;
12
+ inset: 0;
16
13
  display: flex;
17
14
  align-items: center;
18
15
  justify-content: center;
@@ -37,6 +34,38 @@ const css = `.genome-spy {
37
34
  opacity: 0;
38
35
  }
39
36
  }
37
+ .genome-spy .loading-indicators {
38
+ position: absolute;
39
+ inset: 0;
40
+ user-select: none;
41
+ pointer-events: none;
42
+ }
43
+ .genome-spy .loading-indicators div {
44
+ position: absolute;
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ }
49
+ .genome-spy .loading-indicators div > div {
50
+ font-size: 11px;
51
+ transition: opacity 0.2s;
52
+ background: white;
53
+ padding: 2px 5px;
54
+ display: flex;
55
+ border-radius: 3px;
56
+ gap: 0.5em;
57
+ opacity: 0;
58
+ }
59
+ .genome-spy .loading-indicators div > div.loading {
60
+ opacity: 0.5;
61
+ }
62
+ .genome-spy .loading-indicators div > div > * {
63
+ display: block;
64
+ }
65
+ .genome-spy .loading-indicators div > div img {
66
+ width: 1.5em;
67
+ height: 1.5em;
68
+ }
40
69
  .genome-spy .tooltip {
41
70
  position: absolute;
42
71
  max-width: 450px;
@@ -18,10 +18,7 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
18
18
 
19
19
  .loading-message {
20
20
  position: absolute;
21
- top: 0;
22
- bottom: 0;
23
- left: 0;
24
- right: 0;
21
+ inset: 0;
25
22
  display: flex;
26
23
 
27
24
  align-items: center;
@@ -55,6 +52,45 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
55
52
  }
56
53
  }
57
54
 
55
+ .loading-indicators {
56
+ position: absolute;
57
+ inset: 0;
58
+
59
+ user-select: none;
60
+ pointer-events: none;
61
+
62
+ div {
63
+ position: absolute;
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: center;
67
+
68
+ > div {
69
+ font-size: 11px;
70
+ transition: opacity 0.2s;
71
+ background: white;
72
+ padding: 2px 5px;
73
+ display: flex;
74
+ border-radius: 3px;
75
+ gap: 0.5em;
76
+ opacity: 0;
77
+
78
+ &.loading {
79
+ opacity: 0.5;
80
+ }
81
+
82
+ > * {
83
+ display: block;
84
+ }
85
+
86
+ img {
87
+ width: 1.5em;
88
+ height: 1.5em;
89
+ }
90
+ }
91
+ }
92
+ }
93
+
58
94
  .tooltip {
59
95
  position: absolute;
60
96
 
@@ -70,6 +70,15 @@ export default interface ViewContext {
70
70
 
71
71
  getNamedDataFromProvider: (name: string) => any[];
72
72
 
73
+ /**
74
+ * Allows lazy data sources to signal that they are loading data.
75
+ * The status is shown in the UI somewhere within or near the view.
76
+ *
77
+ * @param view The view where the data source is located.
78
+ * @param status true if loading, false if not loading.
79
+ */
80
+ setDataLoadingStatus: (view: View, status: boolean) => void;
81
+
73
82
  /**
74
83
  * Returns true if the view is configured to be visible.
75
84
  * N.B. This does NOT consider ancestors' visibility.
@@ -9,6 +9,8 @@
9
9
  * A binned index for (overlapping) ranges that are sorted by their start position.
10
10
  * Each indexed range is associated with respective vertex indices.
11
11
  *
12
+ * The indexing scheme is somewhat similar to Tabix (https://academic.oup.com/bioinformatics/article/27/5/718/262743).
13
+ *
12
14
  * @param {number} size Number of bins
13
15
  * @param {[number, number]} domain Domain of positions
14
16
  * @param {(datum: T) => number} accessor Accessor for range's start position
@@ -1 +1 @@
1
- {"version":3,"file":"binnedIndex.d.ts","sourceRoot":"","sources":["../../../src/utils/binnedIndex.js"],"names":[],"mappings":"AAKA;;;;;;GAMG;AAEH;;;;;;;;;GASG;AACH,mDANW,MAAM,UACN,CAAC,MAAM,EAAE,MAAM,CAAC,0BACF,MAAM,4BACN,MAAM;iCAyChB,MAAM,kBACN,MAAM;;EAwGpB;6BA/JU,MAAM,OACN,MAAM,QACN,CAAC,MAAM,EAAE,MAAM,CAAC,KACd,CAAC,MAAM,EAAE,MAAM,CAAC"}
1
+ {"version":3,"file":"binnedIndex.d.ts","sourceRoot":"","sources":["../../../src/utils/binnedIndex.js"],"names":[],"mappings":"AAKA;;;;;;GAMG;AAEH;;;;;;;;;;;GAWG;AACH,mDANW,MAAM,UACN,CAAC,MAAM,EAAE,MAAM,CAAC,0BACF,MAAM,4BACN,MAAM;iCA2ChB,MAAM,kBACN,MAAM;oBAsHJ,MAAM;EA+BtB;6BAhNU,MAAM,OACN,MAAM,QACN,CAAC,MAAM,EAAE,MAAM,CAAC,KACd,CAAC,MAAM,EAAE,MAAM,CAAC"}
@@ -15,6 +15,8 @@ const MIN_INTEGER = -(2 ** 31);
15
15
  * A binned index for (overlapping) ranges that are sorted by their start position.
16
16
  * Each indexed range is associated with respective vertex indices.
17
17
  *
18
+ * The indexing scheme is somewhat similar to Tabix (https://academic.oup.com/bioinformatics/article/27/5/718/262743).
19
+ *
18
20
  * @param {number} size Number of bins
19
21
  * @param {[number, number]} domain Domain of positions
20
22
  * @param {(datum: T) => number} accessor Accessor for range's start position
@@ -27,13 +29,15 @@ export function createBinningRangeIndexer(
27
29
  accessor,
28
30
  accessor2 = accessor
29
31
  ) {
30
- const startIndices = new Int32Array(size);
32
+ const startIndices = new Array(size);
31
33
  startIndices.fill(MAX_INTEGER);
32
34
 
33
35
  let lastIndex = MIN_INTEGER;
36
+ let lastStart = -Infinity;
34
37
  let unordered = false;
35
38
 
36
- const endIndices = new Int32Array(size);
39
+ const endIndices = new Array(size);
40
+ endIndices.fill(0);
37
41
 
38
42
  const start = domain[0];
39
43
  const domainLength = domain[1] - domain[0];
@@ -63,17 +67,33 @@ export function createBinningRangeIndexer(
63
67
  * @param {number} endVertexIndex
64
68
  */
65
69
  function binningIndexer(datum, startVertexIndex, endVertexIndex) {
70
+ if (unordered) {
71
+ return;
72
+ }
73
+
66
74
  if (startVertexIndex > lastIndex) {
67
75
  lastIndex = startVertexIndex;
68
- } else if (!unordered) {
76
+ } else {
69
77
  unordered = true;
70
78
  // TODO: Contextual info like view path
71
79
  console.debug(
72
80
  "Items are not ordered properly. Disabling binned index."
73
81
  );
82
+ return;
74
83
  }
75
84
 
76
85
  const value = accessor(datum);
86
+
87
+ if (value < lastStart) {
88
+ unordered = true;
89
+ // TODO: Contextual info like view path
90
+ console.debug(
91
+ "Items are not ordered properly. Disabling binned index."
92
+ );
93
+ return;
94
+ }
95
+ lastStart = value;
96
+
77
97
  const bin = getBin(value, false);
78
98
 
79
99
  if (startIndices[bin] > startVertexIndex) {
@@ -93,18 +113,42 @@ export function createBinningRangeIndexer(
93
113
  * @param {number} endVertexIndex
94
114
  */
95
115
  function binningRangeIndexer(datum, startVertexIndex, endVertexIndex) {
116
+ if (unordered) {
117
+ return;
118
+ }
119
+
96
120
  if (startVertexIndex > lastIndex) {
97
121
  lastIndex = startVertexIndex;
98
- } else if (!unordered) {
122
+ } else {
99
123
  unordered = true;
100
124
  // TODO: Contextual info like view path
101
125
  console.debug(
102
- "Items are not ordered properly. Disabling binned index."
126
+ "Items (vertices) are not ordered properly. Disabling binned index."
103
127
  );
128
+ return;
104
129
  }
105
130
 
106
131
  const start = accessor(datum);
107
132
  const end = accessor2(datum);
133
+
134
+ if (start < lastStart) {
135
+ unordered = true;
136
+ // TODO: Contextual info like view path
137
+ console.debug(
138
+ "Items are not ordered properly. Disabling binned index."
139
+ );
140
+ return;
141
+ } else if (end < start) {
142
+ unordered = true;
143
+ // TODO: Contextual info like view path
144
+ console.debug(
145
+ "End index is less than start index. Disabling binned index. Datum: ",
146
+ datum
147
+ );
148
+ return;
149
+ }
150
+ lastStart = start;
151
+
108
152
  const startBin = getBin(start, false);
109
153
  const endBin = getBin(end, true);
110
154
 
@@ -135,7 +179,16 @@ export function createBinningRangeIndexer(
135
179
  return arr;
136
180
  };
137
181
 
182
+ /**
183
+ * Finalizes the index and returns a lookup function.
184
+ *
185
+ * @returns {Lookup}
186
+ */
138
187
  const getIndex = () => {
188
+ if (unordered) {
189
+ return undefined;
190
+ }
191
+
139
192
  for (let i = 1; i < endIndices.length; i++) {
140
193
  if (endIndices[i] < endIndices[i - 1]) {
141
194
  endIndices[i] = endIndices[i - 1];
@@ -159,9 +212,5 @@ export function createBinningRangeIndexer(
159
212
  binningIndexer.getIndex = getIndex;
160
213
  binningRangeIndexer.getIndex = getIndex;
161
214
 
162
- if (unordered) {
163
- return undefined;
164
- } else {
165
- return accessor == accessor2 ? binningIndexer : binningRangeIndexer;
166
- }
215
+ return accessor == accessor2 ? binningIndexer : binningRangeIndexer;
167
216
  }