higlass 1.12.4 → 1.13.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/README.md +3 -3
- package/app/globals.d.ts +11 -0
- package/app/missing-types.d.ts +21 -0
- package/app/scripts/CenterTrack.jsx +0 -1
- package/app/scripts/DraggableDiv.jsx +0 -1
- package/app/scripts/GenomePositionSearchBox.jsx +0 -1
- package/app/scripts/TrackRenderer.jsx +405 -89
- package/app/scripts/VerticalTiledPlot.jsx +0 -1
- package/app/scripts/configs/default-tracks-for-datatype.js +3 -2
- package/app/scripts/configs/primitives.js +3 -2
- package/app/scripts/configs/tracks-info-by-type.js +4 -1
- package/app/scripts/configs/tracks-info.js +25 -1
- package/app/scripts/types.ts +79 -0
- package/app/scripts/utils/abs-to-chr.js +16 -1
- package/app/scripts/utils/accessor-transposition.js +5 -4
- package/app/scripts/utils/add-arrays.js +9 -7
- package/app/scripts/utils/add-class.js +4 -2
- package/app/scripts/utils/add-event-listener-once.js +9 -3
- package/app/scripts/utils/background-task-scheduler.js +58 -2
- package/app/scripts/utils/base64-to-canvas.js +12 -5
- package/app/scripts/utils/chr-to-abs.js +10 -0
- package/app/scripts/utils/chrom-info-bisector.js +4 -1
- package/app/scripts/utils/clone-event.js +11 -4
- package/app/scripts/utils/color-to-hex.js +8 -0
- package/app/scripts/utils/color-to-rgba.js +8 -0
- package/app/scripts/utils/data-to-genomic-loci.js +13 -1
- package/app/scripts/utils/debounce.js +16 -11
- package/app/scripts/utils/dec-to-hex-str.js +7 -0
- package/app/scripts/utils/dict-from-tuples.js +11 -3
- package/app/scripts/utils/dict-items.js +15 -0
- package/app/scripts/utils/dict-keys.js +11 -1
- package/app/scripts/utils/dict-values.js +7 -0
- package/app/scripts/utils/download.js +14 -11
- package/app/scripts/utils/flatten.js +5 -2
- package/app/scripts/utils/for-each.js +7 -5
- package/app/scripts/utils/forward-event.js +3 -2
- package/app/scripts/utils/genome-loci-to-pixels.js +8 -0
- package/app/scripts/utils/genomic-range-to-chromosome-chunks.js +13 -6
- package/app/scripts/utils/get-aggregation-function.js +10 -2
- package/app/scripts/utils/get-element-dim.js +6 -0
- package/app/scripts/utils/gradient.js +14 -0
- package/app/scripts/utils/has-class.js +6 -4
- package/app/scripts/utils/hex-string-to-int.js +11 -4
- package/app/scripts/utils/index.js +1 -0
- package/app/scripts/utils/into-the-void.js +2 -1
- package/app/scripts/utils/is-track-or-child-track.js +6 -0
- package/app/scripts/utils/is-track-range-selectable.js +10 -1
- package/app/scripts/utils/is-within.js +9 -7
- package/app/scripts/utils/lat-to-y.js +6 -3
- package/app/scripts/utils/lng-to-x.js +4 -3
- package/app/scripts/utils/map.js +5 -2
- package/app/scripts/utils/max-non-zero.js +6 -0
- package/app/scripts/utils/max.js +4 -3
- package/app/scripts/utils/min-non-zero.js +6 -0
- package/app/scripts/utils/min.js +4 -3
- package/app/scripts/utils/mod.js +4 -3
- package/app/scripts/utils/numericify-version.js +5 -0
- package/app/scripts/utils/obj-vals.js +3 -2
- package/app/scripts/utils/or.js +4 -3
- package/app/scripts/utils/parse-chromsizes-rows.js +26 -5
- package/app/scripts/utils/q.js +3 -2
- package/app/scripts/utils/rad-to-deg.js +3 -2
- package/app/scripts/utils/reduce.js +2 -2
- package/app/scripts/utils/rel-to-abs-chrom-pos.js +10 -0
- package/app/scripts/utils/remove-class.js +3 -2
- package/app/scripts/utils/reset-d3-brush-style.js +7 -2
- package/app/scripts/utils/rgb-to-hex.js +9 -0
- package/app/scripts/utils/scales-center-and-k.js +5 -3
- package/app/scripts/utils/scales-to-genome-loci.js +10 -0
- package/app/scripts/utils/selected-items-to-cum-weights.js +12 -4
- package/app/scripts/utils/selected-items-to-size.js +5 -2
- package/app/scripts/utils/show-mouse-position.js +62 -19
- package/app/scripts/utils/some.js +6 -4
- package/app/scripts/utils/sum.js +4 -3
- package/app/scripts/utils/throttle-and-debounce.js +15 -6
- package/app/scripts/utils/tile-to-canvas.js +8 -4
- package/app/scripts/utils/timeout.js +2 -0
- package/app/scripts/utils/to-void.js +2 -0
- package/app/scripts/utils/total-track-pixel-height.js +11 -12
- package/app/scripts/utils/trim-trailing-slash.js +3 -2
- package/app/scripts/utils/type-guards.js +17 -0
- package/app/scripts/utils/value-to-color.js +7 -6
- package/app/scripts/utils/visit-positioned-tracks.js +16 -11
- package/app/scripts/utils/visit-tracks.js +12 -13
- package/dist/hglib.js +204 -131
- package/dist/hglib.min.js +70 -70
- package/package.json +16 -5
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
export const DEFAULT_TRACKS_FOR_DATATYPE = /** @type {const} */ ({
|
|
2
3
|
chromsizes: {
|
|
3
4
|
center: '2d-chromosome-grid',
|
|
4
5
|
top: 'chromosome-labels',
|
|
@@ -34,6 +35,6 @@ export const DEFAULT_TRACKS_FOR_DATATYPE = {
|
|
|
34
35
|
left: 'vertical-bedlike',
|
|
35
36
|
right: 'vertical-bedlike',
|
|
36
37
|
},
|
|
37
|
-
};
|
|
38
|
+
});
|
|
38
39
|
|
|
39
40
|
export default DEFAULT_TRACKS_FOR_DATATYPE;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
export const DEFAULT_VIEW_MARGIN = 0;
|
|
2
3
|
|
|
3
4
|
export const DEFAULT_VIEW_PADDING = 5;
|
|
@@ -32,7 +33,7 @@ export const VIEW_HEADER_MED_WIDTH_SEARCH_BAR = 400;
|
|
|
32
33
|
|
|
33
34
|
export const VIEW_HEADER_MIN_WIDTH_SEARCH_BAR = 300;
|
|
34
35
|
|
|
35
|
-
export const TRACK_LOCATIONS = [
|
|
36
|
+
export const TRACK_LOCATIONS = /** @type {const} */ ([
|
|
36
37
|
'top',
|
|
37
38
|
'left',
|
|
38
39
|
'right',
|
|
@@ -40,7 +41,7 @@ export const TRACK_LOCATIONS = [
|
|
|
40
41
|
'center',
|
|
41
42
|
'whole',
|
|
42
43
|
'gallery',
|
|
43
|
-
];
|
|
44
|
+
]);
|
|
44
45
|
|
|
45
46
|
export const MIN_HORIZONTAL_HEIGHT = 20;
|
|
46
47
|
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import { TRACKS_INFO } from './tracks-info';
|
|
2
3
|
|
|
4
|
+
/** @typedef {Record<string, import('./tracks-info').TrackInfo>} TracksInfoByType */
|
|
5
|
+
|
|
3
6
|
export const TRACKS_INFO_BY_TYPE = TRACKS_INFO.reduce((tracksByType, track) => {
|
|
4
7
|
tracksByType[track.type] = track;
|
|
5
8
|
if (track.aliases) {
|
|
@@ -8,6 +11,6 @@ export const TRACKS_INFO_BY_TYPE = TRACKS_INFO.reduce((tracksByType, track) => {
|
|
|
8
11
|
}
|
|
9
12
|
}
|
|
10
13
|
return tracksByType;
|
|
11
|
-
}, {});
|
|
14
|
+
}, /** @type {TracksInfoByType} */ ({}));
|
|
12
15
|
|
|
13
16
|
export default TRACKS_INFO_BY_TYPE;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import { THEME_DARK } from './themes';
|
|
2
3
|
|
|
3
4
|
import {
|
|
@@ -14,6 +15,28 @@ import {
|
|
|
14
15
|
svgGeoMapIcon,
|
|
15
16
|
} from '../icons';
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @typedef TrackInfo
|
|
20
|
+
* @property {string} type
|
|
21
|
+
* @property {string | string[]} datatype
|
|
22
|
+
* @property {string} orientation
|
|
23
|
+
* @property {string[]=} aliases
|
|
24
|
+
* @property {boolean=} local
|
|
25
|
+
* @property {boolean=} rotatable
|
|
26
|
+
* @property {boolean=} hidden
|
|
27
|
+
* @property {string=} name
|
|
28
|
+
* @property {HTMLElement | null | string=} thumbnail
|
|
29
|
+
* @property {string[]=} availableOptions
|
|
30
|
+
* @property {Record<string, unknown>=} defaultOptions
|
|
31
|
+
* @property {boolean=} exportable
|
|
32
|
+
* @property {Record<string, Record<string, unknown>>=} defaultOptionsByTheme
|
|
33
|
+
* @property {number=} minHeight
|
|
34
|
+
* @property {number=} defaultHeight
|
|
35
|
+
* @property {number=} defaultWidth
|
|
36
|
+
* @property {string=} chromInfoPath
|
|
37
|
+
* @property {boolean=} projection
|
|
38
|
+
*/
|
|
39
|
+
|
|
17
40
|
const osm = {
|
|
18
41
|
type: 'osm-tiles',
|
|
19
42
|
datatype: ['map-tiles'],
|
|
@@ -72,6 +95,7 @@ const mapbox = {
|
|
|
72
95
|
},
|
|
73
96
|
};
|
|
74
97
|
|
|
98
|
+
/** @type {TrackInfo[]} */
|
|
75
99
|
export const TRACKS_INFO = [
|
|
76
100
|
osm,
|
|
77
101
|
{ ...osm, type: 'osm' },
|
|
@@ -682,7 +706,7 @@ export const TRACKS_INFO = [
|
|
|
682
706
|
aliases: ['horizontal-1d-value-interval', 'vertical-1d-value-interval'],
|
|
683
707
|
datatype: ['bed-value'],
|
|
684
708
|
local: false,
|
|
685
|
-
orientation:
|
|
709
|
+
orientation: '1d-horizontal',
|
|
686
710
|
rotatable: true,
|
|
687
711
|
name: '1D Rectangles',
|
|
688
712
|
availableOptions: [
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
export type Scale = import("d3-scale").ScaleContinuousNumeric<number, number>;
|
|
4
|
+
|
|
5
|
+
export type TrackPosition = typeof import('./configs/primitives').TRACK_LOCATIONS[number];
|
|
6
|
+
|
|
7
|
+
export type ChromInfo<Name extends string = string> = {
|
|
8
|
+
cumPositions: { id?: number; pos: number; chr: Name }[];
|
|
9
|
+
chrPositions: Record<Name, { pos: number }>;
|
|
10
|
+
chromLengths: Record<Name, number>;
|
|
11
|
+
totalLength: number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type UnknownTrackConfig = {
|
|
15
|
+
uid: string;
|
|
16
|
+
options: Record<string, unknown>;
|
|
17
|
+
type: string;
|
|
18
|
+
position: TrackPosition;
|
|
19
|
+
data?: Record<string, unknown>;
|
|
20
|
+
server: string;
|
|
21
|
+
tilesetUid: string;
|
|
22
|
+
coordSystem?: unknown;
|
|
23
|
+
x?: number;
|
|
24
|
+
y?: number;
|
|
25
|
+
chromInfoPath: string;
|
|
26
|
+
projectionXDomain?: [number, number];
|
|
27
|
+
projectionYDomain?: [number, number];
|
|
28
|
+
registerViewportChanged?: unknown;
|
|
29
|
+
removeViewportChanged?: unknown;
|
|
30
|
+
setDomainsCallback?: unknown;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type CombinedTrackConfig = {
|
|
34
|
+
uid: string;
|
|
35
|
+
options: Record<string, unknown>;
|
|
36
|
+
contents: TrackConfig[];
|
|
37
|
+
type: 'combined';
|
|
38
|
+
position: TrackPosition;
|
|
39
|
+
data?: Record<string, unknown>;
|
|
40
|
+
server: string;
|
|
41
|
+
tilesetUid: string;
|
|
42
|
+
coordSystem?: unknown;
|
|
43
|
+
x?: number;
|
|
44
|
+
y?: number;
|
|
45
|
+
chromInfoPath: string;
|
|
46
|
+
projectionXDomain?: [number, number];
|
|
47
|
+
projectionYDomain?: [number, number];
|
|
48
|
+
registerViewportChanged?: unknown;
|
|
49
|
+
removeViewportChanged?: unknown;
|
|
50
|
+
setDomainsCallback?: unknown;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type TrackConfig = UnknownTrackConfig | CombinedTrackConfig;
|
|
54
|
+
|
|
55
|
+
export type TrackVisitor = {
|
|
56
|
+
(track: TrackConfig, position: null | TrackPosition): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
type ZoomedFunction = {
|
|
60
|
+
(xScale: Scale, yScale: Scale, k?: number, x?: number, y?: number, xPosition?: number, yPosition?: number): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface TrackObject {
|
|
64
|
+
draw(): void;
|
|
65
|
+
rerender(options: unknown): void;
|
|
66
|
+
delayDrawing: boolean;
|
|
67
|
+
childTracks?: TrackObject[];
|
|
68
|
+
createdTracks: Record<string, TrackObject>;
|
|
69
|
+
refScalesChanged(x: Scale, y: Scale): void;
|
|
70
|
+
position: [number, number];
|
|
71
|
+
dimensions: [number, number];
|
|
72
|
+
updateContents(contents: TrackConfig[], x: unknown): TrackObject;
|
|
73
|
+
zoomed: ZoomedFunction;
|
|
74
|
+
setPosition(position: [number, number]): void;
|
|
75
|
+
setDimensions(dimensions: [number, number]): void;
|
|
76
|
+
remove(): void;
|
|
77
|
+
movedY(extent: number): void;
|
|
78
|
+
zoomedY(yPosition: number, wheelDelta: number): void;
|
|
79
|
+
}
|
|
@@ -1,5 +1,18 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import chromInfoBisector from './chrom-info-bisector';
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* @template {string} Name
|
|
6
|
+
* @typedef {[name: Name, pos: number, offset: number, insertPoint: number ]} ChromosomePosition
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Convert an absolute genome position to a chromosome position.
|
|
11
|
+
* @template {string} Name
|
|
12
|
+
* @param {number} absPosition - Absolute genome position.
|
|
13
|
+
* @param {import('../types').ChromInfo<Name>} chromInfo - Chromosome info object.
|
|
14
|
+
* @return {ChromosomePosition<Name> | null} The chromosome position.
|
|
15
|
+
*/
|
|
3
16
|
const absToChr = (absPosition, chromInfo) => {
|
|
4
17
|
if (!chromInfo || !chromInfo.cumPositions || !chromInfo.cumPositions.length) {
|
|
5
18
|
return null;
|
|
@@ -9,7 +22,9 @@ const absToChr = (absPosition, chromInfo) => {
|
|
|
9
22
|
const lastChr = chromInfo.cumPositions[chromInfo.cumPositions.length - 1].chr;
|
|
10
23
|
const lastLength = chromInfo.chromLengths[lastChr];
|
|
11
24
|
|
|
12
|
-
|
|
25
|
+
if (insertPoint > 0) {
|
|
26
|
+
insertPoint -= 1;
|
|
27
|
+
}
|
|
13
28
|
|
|
14
29
|
let chrPosition = Math.floor(
|
|
15
30
|
absPosition - chromInfo.cumPositions[insertPoint].pos,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Factory function for a transposition accessor for a 2D matrix in form of a 1D
|
|
3
5
|
* array.
|
|
@@ -6,10 +8,9 @@
|
|
|
6
8
|
* i^T = column * i + row
|
|
7
9
|
* where column: `Math.floor(i / x)` and row: `Math.floor(i / x)`
|
|
8
10
|
*
|
|
9
|
-
* @param
|
|
10
|
-
* @param
|
|
11
|
-
* @return
|
|
12
|
-
* the transposed index
|
|
11
|
+
* @param {number} x - X dimension of the 2D matrix
|
|
12
|
+
* @param {number} y - Y dimension of the 2D matrix
|
|
13
|
+
* @return {(index: number) => number} Accessor function converting the orignal 1D index into the transposed index
|
|
13
14
|
*/
|
|
14
15
|
const accessorTransposition = (x, y) => (i) => (i % x) * y + Math.floor(i / x);
|
|
15
16
|
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/** @type {<T>(index: T) => T} */
|
|
4
|
+
const identity = (i) => i;
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* Add two 1D arrays
|
|
@@ -11,13 +14,12 @@ const STD_ACC = (i) => i;
|
|
|
11
14
|
* addArrays([1,2,3], [2,3,4,5]) === [3,5,7]
|
|
12
15
|
* ```
|
|
13
16
|
*
|
|
14
|
-
* @param
|
|
15
|
-
* @param
|
|
16
|
-
* @param
|
|
17
|
-
*
|
|
18
|
-
* @return {Array} Combination of both arrays.
|
|
17
|
+
* @param {Array<number>} a1 - First array of numbers
|
|
18
|
+
* @param {Array<number>} a2 - Second array of numbers
|
|
19
|
+
* @param {(index: number) => number} accessor - Allows to use custom accessors. This can be useful when a2 represents a transformed (e.g., transposed matrix).
|
|
20
|
+
* @return {Array<number>} - Combination of both arrays.
|
|
19
21
|
*/
|
|
20
|
-
const addArrays = (a1, a2, accessor =
|
|
22
|
+
const addArrays = (a1, a2, accessor = identity) =>
|
|
21
23
|
a1.map((val, i) => val + a2[accessor(i)]);
|
|
22
24
|
|
|
23
25
|
export default addArrays;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import hasClass from './has-class';
|
|
2
3
|
|
|
3
4
|
const XMLNS = 'http://www.w3.org/2000/svg';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Method to add a class name to an HTML or SVG element.
|
|
7
|
-
* @param
|
|
8
|
-
* @param
|
|
8
|
+
* @param {Element} el - HTML or SVG element to add a class to.
|
|
9
|
+
* @param {string} className - The class name to be added.
|
|
10
|
+
* @returns {void}
|
|
9
11
|
*/
|
|
10
12
|
const addClass = (el, className) => {
|
|
11
13
|
if (el.namespaceURI === XMLNS) {
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Add an event listener that fires only once and auto-removes itself
|
|
3
|
-
*
|
|
4
|
-
* @
|
|
5
|
-
*
|
|
5
|
+
*
|
|
6
|
+
* @template {keyof HTMLElementEventMap} K
|
|
7
|
+
*
|
|
8
|
+
* @param {HTMLElement} element - DOM element to assign listener to.
|
|
9
|
+
* @param {K} eventName - Event name to listen to.
|
|
10
|
+
* @param {(event: HTMLElementEventMap[K]) => void} f - Event callback function.
|
|
6
11
|
*/
|
|
7
12
|
const addEventListenerOnce = (element, eventName, f) => {
|
|
13
|
+
/** @type {(event: HTMLElementEventMap[K]) => void} */
|
|
8
14
|
const callback = (event) => {
|
|
9
15
|
f(event);
|
|
10
16
|
element.removeEventListener(eventName, callback);
|
|
@@ -1,10 +1,63 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @template T
|
|
5
|
+
* @typedef DataTask
|
|
6
|
+
* @property {T} data
|
|
7
|
+
* @property {(data: T) => void} handler
|
|
8
|
+
* @property {string=} trackId
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef NullDataTask
|
|
13
|
+
* @property {null} data
|
|
14
|
+
* @property {() => void} handler
|
|
15
|
+
* @property {string=} trackId
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** @typedef {DataTask<any> | NullDataTask} Task */
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {Task} task
|
|
22
|
+
* @return {task is NullDataTask}
|
|
23
|
+
*/
|
|
24
|
+
function isNullDataTask(task) {
|
|
25
|
+
return task.data === null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
*/
|
|
1
30
|
class BackgroundTaskScheduler {
|
|
2
31
|
constructor() {
|
|
32
|
+
/** @type {Task[]} */
|
|
3
33
|
this.taskList = [];
|
|
4
34
|
this.taskHandle = null;
|
|
5
35
|
this.requestIdleCallbackTimeout = 300;
|
|
6
36
|
}
|
|
7
37
|
|
|
38
|
+
/**
|
|
39
|
+
* @template T
|
|
40
|
+
* @overload
|
|
41
|
+
* @param {(data: T) => void} taskHandler
|
|
42
|
+
* @param {T} taskData
|
|
43
|
+
* @param {string | null=} trackId
|
|
44
|
+
* @return {void}
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* If `taskData` is `null` the `taskHandler` will eventaully be called without any arguments.
|
|
48
|
+
*
|
|
49
|
+
* @overload
|
|
50
|
+
* @param {() => void} taskHandler
|
|
51
|
+
* @param {null} taskData
|
|
52
|
+
* @param {string | null=} trackId
|
|
53
|
+
* @return {void}
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* @param {(data: any) => void} taskHandler
|
|
57
|
+
* @param {any} taskData
|
|
58
|
+
* @param {string | null} trackId
|
|
59
|
+
* @return {void}
|
|
60
|
+
*/
|
|
8
61
|
enqueueTask(taskHandler, taskData, trackId = null) {
|
|
9
62
|
if (trackId === null) {
|
|
10
63
|
this.taskList.push({
|
|
@@ -30,6 +83,9 @@ class BackgroundTaskScheduler {
|
|
|
30
83
|
}
|
|
31
84
|
}
|
|
32
85
|
|
|
86
|
+
/**
|
|
87
|
+
* @param {{ timeRemaining(): number, didTimeout: boolean }} deadline
|
|
88
|
+
*/
|
|
33
89
|
runTaskQueue(deadline) {
|
|
34
90
|
while (
|
|
35
91
|
(deadline.timeRemaining() > 0 || deadline.didTimeout) &&
|
|
@@ -37,9 +93,9 @@ class BackgroundTaskScheduler {
|
|
|
37
93
|
) {
|
|
38
94
|
const task = this.taskList.shift();
|
|
39
95
|
|
|
40
|
-
if (task
|
|
96
|
+
if (task && isNullDataTask(task)) {
|
|
41
97
|
task.handler();
|
|
42
|
-
} else {
|
|
98
|
+
} else if (task) {
|
|
43
99
|
task.handler(task.data);
|
|
44
100
|
}
|
|
45
101
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Convert a base64 encoded image into a canvas object.
|
|
3
|
-
* @param
|
|
4
|
-
* @param
|
|
5
|
-
* @param
|
|
6
|
-
* @return
|
|
5
|
+
* @param {string} base64 - Base64 string encoding the image.
|
|
6
|
+
* @param {number} width - Custom width for the canvas object.
|
|
7
|
+
* @param {number} height - Custom height for the canvas object.
|
|
8
|
+
* @return {Promise<HTMLCanvasElement>} The converted canvas object
|
|
7
9
|
*/
|
|
8
10
|
const base64ToCanvas = (base64, width, height) => {
|
|
9
11
|
const canvas = document.createElement('canvas');
|
|
@@ -13,7 +15,12 @@ const base64ToCanvas = (base64, width, height) => {
|
|
|
13
15
|
img.onload = () => {
|
|
14
16
|
canvas.width = width || img.width;
|
|
15
17
|
canvas.height = height || img.height;
|
|
16
|
-
canvas.getContext('2d')
|
|
18
|
+
const context = canvas.getContext('2d');
|
|
19
|
+
if (!context) {
|
|
20
|
+
reject(new Error('Could not get canvas context'));
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
context.drawImage(img, 0, 0);
|
|
17
24
|
resolve(canvas);
|
|
18
25
|
};
|
|
19
26
|
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert a chromosome position to an absolute genome position.
|
|
5
|
+
*
|
|
6
|
+
* @template {string} Name
|
|
7
|
+
* @param {Name} chrom - Chromosome name
|
|
8
|
+
* @param {number} chromPos - Chromosome position
|
|
9
|
+
* @param {import('../types').ChromInfo<Name>} chromInfo - Chromosome info object
|
|
10
|
+
*/
|
|
1
11
|
const chrToAbs = (chrom, chromPos, chromInfo) =>
|
|
2
12
|
chromInfo.chrPositions[chrom].pos + chromPos;
|
|
3
13
|
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
* Clone an event by invoking the source event's constructor and passing in
|
|
3
|
-
*
|
|
4
|
-
* @
|
|
5
|
-
* @
|
|
4
|
+
* Clone an event by invoking the source event's constructor and passing in the source event.
|
|
5
|
+
*
|
|
6
|
+
* @template {Event & { sourceUid?: string, forwarded?: boolean }} TEvent
|
|
7
|
+
* @param {TEvent} event - Source event to be cloned.
|
|
8
|
+
* @return {TEvent} Cloned event
|
|
6
9
|
*/
|
|
7
10
|
const cloneEvent = (event) => {
|
|
11
|
+
if (!(event instanceof Event)) {
|
|
12
|
+
throw new Error('Event must be an instance of Event');
|
|
13
|
+
}
|
|
14
|
+
// @ts-expect-error - TS doesn't know about the constructor property.
|
|
8
15
|
const newEvent = new event.constructor(event.type, event);
|
|
9
16
|
newEvent.sourceUid = event.sourceUid;
|
|
10
17
|
newEvent.forwarded = event.forwarded;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import { color } from 'd3-color';
|
|
2
3
|
|
|
3
4
|
// Configs
|
|
@@ -6,8 +7,15 @@ import { GLOBALS } from '../configs';
|
|
|
6
7
|
/**
|
|
7
8
|
* Convert a regular color value (e.g. 'red', '#FF0000', 'rgb(255,0,0)') to a
|
|
8
9
|
* hex value which is legible by PIXI
|
|
10
|
+
*
|
|
11
|
+
* @param {string} colorValue - Color value to convert
|
|
12
|
+
* @return {number} Hex value
|
|
9
13
|
*/
|
|
10
14
|
const colorToHex = (colorValue) => {
|
|
15
|
+
/** @type {import('d3-color').RGBColor} */
|
|
16
|
+
// @ts-expect-error - FIXME: `color` can return many different types
|
|
17
|
+
// depending on the string input. We should probably use a different
|
|
18
|
+
// the more strict `rgb` function instead?
|
|
11
19
|
const c = color(colorValue);
|
|
12
20
|
const hex = GLOBALS.PIXI.utils.rgb2hex([
|
|
13
21
|
c.r / 255.0,
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import { color } from 'd3-color';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Convert a regular color value (e.g. 'red', '#FF0000', 'rgb(255,0,0)') to a
|
|
5
6
|
* RGBA array, with support for the value "transparent".
|
|
7
|
+
*
|
|
8
|
+
* @param {string} colorValue - An RGB(A) color value to convert.
|
|
9
|
+
* @return {[r: number, g: number, b: number, a: number]} An RGBA array.
|
|
6
10
|
*/
|
|
7
11
|
const colorToRgba = (colorValue) => {
|
|
8
12
|
if (colorValue === 'transparent') {
|
|
9
13
|
return [255, 255, 255, 0];
|
|
10
14
|
}
|
|
15
|
+
/** @type {import('d3-color').RGBColor} */
|
|
16
|
+
// @ts-expect-error - FIXME: `color` can return many different types
|
|
17
|
+
// depending on the string input. We should probably use a different
|
|
18
|
+
// the more strict `rgb` function instead?
|
|
11
19
|
const c = color(colorValue);
|
|
12
20
|
return [c.r, c.g, c.b, 255];
|
|
13
21
|
};
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
import absToChr from './abs-to-chr';
|
|
2
3
|
|
|
4
|
+
/** @typedef {[startChromName: string, startChromPos: number, endChromName: string, endChromPos: number]} GenomicLoci */
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Convert a pair of data coordinates to genomic coordinates.
|
|
8
|
+
* @param {number} x0 - The first data coordinate.
|
|
9
|
+
* @param {number} x1 - The second data coordinate.
|
|
10
|
+
* @param {import('../types').ChromInfo} chromInfo - The chromosome info object.
|
|
11
|
+
* @returns {GenomicLoci} The genomic coordinates.
|
|
12
|
+
*/
|
|
3
13
|
const dataToGenomicLoci = (x0, x1, chromInfo) => {
|
|
4
14
|
const gX0 = absToChr(x0, chromInfo);
|
|
5
15
|
const gX1 = absToChr(x1, chromInfo);
|
|
6
|
-
|
|
16
|
+
if (!gX0 || !gX1) {
|
|
17
|
+
throw new Error("Couldn't convert data to genomic coordinates");
|
|
18
|
+
}
|
|
7
19
|
return [gX0[0], Math.round(gX0[1]), gX1[0], Math.round(gX1[1])];
|
|
8
20
|
};
|
|
9
21
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Debounce a function call
|
|
3
5
|
*
|
|
@@ -9,21 +11,24 @@
|
|
|
9
11
|
* Once webpack 2 with tree-shaking is supported I'd advocate to use lodash's
|
|
10
12
|
* debounce method.
|
|
11
13
|
*
|
|
12
|
-
* @method
|
|
13
|
-
* @author
|
|
14
|
-
* @date
|
|
15
|
-
*
|
|
16
|
-
* @
|
|
17
|
-
*
|
|
18
|
-
* @param
|
|
19
|
-
* @
|
|
14
|
+
* @method debounce
|
|
15
|
+
* @author Fritz Lekschas
|
|
16
|
+
* @date 2017-01-14
|
|
17
|
+
*
|
|
18
|
+
* @template {any[]} Args
|
|
19
|
+
* @param {(...args: Args) => void} func - Function to be debounced
|
|
20
|
+
* @param {number} wait - Number of milliseconds to debounce the function call.
|
|
21
|
+
* @param {boolean} immediate - If `true` function is not debounced.
|
|
22
|
+
* @return {{ (...args: Args): void, cancel(): void }} Debounced function.
|
|
20
23
|
*/
|
|
21
24
|
export const debounce = (func, wait, immediate) => {
|
|
25
|
+
/** @type {ReturnType<typeof setTimeout> | undefined} */
|
|
22
26
|
let timeout;
|
|
23
27
|
|
|
28
|
+
/** @param {Args} args */
|
|
24
29
|
const debounced = (...args) => {
|
|
25
30
|
const later = () => {
|
|
26
|
-
timeout =
|
|
31
|
+
timeout = undefined;
|
|
27
32
|
if (!immediate) {
|
|
28
33
|
func(...args);
|
|
29
34
|
}
|
|
@@ -38,9 +43,9 @@ export const debounce = (func, wait, immediate) => {
|
|
|
38
43
|
}
|
|
39
44
|
};
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
debounced.cancel = () => {
|
|
42
47
|
clearTimeout(timeout);
|
|
43
|
-
timeout =
|
|
48
|
+
timeout = undefined;
|
|
44
49
|
};
|
|
45
50
|
|
|
46
51
|
return debounced;
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
|
-
* Create a dictionary from a list of [key,value] pairs.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
4
|
+
* Create a dictionary from a list of [key, value] pairs.
|
|
5
|
+
*
|
|
6
|
+
* TODO(Trevor): Replace with Object.fromEntries?
|
|
7
|
+
*
|
|
8
|
+
* @template {ReadonlyArray<readonly [PropertyKey, unknown]>} T
|
|
9
|
+
* @param {T} tuples: A list of [key, value] pairs
|
|
10
|
+
* @return {{ [Item in T[number] as Item[0]]: Item[1] }} A dictionary
|
|
5
11
|
*/
|
|
6
12
|
const dictFromTuples = (tuples) => {
|
|
13
|
+
/** @type {Record<PropertyKey, unknown>} */
|
|
7
14
|
const dict = {};
|
|
8
15
|
|
|
9
16
|
tuples.forEach((x) => {
|
|
10
17
|
dict[x[0]] = x[1];
|
|
11
18
|
});
|
|
12
19
|
|
|
20
|
+
// @ts-expect-error - TS inference not good enough to infer the correct type
|
|
13
21
|
return dict;
|
|
14
22
|
};
|
|
15
23
|
|
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @template T
|
|
5
|
+
* @typedef {Array<{ [Key in keyof T]: [Key, T[Key]] }[keyof T]>} DictItems
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
/**
|
|
2
9
|
* Return an array of (key,value) pairs that are present in this
|
|
3
10
|
* dictionary
|
|
11
|
+
*
|
|
12
|
+
* TODO(Trevor): Replace with `Object.entries`?
|
|
13
|
+
*
|
|
14
|
+
* @template {object} T
|
|
15
|
+
* @param {T} dictionary
|
|
16
|
+
*
|
|
17
|
+
* @returns {DictItems<T>}
|
|
4
18
|
*/
|
|
5
19
|
const dictItems = (dictionary) => {
|
|
20
|
+
/** @type {DictItems<T>} */
|
|
6
21
|
const keyValues = [];
|
|
7
22
|
|
|
8
23
|
for (const key in dictionary) {
|