@genome-spy/core 0.41.0 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle/index--cKb-dKG.js +615 -0
- package/dist/bundle/{index-gn8bhQ8w.js → index-d7k3kkin.js} +365 -366
- package/dist/bundle/index.es.js +4077 -3900
- package/dist/bundle/index.js +111 -69
- package/dist/schema.json +58 -6
- package/dist/src/data/sources/dynamic/axisGenomeSource.js +1 -1
- package/dist/src/data/sources/dynamic/axisTickSource.js +3 -3
- package/dist/src/data/sources/dynamic/bamSource.d.ts +3 -21
- package/dist/src/data/sources/dynamic/bamSource.d.ts.map +1 -1
- package/dist/src/data/sources/dynamic/bamSource.js +38 -55
- package/dist/src/data/sources/dynamic/bigBedSource.d.ts +2 -38
- package/dist/src/data/sources/dynamic/bigBedSource.d.ts.map +1 -1
- package/dist/src/data/sources/dynamic/bigBedSource.js +14 -71
- package/dist/src/data/sources/dynamic/bigWigSource.d.ts +4 -42
- package/dist/src/data/sources/dynamic/bigWigSource.d.ts.map +1 -1
- package/dist/src/data/sources/dynamic/bigWigSource.js +23 -60
- package/dist/src/data/sources/dynamic/gff3Source.d.ts.map +1 -1
- package/dist/src/data/sources/dynamic/gff3Source.js +1 -0
- package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts +2 -20
- package/dist/src/data/sources/dynamic/indexedFastaSource.d.ts.map +1 -1
- package/dist/src/data/sources/dynamic/indexedFastaSource.js +23 -41
- package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts +23 -4
- package/dist/src/data/sources/dynamic/singleAxisLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/dynamic/singleAxisLazySource.js +29 -4
- package/dist/src/data/sources/dynamic/singleAxisWindowedSource.d.ts +60 -0
- package/dist/src/data/sources/dynamic/singleAxisWindowedSource.d.ts.map +1 -0
- package/dist/src/data/sources/dynamic/singleAxisWindowedSource.js +152 -0
- package/dist/src/data/sources/dynamic/tabixSource.d.ts +6 -40
- package/dist/src/data/sources/dynamic/tabixSource.d.ts.map +1 -1
- package/dist/src/data/sources/dynamic/tabixSource.js +29 -78
- package/dist/src/data/transforms/regexFold.d.ts.map +1 -1
- package/dist/src/data/transforms/regexFold.js +8 -0
- package/dist/src/data/transforms/regexFold.test.js +28 -0
- package/dist/src/genomeSpy.d.ts +14 -0
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +114 -8
- package/dist/src/gl/webGLHelper.d.ts +6 -21
- package/dist/src/gl/webGLHelper.d.ts.map +1 -1
- package/dist/src/gl/webGLHelper.js +7 -38
- package/dist/src/img/90-ring-with-bg.svg +1 -0
- package/dist/src/img/README.md +5 -0
- package/dist/src/marks/link.d.ts +7 -0
- package/dist/src/marks/link.d.ts.map +1 -1
- package/dist/src/marks/link.js +72 -37
- package/dist/src/marks/text.d.ts.map +1 -1
- package/dist/src/marks/text.js +16 -17
- package/dist/src/spec/data.d.ts +28 -13
- package/dist/src/spec/mark.d.ts +0 -8
- package/dist/src/styles/genome-spy.css.d.ts +1 -1
- package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
- package/dist/src/styles/genome-spy.css.js +33 -4
- package/dist/src/styles/genome-spy.scss +40 -4
- package/dist/src/types/viewContext.d.ts +9 -0
- package/dist/src/utils/binnedIndex.d.ts +2 -0
- package/dist/src/utils/binnedIndex.d.ts.map +1 -1
- package/dist/src/utils/binnedIndex.js +59 -10
- package/dist/src/utils/binnedIndex.test.js +46 -0
- package/dist/src/view/gridView.d.ts.map +1 -1
- package/dist/src/view/gridView.js +2 -0
- package/dist/src/view/layerView.d.ts.map +1 -1
- package/dist/src/view/layerView.js +2 -0
- package/dist/src/view/unitView.d.ts +0 -6
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +2 -9
- package/dist/src/view/view.d.ts +6 -0
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +11 -0
- package/package.json +3 -3
- package/dist/bundle/index-Cbz74kpR.js +0 -638
- package/dist/src/data/sources/dynamic/windowedMixin.d.ts +0 -32
- package/dist/src/data/sources/dynamic/windowedMixin.d.ts.map +0 -1
- package/dist/src/data/sources/dynamic/windowedMixin.js +0 -53
package/dist/src/marks/link.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAWA;IA+
|
|
1
|
+
{"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/marks/link.js"],"names":[],"mappings":"AAWA;IA+BQ;;;;;OAKG;IACH,yBAEC;IAkGD;;;;;;MAKC;CAoFR;iBAxOgB,WAAW"}
|
package/dist/src/marks/link.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { setBuffersAndAttributes } from "twgl.js";
|
|
2
2
|
import VERTEX_SHADER from "../gl/link.vertex.glsl.js";
|
|
3
3
|
import FRAGMENT_SHADER from "../gl/link.fragment.glsl.js";
|
|
4
4
|
import { LinkVertexBuilder } from "../gl/dataToVertices.js";
|
|
@@ -39,6 +39,16 @@ export default class LinkMark extends Mark {
|
|
|
39
39
|
orient: "vertical",
|
|
40
40
|
})
|
|
41
41
|
);
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Only available if "WebGL Draft Extensions" is enabled in chrome://flags
|
|
45
|
+
* But seems to work.
|
|
46
|
+
*
|
|
47
|
+
* @private
|
|
48
|
+
*/
|
|
49
|
+
this._baseInstanceExt = this.gl.getExtension(
|
|
50
|
+
"WEBGL_draw_instanced_base_vertex_base_instance"
|
|
51
|
+
);
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
getAttributes() {
|
|
@@ -154,6 +164,18 @@ export default class LinkMark extends Mark {
|
|
|
154
164
|
|
|
155
165
|
ops.push(() => this.bindOrSetMarkUniformBlock());
|
|
156
166
|
|
|
167
|
+
if (this._baseInstanceExt) {
|
|
168
|
+
ops.push(() =>
|
|
169
|
+
setBuffersAndAttributes(
|
|
170
|
+
this.gl,
|
|
171
|
+
this.programInfo,
|
|
172
|
+
this.vertexArrayInfo
|
|
173
|
+
)
|
|
174
|
+
);
|
|
175
|
+
} else {
|
|
176
|
+
ops.push(() => this.gl.bindVertexArray(null));
|
|
177
|
+
}
|
|
178
|
+
|
|
157
179
|
return ops;
|
|
158
180
|
}
|
|
159
181
|
|
|
@@ -163,42 +185,55 @@ export default class LinkMark extends Mark {
|
|
|
163
185
|
render(options) {
|
|
164
186
|
const gl = this.gl;
|
|
165
187
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
188
|
+
const arcVertexCount = (this.properties.segments + 1) * 2;
|
|
189
|
+
|
|
190
|
+
return this._baseInstanceExt
|
|
191
|
+
? this.createRenderCallback((offset, count) => {
|
|
192
|
+
// Using the following extension, which, however, is only a draft and
|
|
193
|
+
// available if "WebGL Draft Extensions" is enabled in chrome://flags
|
|
194
|
+
// https://www.khronos.org/registry/webgl/extensions/WEBGL_draw_instanced_base_vertex_base_instance/
|
|
195
|
+
|
|
196
|
+
this._baseInstanceExt.drawArraysInstancedBaseInstanceWEBGL(
|
|
197
|
+
gl.TRIANGLE_STRIP,
|
|
198
|
+
0,
|
|
199
|
+
arcVertexCount,
|
|
200
|
+
count,
|
|
201
|
+
offset
|
|
202
|
+
);
|
|
203
|
+
}, options)
|
|
204
|
+
: this.createRenderCallback((offset, count) => {
|
|
205
|
+
// Because vanilla WebGL 2 does not provide glDrawArraysInstancedBaseInstance,
|
|
206
|
+
// we have to hack with offsets in vertexAttribPointer
|
|
207
|
+
//
|
|
208
|
+
// TODO: Use VAOs more intelligently to reduce WebGL calls. In other words,
|
|
209
|
+
// reserve one VAO for each facet/sample.
|
|
210
|
+
|
|
211
|
+
for (const attribInfoObject of Object.entries(
|
|
212
|
+
this.bufferInfo.attribs
|
|
213
|
+
)) {
|
|
214
|
+
const [attribute, attribInfo] = attribInfoObject;
|
|
215
|
+
if (
|
|
216
|
+
attribInfo.buffer &&
|
|
217
|
+
attribInfo.numComponents &&
|
|
218
|
+
attribInfo.divisor
|
|
219
|
+
) {
|
|
220
|
+
attribInfo.offset =
|
|
221
|
+
offset * this.arrays[attribute].numComponents * 4; // gl.FLOAT in bytes
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
setBuffersAndAttributes(
|
|
225
|
+
gl,
|
|
226
|
+
this.programInfo,
|
|
227
|
+
this.bufferInfo
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
gl.drawArraysInstanced(
|
|
231
|
+
gl.TRIANGLE_STRIP,
|
|
232
|
+
0,
|
|
233
|
+
arcVertexCount,
|
|
234
|
+
count
|
|
235
|
+
);
|
|
236
|
+
}, options);
|
|
202
237
|
}
|
|
203
238
|
}
|
|
204
239
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAsDQ,oDAMmD;
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/marks/text.js"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH;IAsDQ,oDAMmD;CAgM1D;iBAvRgB,WAAW"}
|
package/dist/src/marks/text.js
CHANGED
|
@@ -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
|
});
|
package/dist/src/spec/data.d.ts
CHANGED
|
@@ -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 {
|
package/dist/src/spec/mark.d.ts
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
163
|
-
return undefined;
|
|
164
|
-
} else {
|
|
165
|
-
return accessor == accessor2 ? binningIndexer : binningRangeIndexer;
|
|
166
|
-
}
|
|
215
|
+
return accessor == accessor2 ? binningIndexer : binningRangeIndexer;
|
|
167
216
|
}
|
|
@@ -152,4 +152,50 @@ describe("Binning Indexer", () => {
|
|
|
152
152
|
expect(index(115, 116)).toEqual([4, 8]);
|
|
153
153
|
expect(index(135, 145)).toEqual([6, 10]);
|
|
154
154
|
});
|
|
155
|
+
|
|
156
|
+
test("Unordered ranges disable the index", () => {
|
|
157
|
+
const items = [
|
|
158
|
+
[10, 30],
|
|
159
|
+
[25, 50],
|
|
160
|
+
|
|
161
|
+
[112, 139],
|
|
162
|
+
[102, 129], // <- Unordered!
|
|
163
|
+
[121, 149],
|
|
164
|
+
];
|
|
165
|
+
const indexer = createBinningRangeIndexer(
|
|
166
|
+
100,
|
|
167
|
+
[0, 1000],
|
|
168
|
+
(x) => x[0],
|
|
169
|
+
(x) => x[1]
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
items.forEach((x, i) => indexer(x, i * 2, (i + 1) * 2));
|
|
173
|
+
|
|
174
|
+
const index = indexer.getIndex();
|
|
175
|
+
|
|
176
|
+
expect(index).toBeUndefined();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("Inverted ranges disable the index", () => {
|
|
180
|
+
const items = [
|
|
181
|
+
[10, 30],
|
|
182
|
+
[25, 50],
|
|
183
|
+
|
|
184
|
+
[102, 129],
|
|
185
|
+
[139, 112], // <- Inverted!
|
|
186
|
+
[121, 149],
|
|
187
|
+
];
|
|
188
|
+
const indexer = createBinningRangeIndexer(
|
|
189
|
+
100,
|
|
190
|
+
[0, 1000],
|
|
191
|
+
(x) => x[0],
|
|
192
|
+
(x) => x[1]
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
items.forEach((x, i) => indexer(x, i * 2, (i + 1) * 2));
|
|
196
|
+
|
|
197
|
+
const index = indexer.getIndex();
|
|
198
|
+
|
|
199
|
+
expect(index).toBeUndefined();
|
|
200
|
+
});
|
|
155
201
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gridView.d.ts","sourceRoot":"","sources":["../../../src/view/gridView.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gridView.d.ts","sourceRoot":"","sources":["../../../src/view/gridView.js"],"names":[],"mappings":"AAowBA;;;GAGG;AACH,iDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CAwB9C;AAED;;;GAGG;AACH,uDAHW,OAAO,iBAAiB,EAAE,cAAc,GACtC,OAAO,iBAAiB,EAAE,QAAQ,CA6C9C;AA2BD;;GAEG;AACH,8EAUC;AAED;;;;;GAKG;AACH,4CAJW,OAAO,uBAAuB,EAAE,OAAO,UACvC,OAAO,iBAAiB,EAAE,UAAU,YACpC,QAAQ,aAmBlB;AA33BD;;;;;;;;;;;;;;;GAeG;AACH;IA6BI;;;;;;;;;OASG;IACH,kBARW,OAAO,iBAAiB,EAAE,aAAa,WACvC,OAAO,yBAAyB,EAAE,OAAO,gBACzC,aAAa,iDAEb,MAAM,WACN,MAAM,YACN,OAAO,WAAW,EAAE,WAAW,EAoBzC;IARG,8CAAgB;IAOhB,uBAA0B;IAG9B;;OAEG;IACH,qDAIC;IAeD;;OAEG;IACH,wDAKC;IAqBD;;OAEG;IACH,8CAEC;IAED,yBAEC;IAED;;OAEG;IACH,wCAmCC;IA2OD;;;;OAIG;IAEH,gBALW,OAAO,4CAA4C,EAAE,OAAO,UAC5D,OAAO,uBAAuB,EAAE,OAAO,YACvC,OAAO,uBAAuB,EAAE,gBAAgB,QA6O1D;;CAmGJ;AAgJD;IACI;;;;OAIG;IACH,6DAHW,aAAa,UACb,MAAM,EAoFhB;IAjFG,4BAAgC;IAChC,kCAAgB;IAChB,eAAoB;IAEpB,uBAAuB;IACvB,YADW,QAAQ,CACQ;IAE3B,uBAAuB;IACvB,kBADW,QAAQ,CACc;IAEjC,mFAAmF;IACnF,MADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAC5D;IAEd,4FAA4F;IAC5F,WADW,QAAQ,OAAO,OAAO,iBAAiB,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC,CAC3D;IAEnB,0DAA0D;IAC1D,kEAAoB;IAEpB,uBAAuB;IACvB,OADW,QAAQ,CACG;IAEtB,wBAAwB;IACxB,QADW,SAAS,CACQ;IA4DhC,uEAcC;IAED;;OAEG;IACH,4BAkKC;IAED,uBAqBC;IAED,iCAEC;CACJ;qBAhrC0D,eAAe;sBAFpD,uBAAuB;0BAGnB,oBAAoB;qBAGzB,eAAe;yBALX,mBAAmB;AAmrC5C;IACI;;;OAGG;IACH,uBAHW,SAAS,8CAyFnB;IAtDG;;;MAAoB;IACpB,2CAAsC;IAKtC,uBAAuB;IAEvB,wBAAwB;IACxB,2BAAqC;IA+CzC,0BAKC;IAWD;;;;OAIG;IACH,gCAHW,SAAS,UACT,SAAS,QA8CnB;IA7BG,0BAAsE;CA8B7E;oBAp1CmB,qBAAqB"}
|