@genome-spy/core 0.29.0 → 0.30.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/index.js +32 -32
- package/package.json +2 -2
- package/src/genomeSpy.js +1 -0
- package/src/gl/webGLHelper.js +39 -24
- package/src/scale/glslScaleGenerator.js +25 -11
- package/src/view/scaleResolution.js +6 -0
- package/src/view/zoom.js +2 -2
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"contributors": [],
|
|
9
9
|
"license": "MIT",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.30.0",
|
|
11
11
|
"main": "dist/index.js",
|
|
12
12
|
"module": "src/index.js",
|
|
13
13
|
"exports": {
|
|
@@ -53,5 +53,5 @@
|
|
|
53
53
|
"vega-scale": "^7.1.1",
|
|
54
54
|
"vega-util": "^1.16.0"
|
|
55
55
|
},
|
|
56
|
-
"gitHead": "
|
|
56
|
+
"gitHead": "c8fe26f3421a1bec7323428f0bd7da46cda34dba"
|
|
57
57
|
}
|
package/src/genomeSpy.js
CHANGED
|
@@ -378,6 +378,7 @@ export default class GenomeSpy {
|
|
|
378
378
|
// Now that all data have been loaded, the domains may need adjusting
|
|
379
379
|
this.viewRoot.visit((view) => {
|
|
380
380
|
for (const resolution of Object.values(view.resolutions.scale)) {
|
|
381
|
+
// TODO: Don't reconfigure multiple times
|
|
381
382
|
// IMPORTANT TODO: Check that discrete domains and indexers match!!!!!!!!!
|
|
382
383
|
resolution.reconfigure();
|
|
383
384
|
}
|
package/src/gl/webGLHelper.js
CHANGED
|
@@ -9,7 +9,12 @@ import {
|
|
|
9
9
|
} from "twgl.js";
|
|
10
10
|
import { isArray, isString } from "vega-util";
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isContinuous,
|
|
14
|
+
isDiscrete,
|
|
15
|
+
isDiscretizing,
|
|
16
|
+
isInterpolating,
|
|
17
|
+
} from "vega-scale";
|
|
13
18
|
import {
|
|
14
19
|
createDiscreteColorTexture,
|
|
15
20
|
createDiscreteTexture,
|
|
@@ -321,43 +326,53 @@ export default class WebGLHelper {
|
|
|
321
326
|
const props = resolution.getScaleProps();
|
|
322
327
|
|
|
323
328
|
const scale = resolution.getScale();
|
|
329
|
+
const range = /** @type {any[]} */ (scale.range());
|
|
324
330
|
|
|
325
331
|
/** @type {WebGLTexture} */
|
|
326
332
|
let texture;
|
|
327
333
|
|
|
328
334
|
if (props.scheme) {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
count = fixCount(count, scale);
|
|
334
|
-
|
|
335
|
-
texture = createSchemeTexture(
|
|
336
|
-
props.scheme,
|
|
337
|
-
this.gl,
|
|
338
|
-
count,
|
|
339
|
-
existingTexture
|
|
340
|
-
);
|
|
341
|
-
} else {
|
|
342
|
-
// No scheme, assume that colors are specified in the range
|
|
343
|
-
|
|
344
|
-
const range = /** @type {any[]} */ (scale.range());
|
|
345
|
-
|
|
346
|
-
if (isInterpolating(scale.type)) {
|
|
347
|
-
texture = createInterpolatedColorTexture(
|
|
335
|
+
if (scale.type == "threshold" && range) {
|
|
336
|
+
// Scale initialization may have configured the range. Let's use it.
|
|
337
|
+
texture = createDiscreteColorTexture(
|
|
348
338
|
range,
|
|
349
|
-
props.interpolate,
|
|
350
339
|
this.gl,
|
|
340
|
+
scale.domain().length,
|
|
351
341
|
existingTexture
|
|
352
342
|
);
|
|
353
343
|
} else {
|
|
354
|
-
|
|
355
|
-
|
|
344
|
+
let count = isString(props.scheme)
|
|
345
|
+
? undefined
|
|
346
|
+
: props.scheme.count;
|
|
347
|
+
|
|
348
|
+
count = fixCount(count, scale);
|
|
349
|
+
|
|
350
|
+
texture = createSchemeTexture(
|
|
351
|
+
props.scheme,
|
|
356
352
|
this.gl,
|
|
357
|
-
|
|
353
|
+
count,
|
|
358
354
|
existingTexture
|
|
359
355
|
);
|
|
360
356
|
}
|
|
357
|
+
} else if (
|
|
358
|
+
// Interpolating
|
|
359
|
+
isInterpolating(scale.type) ||
|
|
360
|
+
// Or piecewise
|
|
361
|
+
(isContinuous(scale.type) && range.length > 2)
|
|
362
|
+
) {
|
|
363
|
+
texture = createInterpolatedColorTexture(
|
|
364
|
+
range,
|
|
365
|
+
props.interpolate,
|
|
366
|
+
this.gl,
|
|
367
|
+
existingTexture
|
|
368
|
+
);
|
|
369
|
+
} else {
|
|
370
|
+
texture = createDiscreteColorTexture(
|
|
371
|
+
range,
|
|
372
|
+
this.gl,
|
|
373
|
+
scale.domain().length,
|
|
374
|
+
existingTexture
|
|
375
|
+
);
|
|
361
376
|
}
|
|
362
377
|
|
|
363
378
|
this.rangeTextures.set(resolution, texture);
|
|
@@ -314,7 +314,7 @@ export function generateScaleGlsl(channel, scale, channelDef) {
|
|
|
314
314
|
if (piecewise) {
|
|
315
315
|
// TODO: Handle range correctly. Now this assumes unit range.
|
|
316
316
|
scaleBody.push(
|
|
317
|
-
`transformed = (float(slot) + transformed) / (float(${name}.length()
|
|
317
|
+
`transformed = (float(slot) + transformed) / (float(${name}.length() - 1));`
|
|
318
318
|
);
|
|
319
319
|
}
|
|
320
320
|
} else {
|
|
@@ -463,26 +463,40 @@ export function isHighPrecisionScale(type) {
|
|
|
463
463
|
return type == "index" || type == "locus";
|
|
464
464
|
}
|
|
465
465
|
|
|
466
|
+
// Maximum precise index number is 2^(23 + 11) ~ 17G
|
|
467
|
+
// Higher number increases precision but makes zooming unstable
|
|
468
|
+
const BS = 2 ** 11;
|
|
469
|
+
const BM = BS - 1;
|
|
470
|
+
|
|
466
471
|
/**
|
|
467
|
-
* @param {number} x
|
|
472
|
+
* @param {number} x Must be an integer
|
|
468
473
|
* @param {number[]} [arr]
|
|
469
474
|
*/
|
|
470
|
-
export function splitHighPrecision(x, arr) {
|
|
471
|
-
//
|
|
472
|
-
//
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const hi = Math.round(x - lo);
|
|
477
|
-
arr ??= [];
|
|
475
|
+
export function splitHighPrecision(x, arr = []) {
|
|
476
|
+
// Using a bitmask is MUCH faster than using modulo (at least on Chrome 112)
|
|
477
|
+
// https://www.wikiwand.com/en/Modulo#Performance_issues
|
|
478
|
+
const lo = x & BM;
|
|
479
|
+
const hi = x - lo;
|
|
480
|
+
|
|
478
481
|
arr[0] = hi;
|
|
479
482
|
arr[1] = lo;
|
|
483
|
+
|
|
480
484
|
return arr;
|
|
481
485
|
}
|
|
482
486
|
|
|
487
|
+
/**
|
|
488
|
+
* @param {number} x
|
|
489
|
+
*/
|
|
490
|
+
function exactSplitHighPrecision(x) {
|
|
491
|
+
const lo = x % BS;
|
|
492
|
+
const hi = x - lo;
|
|
493
|
+
|
|
494
|
+
return [hi, lo];
|
|
495
|
+
}
|
|
496
|
+
|
|
483
497
|
/**
|
|
484
498
|
* @param {number[]} domain
|
|
485
499
|
*/
|
|
486
500
|
export function toHighPrecisionDomainUniform(domain) {
|
|
487
|
-
return [...
|
|
501
|
+
return [...exactSplitHighPrecision(domain[0]), domain[1] - domain[0]];
|
|
488
502
|
}
|
|
@@ -220,6 +220,12 @@ export default class ScaleResolution {
|
|
|
220
220
|
props.domain = domain;
|
|
221
221
|
} else if (isDiscrete(props.type)) {
|
|
222
222
|
props.domain = new NominalDomain();
|
|
223
|
+
} else if (props.scheme) {
|
|
224
|
+
// An initial domain is required when using a scheme.
|
|
225
|
+
// Otherwise configureScale() does something weird when the domain is set later,
|
|
226
|
+
// resulting in an interpolator between just two colors.
|
|
227
|
+
// TODO: Fix configureScale().
|
|
228
|
+
props.domain = [0, 1];
|
|
223
229
|
}
|
|
224
230
|
|
|
225
231
|
if (!props.domain && props.domainMid !== undefined) {
|
package/src/view/zoom.js
CHANGED
|
@@ -30,10 +30,10 @@ export default function interactionToZoom(event, coords, handleZoom, hover) {
|
|
|
30
30
|
|
|
31
31
|
if (hover) {
|
|
32
32
|
const e = hover.mark.encoders;
|
|
33
|
-
if (e.x && !e.x2) {
|
|
33
|
+
if (e.x && !e.x2 && !e.x.constantValue) {
|
|
34
34
|
x = +e.x(hover.datum) * coords.width + coords.x;
|
|
35
35
|
}
|
|
36
|
-
if (e.y && !e.y2) {
|
|
36
|
+
if (e.y && !e.y2 && !e.y.constantValue) {
|
|
37
37
|
y = (1 - +e.y(hover.datum)) * coords.height + coords.y;
|
|
38
38
|
}
|
|
39
39
|
}
|