higlass 1.13.4 → 1.13.5
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/app/scripts/AxisPixi.js +4 -2
- package/app/scripts/ChromosomeInfo.js +4 -2
- package/app/scripts/HeatmapOptions.jsx +4 -1
- package/app/scripts/HeatmapTiledPixiTrack.js +57 -29
- package/app/scripts/MapboxTilesTrack.js +3 -2
- package/app/scripts/PixiTrack.js +33 -6
- package/app/scripts/RasterTilesTrack.js +3 -2
- package/app/scripts/SeriesListMenu.jsx +75 -0
- package/app/scripts/SeriesListSubmenuMixin.jsx +4 -0
- package/app/scripts/TiledPixiTrack.js +32 -20
- package/app/scripts/TiledPlot.jsx +2 -0
- package/app/scripts/Track.js +2 -2
- package/app/scripts/UnknownPixiTrack.js +1 -1
- package/app/scripts/data-fetchers/DataFetcher.js +88 -71
- package/app/scripts/gosling-exports.js +29 -0
- package/app/scripts/hglib.jsx +2 -0
- package/app/scripts/hocs/with-pub-sub.js +19 -0
- package/app/scripts/services/tile-proxy.js +3 -2
- package/app/scripts/services/worker.js +6 -6
- package/app/scripts/types.ts +29 -0
- package/app/scripts/utils/DenseDataExtrema1D.js +1 -1
- package/app/scripts/utils/DenseDataExtrema2D.js +2 -1
- package/app/scripts/utils/color-to-hex.js +1 -1
- package/app/scripts/utils/fake-pub-sub.js +12 -0
- package/app/scripts/utils/show-mouse-position.js +1 -1
- package/dist/hglib.js +23341 -23368
- package/dist/hglib.min.js +73 -72
- package/dist/higlass.mjs +23081 -23108
- package/package.json +2 -1
- package/app/scripts/hocs/with-pub-sub.jsx +0 -28
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import slugid from 'slugid';
|
|
2
2
|
import { scaleLinear } from 'd3-scale';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
|
|
4
|
+
// Utils
|
|
5
|
+
import tts from '../utils/trim-trailing-slash';
|
|
6
|
+
import dictValues from '../utils/dict-values';
|
|
7
|
+
import minNonZero from '../utils/min-non-zero';
|
|
8
|
+
import maxNonZero from '../utils/max-non-zero';
|
|
9
|
+
import DenseDataExtrema1D from '../utils/DenseDataExtrema1D';
|
|
10
|
+
import DenseDataExtrema2D from '../utils/DenseDataExtrema2D';
|
|
11
11
|
|
|
12
12
|
// Services
|
|
13
|
-
import
|
|
13
|
+
import * as tileProxy from '../services/tile-proxy';
|
|
14
14
|
|
|
15
15
|
/** @typedef {import('../types').DataConfig} DataConfig */
|
|
16
16
|
/** @typedef {import('../types').TilesetInfo} TilesetInfo */
|
|
@@ -18,6 +18,10 @@ import { tileProxy } from '../services';
|
|
|
18
18
|
* @template T
|
|
19
19
|
* @typedef {import('../types').AbstractDataFetcher<T>} AbstractDataFetcher
|
|
20
20
|
*/
|
|
21
|
+
/**
|
|
22
|
+
* @template T
|
|
23
|
+
* @typedef {import('../types').TileSource<T>} TileSource
|
|
24
|
+
*/
|
|
21
25
|
|
|
22
26
|
/**
|
|
23
27
|
* @typedef Tile
|
|
@@ -49,13 +53,50 @@ function isTuple(x) {
|
|
|
49
53
|
return x.length === 2;
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
/**
|
|
57
|
+
* @param {import("pub-sub-es").PubSub} pubSub
|
|
58
|
+
* @returns {TileSource<Tile>}
|
|
59
|
+
*/
|
|
60
|
+
function createDefaultTileSource(pubSub) {
|
|
61
|
+
return {
|
|
62
|
+
fetchTiles(request) {
|
|
63
|
+
const ids = request.tileIds;
|
|
64
|
+
return new Promise((done, _reject) => {
|
|
65
|
+
tileProxy.fetchTilesDebounced({ ...request, ids, done }, pubSub, true);
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
fetchTilesetInfo({ server, tilesetUid }) {
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
tileProxy.trackInfo(server, tilesetUid, resolve, reject, pubSub);
|
|
71
|
+
});
|
|
72
|
+
},
|
|
73
|
+
registerTileset({ server, url, filetype, coordSystem }) {
|
|
74
|
+
const serverUrl = `${tts(server)}/register_url/`;
|
|
75
|
+
const payload = {
|
|
76
|
+
fileurl: url,
|
|
77
|
+
filetype,
|
|
78
|
+
coordSystem,
|
|
79
|
+
};
|
|
80
|
+
return fetch(serverUrl, {
|
|
81
|
+
method: 'POST',
|
|
82
|
+
body: JSON.stringify(payload),
|
|
83
|
+
headers: {
|
|
84
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
52
91
|
/** @implements {AbstractDataFetcher<Tile | DividedTile>} */
|
|
53
92
|
export default class DataFetcher {
|
|
54
93
|
/**
|
|
55
94
|
* @param {import('../types').DataConfig} dataConfig
|
|
56
95
|
* @param {import('pub-sub-es').PubSub} pubSub
|
|
96
|
+
* @param {TileSource<Tile>} [tileSource]
|
|
57
97
|
*/
|
|
58
|
-
constructor(dataConfig, pubSub) {
|
|
98
|
+
constructor(dataConfig, pubSub, tileSource) {
|
|
99
|
+
this._tileSource = tileSource || createDefaultTileSource(pubSub);
|
|
59
100
|
/** @type {boolean} */
|
|
60
101
|
this.tilesetInfoLoading = true;
|
|
61
102
|
|
|
@@ -95,20 +136,11 @@ export default class DataFetcher {
|
|
|
95
136
|
* @param {string=} opts.coordSystem - The coordinate system being served (e.g. 'hg38')
|
|
96
137
|
*/
|
|
97
138
|
async registerFileUrl({ server, url, filetype, coordSystem }) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
fileurl: url,
|
|
139
|
+
return this._tileSource.registerTileset({
|
|
140
|
+
server,
|
|
141
|
+
url,
|
|
102
142
|
filetype,
|
|
103
143
|
coordSystem,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
return fetch(serverUrl, {
|
|
107
|
-
method: 'POST',
|
|
108
|
-
body: JSON.stringify(payload),
|
|
109
|
-
headers: {
|
|
110
|
-
'Content-Type': 'application/json; charset=utf-8',
|
|
111
|
-
},
|
|
112
144
|
});
|
|
113
145
|
}
|
|
114
146
|
|
|
@@ -160,22 +192,18 @@ export default class DataFetcher {
|
|
|
160
192
|
);
|
|
161
193
|
finished(null);
|
|
162
194
|
} else {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
tilesetUid,
|
|
167
|
-
(/** @type {Record<string, TilesetInfo>} */ tilesetInfo) => {
|
|
195
|
+
this._tileSource
|
|
196
|
+
.fetchTilesetInfo({ server, tilesetUid })
|
|
197
|
+
.then((tilesetInfo) => {
|
|
168
198
|
// tileset infos are indxed by by tilesetUids, we can just resolve
|
|
169
199
|
// that here before passing it back to the track
|
|
170
200
|
this.dataConfig.tilesetInfo = tilesetInfo[tilesetUid];
|
|
171
201
|
finished(tilesetInfo[tilesetUid], tilesetUid);
|
|
172
|
-
}
|
|
173
|
-
(
|
|
202
|
+
})
|
|
203
|
+
.catch((error) => {
|
|
174
204
|
this.tilesetInfoLoading = false;
|
|
175
205
|
finished({ error });
|
|
176
|
-
}
|
|
177
|
-
this.pubSub,
|
|
178
|
-
);
|
|
206
|
+
});
|
|
179
207
|
}
|
|
180
208
|
} else {
|
|
181
209
|
// this data source has children, so we need to wait to get
|
|
@@ -231,35 +259,28 @@ export default class DataFetcher {
|
|
|
231
259
|
|
|
232
260
|
if (!this.dataConfig.children && this.dataConfig.tilesetUid) {
|
|
233
261
|
// no children, just return the fetched tiles as is
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
server: this.dataConfig.server,
|
|
240
|
-
done: resolve,
|
|
241
|
-
ids: tileIds.map((x) => `${this.dataConfig.tilesetUid}.${x}`),
|
|
242
|
-
options: this.dataConfig.options,
|
|
243
|
-
},
|
|
244
|
-
this.pubSub,
|
|
245
|
-
true,
|
|
246
|
-
);
|
|
262
|
+
const promise = this._tileSource.fetchTiles({
|
|
263
|
+
id: slugid.nice(),
|
|
264
|
+
server: this.dataConfig.server,
|
|
265
|
+
tileIds: tileIds.map((x) => `${this.dataConfig.tilesetUid}.${x}`),
|
|
266
|
+
options: this.dataConfig.options,
|
|
247
267
|
});
|
|
268
|
+
return /** @type {Promise<Record<string, Tile>>} */ (promise).then(
|
|
269
|
+
(returnedTiles) => {
|
|
270
|
+
const tilesetUid = dictValues(returnedTiles)[0].tilesetUid;
|
|
271
|
+
/** @type {Record<string, Tile>} */
|
|
272
|
+
const newTiles = {};
|
|
248
273
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
/** @type {Record<string, Tile>} */
|
|
252
|
-
const newTiles = {};
|
|
253
|
-
|
|
254
|
-
for (let i = 0; i < tileIds.length; i++) {
|
|
255
|
-
const fullTileId = this.fullTileId(tilesetUid, tileIds[i]);
|
|
274
|
+
for (let i = 0; i < tileIds.length; i++) {
|
|
275
|
+
const fullTileId = this.fullTileId(tilesetUid, tileIds[i]);
|
|
256
276
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
277
|
+
returnedTiles[fullTileId].tilePositionId = tileIds[i];
|
|
278
|
+
newTiles[tileIds[i]] = returnedTiles[fullTileId];
|
|
279
|
+
}
|
|
280
|
+
receivedTiles(newTiles);
|
|
281
|
+
return newTiles;
|
|
282
|
+
},
|
|
283
|
+
);
|
|
263
284
|
}
|
|
264
285
|
|
|
265
286
|
// multiple child tracks, need to wait for all of them to
|
|
@@ -325,12 +346,12 @@ export default class DataFetcher {
|
|
|
325
346
|
/**
|
|
326
347
|
* Extract a slice from a matrix at a given position.
|
|
327
348
|
*
|
|
328
|
-
* @param {Array<number>} inputData - An array containing a matrix stored row-wise
|
|
349
|
+
* @param {Array<number> | Float32Array} inputData - An array containing a matrix stored row-wise
|
|
329
350
|
* @param {Array<number>} arrayShape - The shape of the array, should be a
|
|
330
351
|
* two element array e.g. [256,256].
|
|
331
352
|
* @param {number} sliceIndex - The index across which to take the slice
|
|
332
353
|
* @param {number=} axis - The axis along which to take the slice
|
|
333
|
-
* @returns {Array<number>} an array corresponding to a slice of this matrix
|
|
354
|
+
* @returns {Array<number> | Float32Array} an array corresponding to a slice of this matrix
|
|
334
355
|
*/
|
|
335
356
|
extractDataSlice(inputData, arrayShape, sliceIndex, axis) {
|
|
336
357
|
if (!axis) {
|
|
@@ -419,18 +440,12 @@ export default class DataFetcher {
|
|
|
419
440
|
}
|
|
420
441
|
|
|
421
442
|
// actually fetch the new tileIds
|
|
422
|
-
const promise =
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
server: this.dataConfig.server,
|
|
427
|
-
done: resolve,
|
|
428
|
-
ids: newTileIds.map((x) => `${this.dataConfig.tilesetUid}.${x}`),
|
|
429
|
-
},
|
|
430
|
-
this.pubSub,
|
|
431
|
-
true,
|
|
432
|
-
);
|
|
443
|
+
const promise = this._tileSource.fetchTiles({
|
|
444
|
+
id: slugid.nice(),
|
|
445
|
+
server: this.dataConfig.server,
|
|
446
|
+
tileIds: newTileIds.map((x) => `${this.dataConfig.tilesetUid}.${x}`),
|
|
433
447
|
});
|
|
448
|
+
|
|
434
449
|
return promise.then((returnedTiles) => {
|
|
435
450
|
// we've received some new tiles, but they're 2D
|
|
436
451
|
// we need to extract the row corresponding to the data we need
|
|
@@ -489,7 +504,9 @@ export default class DataFetcher {
|
|
|
489
504
|
}
|
|
490
505
|
|
|
491
506
|
const newTile = {
|
|
507
|
+
// @ts-expect-error - this is ok because float32 array can be spread as number[]
|
|
492
508
|
min_value: Math.min.apply(null, dataSlice),
|
|
509
|
+
// @ts-expect-error - this is ok because float32 array can be spread as number[]
|
|
493
510
|
max_value: Math.max.apply(null, dataSlice),
|
|
494
511
|
denseDataExtrema: new DenseDataExtrema1D(dataSlice),
|
|
495
512
|
minNonZero: minNonZero(dataSlice),
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// These are all exports that are used is Gosling.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tracks
|
|
5
|
+
*/
|
|
6
|
+
export { default as Track } from './Track';
|
|
7
|
+
export { default as PixiTrack } from './PixiTrack';
|
|
8
|
+
export { default as TiledPixiTrack } from './TiledPixiTrack';
|
|
9
|
+
export { default as SVGTrack } from './SVGTrack';
|
|
10
|
+
export { default as ViewportTrackerHorizontal } from './ViewportTrackerHorizontal';
|
|
11
|
+
export { default as HeatmapTiledPixiTrack } from './HeatmapTiledPixiTrack';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Data Fetcher
|
|
15
|
+
*/
|
|
16
|
+
export { default as DataFetcher } from './data-fetchers/DataFetcher';
|
|
17
|
+
/**
|
|
18
|
+
* Utils
|
|
19
|
+
*/
|
|
20
|
+
export { default as tileProxy } from './services/tile-proxy';
|
|
21
|
+
export { default as fakePubSub } from './utils/fake-pub-sub';
|
|
22
|
+
export { default as DenseDataExtrema1D } from './utils/DenseDataExtrema1D';
|
|
23
|
+
export { default as absToChr } from './utils/abs-to-chr';
|
|
24
|
+
export { default as chrToAbs } from './utils/chr-to-abs';
|
|
25
|
+
export { default as colorToHex } from './utils/color-to-hex';
|
|
26
|
+
export { default as chromInfoBisector } from './utils/chrom-info-bisector';
|
|
27
|
+
export { default as pixiTextToSvg } from './utils/pixi-text-to-svg';
|
|
28
|
+
export { default as svgLine } from './utils/svg-line';
|
|
29
|
+
export { default as showMousePosition } from './utils/show-mouse-position';
|
package/app/scripts/hglib.jsx
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import fakePubSub from '../utils/fake-pub-sub';
|
|
5
|
+
|
|
6
|
+
const { Provider, Consumer } = React.createContext(fakePubSub);
|
|
7
|
+
|
|
8
|
+
// Written without JSX to make it so we don't need JSX-transformation to load this file
|
|
9
|
+
function withPubSub(Component) {
|
|
10
|
+
return React.forwardRef((props, ref) =>
|
|
11
|
+
React.createElement(Consumer, null, (pubSub) =>
|
|
12
|
+
React.createElement(Component, { ref, ...props, pubSub }),
|
|
13
|
+
),
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default withPubSub;
|
|
18
|
+
|
|
19
|
+
export { Provider };
|
|
@@ -4,10 +4,11 @@ import slugid from 'slugid';
|
|
|
4
4
|
|
|
5
5
|
import { workerGetTiles, workerSetPix } from './worker';
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import tts from '../utils/trim-trailing-slash';
|
|
8
|
+
import sleep from '../utils/timeout';
|
|
8
9
|
|
|
9
10
|
// Config
|
|
10
|
-
import { TILE_FETCH_DEBOUNCE } from '../configs';
|
|
11
|
+
import { TILE_FETCH_DEBOUNCE } from '../configs/primitives';
|
|
11
12
|
|
|
12
13
|
const MAX_FETCH_TILES = 15;
|
|
13
14
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { scaleLog, scaleLinear } from 'd3-scale';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
|
|
3
|
+
// utils
|
|
4
|
+
import DenseDataExtrema1D from '../utils/DenseDataExtrema1D';
|
|
5
|
+
import DenseDataExtrema2D from '../utils/DenseDataExtrema2D';
|
|
6
|
+
import getAggregationFunction from '../utils/get-aggregation-function';
|
|
7
|
+
import selectedItemsToSize from '../utils/selected-items-to-size';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* This function helps to fill in pixData by calling setPixData()
|
package/app/scripts/types.ts
CHANGED
|
@@ -140,3 +140,32 @@ export interface AbstractDataFetcher<TileType> {
|
|
|
140
140
|
tileIds: string[],
|
|
141
141
|
): Promise<Record<string, TileType>>;
|
|
142
142
|
}
|
|
143
|
+
|
|
144
|
+
// Tileset API
|
|
145
|
+
|
|
146
|
+
type TilesRequest = {
|
|
147
|
+
id: string;
|
|
148
|
+
server?: string;
|
|
149
|
+
tileIds: string[];
|
|
150
|
+
options?: unknown;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
type TilesetInfoRequest = {
|
|
154
|
+
server: string;
|
|
155
|
+
tilesetUid: string;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
type RegisterTilesetRequest = {
|
|
159
|
+
server: string;
|
|
160
|
+
url: string;
|
|
161
|
+
filetype: string;
|
|
162
|
+
coordSystem?: string;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
export type TileSource<T> = {
|
|
166
|
+
fetchTiles: (request: TilesRequest) => Promise<Record<string, T>>;
|
|
167
|
+
fetchTilesetInfo: (
|
|
168
|
+
request: TilesetInfoRequest,
|
|
169
|
+
) => Promise<Record<string, TilesetInfo>>;
|
|
170
|
+
registerTileset: (request: RegisterTilesetRequest) => Promise<Response>;
|
|
171
|
+
};
|