@genome-spy/core 0.43.3 → 0.45.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.es.js +5231 -4324
- package/dist/bundle/index.js +197 -85
- package/dist/schema.json +723 -104
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +4 -2
- package/dist/src/data/flowOptimizer.test.js +12 -3
- package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
- package/dist/src/data/sources/dataUtils.js +3 -1
- package/dist/src/data/sources/lazy/axisTickSource.d.ts +1 -1
- package/dist/src/data/sources/lazy/axisTickSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/axisTickSource.js +2 -2
- package/dist/src/data/sources/lazy/bigBedSource.d.ts +1 -1
- package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigBedSource.js +52 -20
- package/dist/src/data/sources/lazy/bigWigSource.d.ts +6 -1
- package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigWigSource.js +33 -9
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.js +1 -3
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts +13 -14
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +70 -48
- package/dist/src/data/sources/sequenceSource.d.ts.map +1 -1
- package/dist/src/data/sources/sequenceSource.js +14 -5
- package/dist/src/data/sources/sequenceSource.test.js +23 -5
- package/dist/src/data/sources/urlSource.d.ts.map +1 -1
- package/dist/src/data/sources/urlSource.js +15 -2
- package/dist/src/data/transforms/aggregate.d.ts.map +1 -1
- package/dist/src/data/transforms/aggregate.js +5 -2
- package/dist/src/data/transforms/filterScoredLabels.js +1 -1
- package/dist/src/encoder/encoder.d.ts +2 -4
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +20 -10
- package/dist/src/encoder/encoder.test.js +3 -0
- package/dist/src/genomeSpy.d.ts +8 -5
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +121 -42
- package/dist/src/gl/glslScaleGenerator.d.ts +23 -3
- package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
- package/dist/src/gl/glslScaleGenerator.js +137 -42
- package/dist/src/gl/webGLHelper.d.ts.map +1 -1
- package/dist/src/gl/webGLHelper.js +5 -7
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/marks/link.common.glsl.js +2 -0
- package/dist/src/marks/link.d.ts.map +1 -1
- package/dist/src/marks/link.js +19 -9
- package/dist/src/marks/link.vertex.glsl.js +1 -1
- package/dist/src/marks/mark.d.ts +25 -20
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +234 -129
- package/dist/src/marks/point.common.glsl.js +1 -1
- package/dist/src/marks/point.d.ts +1 -4
- package/dist/src/marks/point.d.ts.map +1 -1
- package/dist/src/marks/point.js +31 -23
- package/dist/src/marks/point.vertex.glsl.js +1 -1
- package/dist/src/marks/rect.common.glsl.js +2 -0
- package/dist/src/marks/rect.d.ts.map +1 -1
- package/dist/src/marks/rect.js +12 -12
- package/dist/src/marks/rect.vertex.glsl.js +1 -1
- package/dist/src/marks/rule.common.glsl.js +1 -1
- package/dist/src/marks/rule.js +2 -2
- package/dist/src/marks/text.common.glsl.js +1 -1
- package/dist/src/marks/text.d.ts.map +1 -1
- package/dist/src/marks/text.js +17 -9
- package/dist/src/spec/channel.d.ts +4 -3
- package/dist/src/spec/data.d.ts +11 -10
- package/dist/src/spec/mark.d.ts +28 -46
- package/dist/src/spec/parameter.d.ts +127 -0
- package/dist/src/spec/root.d.ts +1 -0
- package/dist/src/spec/scale.d.ts +2 -1
- package/dist/src/spec/title.d.ts +5 -4
- package/dist/src/spec/view.d.ts +20 -5
- 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 +52 -5
- package/dist/src/styles/genome-spy.scss +63 -10
- package/dist/src/styles/update.sh +6 -0
- package/dist/src/tooltip/dataTooltipHandler.js +1 -1
- package/dist/src/tooltip/refseqGeneTooltipHandler.js +1 -1
- package/dist/src/tooltip/tooltipHandler.d.ts +1 -1
- package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -1
- package/dist/src/tooltip/tooltipHandler.ts +1 -1
- package/dist/src/types/embedApi.d.ts +6 -0
- package/dist/src/types/scaleResolutionApi.d.ts +7 -3
- package/dist/src/types/viewContext.d.ts +2 -3
- package/dist/src/utils/debounce.d.ts +2 -2
- package/dist/src/utils/debounce.d.ts.map +1 -1
- package/dist/src/utils/debounce.js +5 -2
- package/dist/src/utils/expression.d.ts +2 -2
- package/dist/src/utils/expression.d.ts.map +1 -1
- package/dist/src/utils/expression.js +3 -3
- package/dist/src/utils/formatObject.d.ts +2 -2
- package/dist/src/utils/formatObject.d.ts.map +1 -1
- package/dist/src/utils/formatObject.js +2 -2
- package/dist/src/utils/inputBinding.d.ts +5 -0
- package/dist/src/utils/inputBinding.d.ts.map +1 -0
- package/dist/src/utils/inputBinding.js +115 -0
- package/dist/src/utils/ui/tooltip.js +1 -1
- package/dist/src/view/axisView.js +3 -3
- package/dist/src/view/paramMediator.d.ts +108 -0
- package/dist/src/view/paramMediator.d.ts.map +1 -0
- package/dist/src/view/paramMediator.js +337 -0
- package/dist/src/view/paramMediator.test.js +211 -0
- package/dist/src/view/scaleResolution.d.ts +8 -18
- package/dist/src/view/scaleResolution.d.ts.map +1 -1
- package/dist/src/view/scaleResolution.js +225 -126
- package/dist/src/view/scaleResolution.test.js +7 -7
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +10 -3
- package/dist/src/view/view.d.ts +4 -1
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.js +21 -7
- package/dist/src/view/viewFactory.d.ts.map +1 -1
- package/dist/src/view/viewFactory.js +45 -0
- package/dist/src/view/viewUtils.d.ts +5 -1
- package/dist/src/view/viewUtils.d.ts.map +1 -1
- package/dist/src/view/viewUtils.js +9 -4
- package/package.json +16 -17
- package/dist/src/paramBroker.d.ts +0 -30
- package/dist/src/paramBroker.d.ts.map +0 -1
- package/dist/src/paramBroker.js +0 -102
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
activateExprRefProps,
|
|
3
|
+
withoutExprRef,
|
|
4
|
+
} from "../../view/paramMediator.js";
|
|
1
5
|
import DataSource from "./dataSource.js";
|
|
2
6
|
|
|
3
7
|
/**
|
|
@@ -16,7 +20,11 @@ export default class SequenceSource extends DataSource {
|
|
|
16
20
|
*/
|
|
17
21
|
constructor(params, view) {
|
|
18
22
|
super();
|
|
19
|
-
this.sequence =
|
|
23
|
+
this.sequence = activateExprRefProps(
|
|
24
|
+
view.paramMediator,
|
|
25
|
+
params.sequence,
|
|
26
|
+
() => this.loadSynchronously()
|
|
27
|
+
);
|
|
20
28
|
|
|
21
29
|
if (!("start" in this.sequence)) {
|
|
22
30
|
throw new Error("'start' is missing from sequence parameters!");
|
|
@@ -27,14 +35,15 @@ export default class SequenceSource extends DataSource {
|
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
loadSynchronously() {
|
|
30
|
-
const as = this.sequence.as
|
|
31
|
-
const
|
|
32
|
-
const
|
|
38
|
+
const as = withoutExprRef(this.sequence.as) ?? "data";
|
|
39
|
+
const start = withoutExprRef(this.sequence.start) ?? 0;
|
|
40
|
+
const step = withoutExprRef(this.sequence.step) ?? 1;
|
|
41
|
+
const stop = withoutExprRef(this.sequence.stop);
|
|
33
42
|
|
|
34
43
|
this.reset();
|
|
35
44
|
this.beginBatch({ type: "file" });
|
|
36
45
|
|
|
37
|
-
for (let x =
|
|
46
|
+
for (let x = start; x < stop; x += step) {
|
|
38
47
|
this._propagate({ [as]: x });
|
|
39
48
|
}
|
|
40
49
|
|
|
@@ -14,10 +14,18 @@ async function collectSource(source) {
|
|
|
14
14
|
return [...collector.getData()];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
const viewStub = {
|
|
18
|
+
paramMediator: {
|
|
19
|
+
registerParam: () => {},
|
|
20
|
+
allocateSetter: () => {},
|
|
21
|
+
createExpression: () => {},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
17
25
|
test("SequenceSource generates a sequence", async () => {
|
|
18
26
|
expect(
|
|
19
27
|
await collectSource(
|
|
20
|
-
new SequenceSource({ sequence: { start: 0, stop: 3 } })
|
|
28
|
+
new SequenceSource({ sequence: { start: 0, stop: 3 } }, viewStub)
|
|
21
29
|
)
|
|
22
30
|
).toEqual([{ data: 0 }, { data: 1 }, { data: 2 }]);
|
|
23
31
|
});
|
|
@@ -25,7 +33,10 @@ test("SequenceSource generates a sequence", async () => {
|
|
|
25
33
|
test("SequenceSource generates a sequence with a custom step", async () => {
|
|
26
34
|
expect(
|
|
27
35
|
await collectSource(
|
|
28
|
-
new SequenceSource(
|
|
36
|
+
new SequenceSource(
|
|
37
|
+
{ sequence: { start: 0, stop: 5, step: 2 } },
|
|
38
|
+
viewStub
|
|
39
|
+
)
|
|
29
40
|
)
|
|
30
41
|
).toEqual([{ data: 0 }, { data: 2 }, { data: 4 }]);
|
|
31
42
|
});
|
|
@@ -33,14 +44,21 @@ test("SequenceSource generates a sequence with a custom step", async () => {
|
|
|
33
44
|
test("SequenceSource generates a sequence with a custom field name", async () => {
|
|
34
45
|
expect(
|
|
35
46
|
await collectSource(
|
|
36
|
-
new SequenceSource(
|
|
47
|
+
new SequenceSource(
|
|
48
|
+
{ sequence: { start: 0, stop: 3, as: "x" } },
|
|
49
|
+
viewStub
|
|
50
|
+
)
|
|
37
51
|
)
|
|
38
52
|
).toEqual([{ x: 0 }, { x: 1 }, { x: 2 }]);
|
|
39
53
|
});
|
|
40
54
|
|
|
41
55
|
test("SequenceSource throws on missing 'start' parameter", () => {
|
|
42
|
-
expect(
|
|
56
|
+
expect(
|
|
57
|
+
() => new SequenceSource({ sequence: { stop: 3 } }, viewStub)
|
|
58
|
+
).toThrow();
|
|
43
59
|
});
|
|
44
60
|
test("SequenceSource throws on missing 'stop' parameter", () => {
|
|
45
|
-
expect(
|
|
61
|
+
expect(
|
|
62
|
+
() => new SequenceSource({ sequence: { start: 0 } }, viewStub)
|
|
63
|
+
).toThrow();
|
|
46
64
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urlSource.d.ts","sourceRoot":"","sources":["../../../../src/data/sources/urlSource.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"urlSource.d.ts","sourceRoot":"","sources":["../../../../src/data/sources/urlSource.js"],"names":[],"mappings":"AAQA;;;GAGG;AACH,gCAHW,QAAQ,OAAO,oBAAoB,EAAE,IAAI,CAAC,gDAKpD;AAED;IACI;;;OAGG;IACH,oBAHW,OAAO,oBAAoB,EAAE,OAAO,QACpC,OAAO,oBAAoB,EAAE,OAAO,EAU9C;IALG,6CAEC;IAED,gBAAiC;CA0DxC;uBApFsB,iBAAiB"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { loader as vegaLoader, read } from "vega-loader";
|
|
2
2
|
import { getFormat } from "./dataUtils.js";
|
|
3
3
|
import DataSource from "./dataSource.js";
|
|
4
|
+
import {
|
|
5
|
+
activateExprRefProps,
|
|
6
|
+
withoutExprRef,
|
|
7
|
+
} from "../../view/paramMediator.js";
|
|
4
8
|
|
|
5
9
|
/**
|
|
6
10
|
* @param {Partial<import("../../spec/data.js").Data>} data
|
|
@@ -18,7 +22,10 @@ export default class UrlSource extends DataSource {
|
|
|
18
22
|
constructor(params, view) {
|
|
19
23
|
super();
|
|
20
24
|
|
|
21
|
-
this.params = params
|
|
25
|
+
this.params = activateExprRefProps(view.paramMediator, params, () =>
|
|
26
|
+
this.load()
|
|
27
|
+
);
|
|
28
|
+
|
|
22
29
|
this.baseUrl = view?.getBaseUrl();
|
|
23
30
|
}
|
|
24
31
|
|
|
@@ -27,11 +34,17 @@ export default class UrlSource extends DataSource {
|
|
|
27
34
|
}
|
|
28
35
|
|
|
29
36
|
async load() {
|
|
30
|
-
const url = this.params.url;
|
|
37
|
+
const url = withoutExprRef(this.params.url);
|
|
31
38
|
|
|
32
39
|
/** @type {string[]} */
|
|
33
40
|
const urls = Array.isArray(url) ? url : [url];
|
|
34
41
|
|
|
42
|
+
if (urls.length === 0 || !urls[0]) {
|
|
43
|
+
this.reset();
|
|
44
|
+
this.complete();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
/** @param {string} url */
|
|
36
49
|
const load = async (url) =>
|
|
37
50
|
// TODO: Support chunked loading
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/aggregate.js"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH;IAKI;;OAEG;IACH,oBAFW,OAAO,yBAAyB,EAAE,eAAe,EAQ3D;IAJG,0DAAoB;IAEpB,oBAAoB;IACpB,QADW,GAAG,EAAE,CACA;
|
|
1
|
+
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../../../../src/data/transforms/aggregate.js"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH;IAKI;;OAEG;IACH,oBAFW,OAAO,yBAAyB,EAAE,eAAe,EAQ3D;IAJG,0DAAoB;IAEpB,oBAAoB;IACpB,QADW,GAAG,EAAE,CACA;CA4CvB;qBApEyC,gBAAgB"}
|
|
@@ -46,8 +46,11 @@ export default class AggregateTransform extends FlowNode {
|
|
|
46
46
|
const groupFieldAccessors = groupby.map((f) => field(f));
|
|
47
47
|
|
|
48
48
|
// TODO: Fix case where no group fields are specified
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
|
|
50
|
+
// There's something strange in d3-array's typings
|
|
51
|
+
const groups = /** @type {Map<any, any>} */ /** @type {any} */ (
|
|
52
|
+
d3group(this.buffer, ...groupFieldAccessors)
|
|
53
|
+
);
|
|
51
54
|
|
|
52
55
|
for (const [group, data] of iterateNestedMaps(groups)) {
|
|
53
56
|
/** @type {any} */
|
|
@@ -75,7 +75,7 @@ export default class FilterScoredLabelsTransform extends FlowNode {
|
|
|
75
75
|
_filterAndPropagate() {
|
|
76
76
|
super.reset();
|
|
77
77
|
|
|
78
|
-
const scale = this.resolution.
|
|
78
|
+
const scale = this.resolution.scale;
|
|
79
79
|
const rangeSpan =
|
|
80
80
|
this.resolution.members[0].view.coords?.[
|
|
81
81
|
this.channel == "x" ? "width" : "height"
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Creates an object that contains encoders for every channel of a mark
|
|
3
3
|
*
|
|
4
|
-
* TODO: This should actually receive the mark as parameter
|
|
5
|
-
*
|
|
6
4
|
* TODO: This method should have a test. But how to mock Mark...
|
|
7
5
|
*
|
|
8
6
|
* @param {import("../marks/mark.js").default} mark
|
|
@@ -11,14 +9,14 @@
|
|
|
11
9
|
*/
|
|
12
10
|
export default function createEncoders(mark: import("../marks/mark.js").default, encoding?: import("../spec/channel.js").Encoding): Partial<Record<import("../spec/channel.js").Channel, import("../types/encoder.js").Encoder>>;
|
|
13
11
|
/**
|
|
14
|
-
*
|
|
12
|
+
* @param {import("../marks/mark.js").default} mark
|
|
15
13
|
* @param {import("../spec/channel.js").ChannelDef} channelDef
|
|
16
14
|
* @param {any} scale
|
|
17
15
|
* @param {Accessor} accessor
|
|
18
16
|
* @param {Channel} channel
|
|
19
17
|
* @returns {Encoder}
|
|
20
18
|
*/
|
|
21
|
-
export function createEncoder(channelDef: import("../spec/channel.js").ChannelDef, scale: any, accessor: import("../types/encoder.js").Accessor, channel: import("../spec/channel.js").Channel): import("../types/encoder.js").Encoder;
|
|
19
|
+
export function createEncoder(mark: import("../marks/mark.js").default, channelDef: import("../spec/channel.js").ChannelDef, scale: any, accessor: import("../types/encoder.js").Accessor, channel: import("../spec/channel.js").Channel): import("../types/encoder.js").Encoder;
|
|
22
20
|
/**
|
|
23
21
|
* TODO: Move to a more generic place
|
|
24
22
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/encoder/encoder.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"encoder.d.ts","sourceRoot":"","sources":["../../../src/encoder/encoder.js"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH,6CAJW,OAAO,kBAAkB,EAAE,OAAO,aAClC,OAAO,oBAAoB,EAAE,QAAQ,gGAuC/C;AAED;;;;;;;GAOG;AACH,oCAPW,OAAO,kBAAkB,EAAE,OAAO,cAClC,OAAO,oBAAoB,EAAE,UAAU,SACvC,GAAG,0IAqGb;AAED;;;;;GAKG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,4FAKjD;AAED;;;GAGG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,mEAKjD;AAED;;;GAGG;AACH,uCAHW,OAAO,oBAAoB,EAAE,UAAU,uDAKjD;AAED;;;GAGG;AACH,kDAHW,OAAO,oBAAoB,EAAE,UAAU,kEAWjD;AAED;;;GAGG;AACH,6CAHW,OAAO,qBAAqB,EAAE,OAAO,WACrC,OAAO,oBAAoB,EAAE,OAAO,27CAS9C;AAED;;;GAGG;AACH,iDAHW,OAAO,oBAAoB,EAAE,UAAU,4FAKjD;AAED;;;GAGG;AACH,0CAHW,OAAO,oBAAoB,EAAE,UAAU,0DAKjD;AAED;;;GAGG;AACH,sCAHW,OAAO,oBAAoB,EAAE,UAAU,sDAKjD;AAoBD;;;GAGG;AACH,oDAHW,OAAO,oBAAoB,EAAE,OAAO,oEAM9C;AAED;;;GAGG;AACH,6CAHW,OAAO,oBAAoB,EAAE,OAAO,6DAM9C;AAqBD;;;GAGG;AACH,4CAFW,MAAM,WAIhB;AAED;;;;GAIG;AACH,oDAFW,OAAO,oBAAoB,EAAE,OAAO,2DAS9C;AAED;;;;;GAKG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,wCAI9C;AAED;;;;GAIG;AACH,kDAFW,OAAO,oBAAoB,EAAE,OAAO,0CAM9C;AAED;;GAEG;AACH,wCAFW,OAAO,oBAAoB,EAAE,OAAO,WAI9C;AAED;;;;GAIG;AACH,2CAFW,OAAO,oBAAoB,EAAE,OAAO,WAI9C;AAED;;;GAGG;AACH,4CAHW,OAAO,oBAAoB,EAAE,OAAO,4DAuB9C;AAED;;;;;GAKG;AACH,0CAHW,OAAO,oBAAoB,EAAE,OAAO,GAClC,GAAG,EAAE,CAsBjB;AAED;;;GAGG;AACH,gDAHW,OAAO,oBAAoB,EAAE,OAAO,UACzB,GAAG,KAAE,MAAM,CAmBhC;AA7LD;;GAEG;AACH,wCAFU,OAAO,oBAAoB,EAAE,wBAAwB,EAAE,CAEb;AAEpD;;GAEG;AACH,0CAFU,OAAO,oBAAoB,EAAE,0BAA0B,EAAE,CAEX;AAExD;;GAEG;AACH,iCAFU,OAAO,oBAAoB,EAAE,iBAAiB,EAAE,CAKxD;AAoBF;;;;GAIG;AACH,gCAFU,QAAQ,OAAO,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,oBAAoB,EAAE,0BAA0B,CAAC,CAAC,CAKtH;AAEF;;;;GAIG;AACH,8BAFU,QAAQ,OAAO,OAAO,oBAAoB,EAAE,OAAO,EAAE,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAAC,CAInG"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { isDiscrete } from "vega-scale";
|
|
2
2
|
import createIndexer from "../utils/indexer.js";
|
|
3
3
|
import scaleNull from "../utils/scaleNull.js";
|
|
4
|
+
import { isExprRef } from "../view/paramMediator.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Creates an object that contains encoders for every channel of a mark
|
|
7
8
|
*
|
|
8
|
-
* TODO: This should actually receive the mark as parameter
|
|
9
|
-
*
|
|
10
9
|
* TODO: This method should have a test. But how to mock Mark...
|
|
11
10
|
*
|
|
12
11
|
* @param {import("../marks/mark.js").default} mark
|
|
@@ -40,8 +39,9 @@ export default function createEncoders(mark, encoding) {
|
|
|
40
39
|
const resolution = mark.unitView.getScaleResolution(channelWithScale);
|
|
41
40
|
|
|
42
41
|
encoders[channel] = createEncoder(
|
|
42
|
+
mark,
|
|
43
43
|
encoding[channel],
|
|
44
|
-
resolution?.
|
|
44
|
+
resolution?.scale,
|
|
45
45
|
mark.unitView.getAccessor(channel),
|
|
46
46
|
channel
|
|
47
47
|
);
|
|
@@ -51,14 +51,14 @@ export default function createEncoders(mark, encoding) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* @param {import("../marks/mark.js").default} mark
|
|
55
55
|
* @param {import("../spec/channel.js").ChannelDef} channelDef
|
|
56
56
|
* @param {any} scale
|
|
57
57
|
* @param {Accessor} accessor
|
|
58
58
|
* @param {Channel} channel
|
|
59
59
|
* @returns {Encoder}
|
|
60
60
|
*/
|
|
61
|
-
export function createEncoder(channelDef, scale, accessor, channel) {
|
|
61
|
+
export function createEncoder(mark, channelDef, scale, accessor, channel) {
|
|
62
62
|
/**
|
|
63
63
|
* @typedef {import("../spec/channel.js").Channel} Channel
|
|
64
64
|
* @typedef {import("../types/encoder.js").Encoder} Encoder
|
|
@@ -69,11 +69,21 @@ export function createEncoder(channelDef, scale, accessor, channel) {
|
|
|
69
69
|
let encoder;
|
|
70
70
|
|
|
71
71
|
if (isValueDef(channelDef)) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
if (isExprRef(channelDef.value)) {
|
|
73
|
+
const fn = mark.unitView.paramMediator.createExpression(
|
|
74
|
+
channelDef.value.expr
|
|
75
|
+
);
|
|
76
|
+
encoder = /** @type {Encoder} */ ((datum) => fn(null));
|
|
77
|
+
encoder.constant = true;
|
|
78
|
+
encoder.constantValue = false;
|
|
79
|
+
encoder.accessor = accessor;
|
|
80
|
+
} else {
|
|
81
|
+
const value = channelDef.value;
|
|
82
|
+
encoder = /** @type {Encoder} */ ((datum) => value);
|
|
83
|
+
encoder.constant = true;
|
|
84
|
+
encoder.constantValue = true;
|
|
85
|
+
encoder.accessor = undefined;
|
|
86
|
+
}
|
|
77
87
|
} else if (accessor) {
|
|
78
88
|
if (channel == "text") {
|
|
79
89
|
// TODO: Define somewhere channels that don't use a scale
|
|
@@ -29,6 +29,7 @@ describe("Encoder", () => {
|
|
|
29
29
|
const encoders = {};
|
|
30
30
|
for (const [channel, channelDef] of Object.entries(encoding)) {
|
|
31
31
|
encoders[channel] = createEncoder(
|
|
32
|
+
null, // TODO: stub the mark
|
|
32
33
|
channelDef,
|
|
33
34
|
scales[channel],
|
|
34
35
|
accessorFactory.createAccessor(encodingSpecs[channel]),
|
|
@@ -95,4 +96,6 @@ describe("Encoder", () => {
|
|
|
95
96
|
});
|
|
96
97
|
|
|
97
98
|
// TODO: Test indexer
|
|
99
|
+
|
|
100
|
+
// TODO: Text ExprRef
|
|
98
101
|
});
|
package/dist/src/genomeSpy.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export default class GenomeSpy {
|
|
|
13
13
|
*/
|
|
14
14
|
constructor(container: HTMLElement, spec: import("./spec/root.js").RootSpec, options?: import("./types/embedApi.js").EmbedOptions);
|
|
15
15
|
container: HTMLElement;
|
|
16
|
+
options: import("./types/embedApi.js").EmbedOptions;
|
|
16
17
|
/** @type {(() => void)[]} */
|
|
17
18
|
_destructionCallbacks: (() => void)[];
|
|
18
19
|
/** Root level configuration object */
|
|
@@ -69,13 +70,16 @@ export default class GenomeSpy {
|
|
|
69
70
|
tooltipHandlers: Record<string, import("./tooltip/tooltipHandler.js").TooltipHandler>;
|
|
70
71
|
/** @type {View} */
|
|
71
72
|
viewRoot: import("./view/view.js").default;
|
|
72
|
-
_paramBroker: ParamBroker;
|
|
73
73
|
/**
|
|
74
74
|
* Views that are currently loading data using lazy sources.
|
|
75
75
|
*
|
|
76
76
|
* @type {Map<View, boolean>}
|
|
77
77
|
*/
|
|
78
78
|
_loadingViews: Map<import("./view/view.js").default, boolean>;
|
|
79
|
+
/**
|
|
80
|
+
* @type {HTMLElement}
|
|
81
|
+
*/
|
|
82
|
+
_inputBindingContainer: HTMLElement;
|
|
79
83
|
/**
|
|
80
84
|
*
|
|
81
85
|
* @param {(name: string) => any[]} provider
|
|
@@ -103,10 +107,9 @@ export default class GenomeSpy {
|
|
|
103
107
|
* animations with html elements than with WebGL.
|
|
104
108
|
*/
|
|
105
109
|
_updateLoadingIndicators(): void;
|
|
106
|
-
_prepareContainer(): void;
|
|
107
110
|
_glHelper: WebGLHelper;
|
|
108
|
-
loadingMessageElement:
|
|
109
|
-
loadingIndicatorsElement:
|
|
111
|
+
loadingMessageElement: HTMLElement;
|
|
112
|
+
loadingIndicatorsElement: HTMLElement;
|
|
110
113
|
tooltip: Tooltip;
|
|
111
114
|
/**
|
|
112
115
|
* Unregisters all listeners, removes all created dom elements, removes all css classes from the container
|
|
@@ -139,6 +142,7 @@ export default class GenomeSpy {
|
|
|
139
142
|
renderPickingFramebuffer(): void;
|
|
140
143
|
getSearchableViews(): UnitView[];
|
|
141
144
|
getNamedScaleResolutions(): Map<string, import("./view/scaleResolution.js").default>;
|
|
145
|
+
#private;
|
|
142
146
|
}
|
|
143
147
|
/**
|
|
144
148
|
* Events that are broadcasted to all views.
|
|
@@ -150,7 +154,6 @@ import Animator from "./utils/animator.js";
|
|
|
150
154
|
import GenomeStore from "./genome/genomeStore.js";
|
|
151
155
|
import BufferedViewRenderingContext from "./view/renderingContext/bufferedViewRenderingContext.js";
|
|
152
156
|
import Inertia from "./utils/inertia.js";
|
|
153
|
-
import ParamBroker from "./paramBroker.js";
|
|
154
157
|
import WebGLHelper from "./gl/webGLHelper.js";
|
|
155
158
|
import Tooltip from "./utils/ui/tooltip.js";
|
|
156
159
|
import UnitView from "./view/unitView.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"AA8CA;IACI;;;;;OAKG;IAEH;;;;;OAKG;IACH,uBAJW,WAAW,qDAEX,OAAO,qBAAqB,EAAE,YAAY,EA2FpD;IAxFG,uBAA0B;IAC1B,oDAAsB;IAItB,6BAA6B;IAC7B,uBADW,CAAC,MAAM,IAAI,CAAC,EAAE,CACM;IAE/B,sCAAsC;IACtC,wCAAgB;IAEhB,iCAA4C;IAC5C,yBAAoC;IAEpC,4CAA4C;IAC5C,oBADW,QAAU,MAAM,KAAE,MAAM,EAAE,CAAC,EAAE,CACZ;IAE5B,mBAAoD;IAEpD,0BAA0B;IAC1B,aADW,WAAW,CACM;IAE5B;;;;;OAKG;IACH,qEAF0B,OAAO,CAE8B;IAE/D,2CAA2C;IAC3C,mBADW,4BAA4B,CACL;IAClC,2CAA2C;IAC3C,iBADW,4BAA4B,CACP;IAEhC,oDAAoD;IACpD,6BAAgC;IAEhC;;;OAGG;IACH,eAFU;QAAE,IAAI,EAAE,OAAO,iBAAiB,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,OAAO,oBAAoB,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAEpF;IAE9B,uBAA+C;IAE/C;;;OAGG;IACH,oBAFU,IAAI,MAAM,EAAE,QAAU,aAAa,KAAE,IAAI,CAAC,EAAE,CAAC,CAEpB;IAEnC;;;;;;OAMG;IACH,yCAFkC,GAAG,KAAK,IAAI,GAEd;IAEhC;;;OAGG;IACH,kDAFkC,GAAG,KAAK,IAAI,GAEL;IAEzC,oFAAoF;IACpF,iBADW,OAAO,MAAM,EAAE,OAAO,6BAA6B,EAAE,cAAc,CAAC,CAK9E;IAED,mBAAmB;IACnB,2CAAyB;IAEzB;;;;OAIG;IACH,8DAA8B;IAE9B;;OAEG;IACH,wBAFU,WAAW,CAEkB;IA2C3C;;;OAGG;IACH,2CAFkB,MAAM,KAAK,GAAG,EAAE,QAIjC;IAED;;OAEG;IACH,+BAFW,MAAM,YAShB;IAED;;;;OAIG;IACH,sBAHW,MAAM,QACN,GAAG,EAAE,QAaf;IAED;;;;;OAKG;IACH,gBAHW,kBAAkB,YAClB,GAAG,QAQb;IAED;;;OAGG;IACH,iCAyCC;IA0DG,uBAOC;IAGD,mCAGE;IAOF,sCAEE;IAGF,iBAAyC;IAW7C;;OAEG;IACH,gBAuBC;IAED,sCA8MC;IAED;;;OAGG;IACH,UAFa,QAAQ,OAAO,CAAC,CA6B5B;IAED,4BA6IC;IAjIe,iCAAoC;IAmIpD;;;OAGG;IACH,kBAHW,MAAM,KACN,MAAM,QAiEhB;IAED;;;;;;;OAOG;IACH,oDAHuB,QAAQ,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAYlF;IAED,sBAyCC;IAED,kBAIC;IAED,iCAOC;IAED,iCASC;IAED,qFAWC;;CACJ;;;;iCA15BY,eAAe,GAAG,YAAY,GAAG,QAAQ,GAAG,gBAAgB;4BAjC7C,uBAAuB;4BA2BP,uBAAuB;qBAZ9C,qBAAqB;wBAIlB,yBAAyB;yCARR,yDAAyD;oBAYvD,oBAAoB;wBAdvC,qBAAqB;oBAXzB,uBAAuB;qBAStB,oBAAoB"}
|
package/dist/src/genomeSpy.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formats as vegaFormats } from "vega-loader";
|
|
2
|
-
import { html, render } from "lit
|
|
2
|
+
import { html, render } from "lit";
|
|
3
3
|
import { styleMap } from "lit/directives/style-map.js";
|
|
4
4
|
import SPINNER from "./img/90-ring-with-bg.svg";
|
|
5
5
|
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
checkForDuplicateScaleNames,
|
|
12
12
|
setImplicitScaleNames,
|
|
13
13
|
calculateCanvasSize,
|
|
14
|
+
calculateViewRootSize,
|
|
14
15
|
} from "./view/viewUtils.js";
|
|
15
16
|
import UnitView from "./view/unitView.js";
|
|
16
17
|
|
|
@@ -34,7 +35,7 @@ import dataTooltipHandler from "./tooltip/dataTooltipHandler.js";
|
|
|
34
35
|
import { invalidatePrefix } from "./utils/propertyCacher.js";
|
|
35
36
|
import { VIEW_ROOT_NAME, ViewFactory } from "./view/viewFactory.js";
|
|
36
37
|
import { reconfigureScales } from "./view/scaleResolution.js";
|
|
37
|
-
import
|
|
38
|
+
import createBindingInputs from "./utils/inputBinding.js";
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* Events that are broadcasted to all views.
|
|
@@ -59,14 +60,13 @@ export default class GenomeSpy {
|
|
|
59
60
|
*/
|
|
60
61
|
constructor(container, spec, options = {}) {
|
|
61
62
|
this.container = container;
|
|
63
|
+
this.options = options;
|
|
64
|
+
|
|
65
|
+
options.inputBindingContainer ??= "default";
|
|
62
66
|
|
|
63
67
|
/** @type {(() => void)[]} */
|
|
64
68
|
this._destructionCallbacks = [];
|
|
65
69
|
|
|
66
|
-
const styleElement = document.createElement("style");
|
|
67
|
-
styleElement.innerHTML = css;
|
|
68
|
-
container.appendChild(styleElement);
|
|
69
|
-
|
|
70
70
|
/** Root level configuration object */
|
|
71
71
|
this.spec = spec;
|
|
72
72
|
|
|
@@ -136,14 +136,57 @@ export default class GenomeSpy {
|
|
|
136
136
|
/** @type {View} */
|
|
137
137
|
this.viewRoot = undefined;
|
|
138
138
|
|
|
139
|
-
this._paramBroker = new ParamBroker();
|
|
140
|
-
|
|
141
139
|
/**
|
|
142
140
|
* Views that are currently loading data using lazy sources.
|
|
143
141
|
*
|
|
144
142
|
* @type {Map<View, boolean>}
|
|
145
143
|
*/
|
|
146
144
|
this._loadingViews = new Map();
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @type {HTMLElement}
|
|
148
|
+
*/
|
|
149
|
+
this._inputBindingContainer = undefined;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
get #canvasWrapper() {
|
|
153
|
+
return /** @type {HTMLElement} */ (
|
|
154
|
+
this.container.querySelector(".canvas-wrapper")
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
#initializeParameterBindings() {
|
|
159
|
+
/** @type {import("lit").TemplateResult[]} */
|
|
160
|
+
const inputs = [];
|
|
161
|
+
|
|
162
|
+
this.viewRoot.visit((view) => {
|
|
163
|
+
const mediator = view.paramMediator;
|
|
164
|
+
inputs.push(...createBindingInputs(mediator));
|
|
165
|
+
});
|
|
166
|
+
const ibc = this.options.inputBindingContainer;
|
|
167
|
+
|
|
168
|
+
if (!ibc || ibc == "none" || !inputs.length) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this._inputBindingContainer = element("div", {
|
|
173
|
+
className: "gs-input-bindings",
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
if (ibc == "default") {
|
|
177
|
+
this.container.appendChild(this._inputBindingContainer);
|
|
178
|
+
} else if (ibc instanceof HTMLElement) {
|
|
179
|
+
ibc.appendChild(this._inputBindingContainer);
|
|
180
|
+
} else {
|
|
181
|
+
throw new Error("Invalid inputBindingContainer");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (inputs.length) {
|
|
185
|
+
render(
|
|
186
|
+
html`<div class="gs-input-binding">${inputs}</div>`,
|
|
187
|
+
this._inputBindingContainer
|
|
188
|
+
);
|
|
189
|
+
}
|
|
147
190
|
}
|
|
148
191
|
|
|
149
192
|
/**
|
|
@@ -203,7 +246,7 @@ export default class GenomeSpy {
|
|
|
203
246
|
* animations with html elements than with WebGL.
|
|
204
247
|
*/
|
|
205
248
|
_updateLoadingIndicators() {
|
|
206
|
-
/** @type {import("lit
|
|
249
|
+
/** @type {import("lit").TemplateResult[]} */
|
|
207
250
|
const indicators = [];
|
|
208
251
|
|
|
209
252
|
const isSomethingVisible = () =>
|
|
@@ -245,17 +288,10 @@ export default class GenomeSpy {
|
|
|
245
288
|
render(indicators, this.loadingIndicatorsElement);
|
|
246
289
|
}
|
|
247
290
|
|
|
248
|
-
|
|
249
|
-
this.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
this._glHelper = new WebGLHelper(
|
|
253
|
-
this.container,
|
|
254
|
-
() =>
|
|
255
|
-
this.viewRoot
|
|
256
|
-
? calculateCanvasSize(this.viewRoot)
|
|
257
|
-
: { width: undefined, height: undefined },
|
|
258
|
-
this.spec.background
|
|
291
|
+
#setupDpr() {
|
|
292
|
+
const dprSetter = this.viewRoot.paramMediator.allocateSetter(
|
|
293
|
+
"devicePixelRatio",
|
|
294
|
+
window.devicePixelRatio
|
|
259
295
|
);
|
|
260
296
|
|
|
261
297
|
const resizeCallback = () => {
|
|
@@ -271,9 +307,6 @@ export default class GenomeSpy {
|
|
|
271
307
|
resizeObserver.observe(this.container);
|
|
272
308
|
this._destructionCallbacks.push(() => resizeObserver.disconnect());
|
|
273
309
|
|
|
274
|
-
const dprSetter = this._paramBroker.allocateSetter("devicePixelRatio");
|
|
275
|
-
dprSetter(window.devicePixelRatio);
|
|
276
|
-
|
|
277
310
|
/** @type {() => void} */
|
|
278
311
|
let remove = null;
|
|
279
312
|
|
|
@@ -295,22 +328,48 @@ export default class GenomeSpy {
|
|
|
295
328
|
if (remove) {
|
|
296
329
|
this._destructionCallbacks.push(remove);
|
|
297
330
|
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
#prepareContainer() {
|
|
334
|
+
this.container.classList.add("genome-spy");
|
|
335
|
+
|
|
336
|
+
const styleElement = document.createElement("style");
|
|
337
|
+
styleElement.innerHTML = css;
|
|
338
|
+
this.container.appendChild(styleElement);
|
|
339
|
+
|
|
340
|
+
const canvasWrapper = element("div", {
|
|
341
|
+
class: "canvas-wrapper",
|
|
342
|
+
});
|
|
343
|
+
this.container.appendChild(canvasWrapper);
|
|
344
|
+
|
|
345
|
+
canvasWrapper.classList.add("loading");
|
|
346
|
+
|
|
347
|
+
this._glHelper = new WebGLHelper(
|
|
348
|
+
canvasWrapper,
|
|
349
|
+
() =>
|
|
350
|
+
this.viewRoot
|
|
351
|
+
? calculateCanvasSize(calculateViewRootSize(this.viewRoot))
|
|
352
|
+
: { width: undefined, height: undefined },
|
|
353
|
+
this.spec.background
|
|
354
|
+
);
|
|
298
355
|
|
|
299
356
|
// The initial loading message that is shown until the first frame is rendered
|
|
300
|
-
this.loadingMessageElement =
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
357
|
+
this.loadingMessageElement = element("div", {
|
|
358
|
+
class: "loading-message",
|
|
359
|
+
innerHTML: `<div class="message">Loading<span class="ellipsis">...</span></div>`,
|
|
360
|
+
});
|
|
361
|
+
canvasWrapper.appendChild(this.loadingMessageElement);
|
|
304
362
|
|
|
305
363
|
// A container for loading indicators (for lazy data sources.)
|
|
306
364
|
// These could alternatively be included in the view hierarchy,
|
|
307
365
|
// but it's easier this way – particularly if we want to show
|
|
308
366
|
// some fancy animated spinners.
|
|
309
|
-
this.loadingIndicatorsElement =
|
|
310
|
-
|
|
311
|
-
|
|
367
|
+
this.loadingIndicatorsElement = element("div", {
|
|
368
|
+
class: "loading-indicators",
|
|
369
|
+
});
|
|
370
|
+
canvasWrapper.appendChild(this.loadingIndicatorsElement);
|
|
312
371
|
|
|
313
|
-
this.tooltip = new Tooltip(
|
|
372
|
+
this.tooltip = new Tooltip(canvasWrapper);
|
|
314
373
|
|
|
315
374
|
this.loadingMessageElement
|
|
316
375
|
.querySelector(".message")
|
|
@@ -327,8 +386,10 @@ export default class GenomeSpy {
|
|
|
327
386
|
destroy() {
|
|
328
387
|
// TODO: There's a memory leak somewhere
|
|
329
388
|
|
|
389
|
+
const canvasWrapper = this.#canvasWrapper;
|
|
390
|
+
|
|
330
391
|
this.container.classList.remove("genome-spy");
|
|
331
|
-
|
|
392
|
+
canvasWrapper.classList.remove("loading");
|
|
332
393
|
|
|
333
394
|
for (const [type, listeners] of this._keyboardListeners) {
|
|
334
395
|
for (const listener of listeners) {
|
|
@@ -340,6 +401,8 @@ export default class GenomeSpy {
|
|
|
340
401
|
|
|
341
402
|
this._glHelper.finalize();
|
|
342
403
|
|
|
404
|
+
this._inputBindingContainer?.remove();
|
|
405
|
+
|
|
343
406
|
while (this.container.firstChild) {
|
|
344
407
|
this.container.firstChild.remove();
|
|
345
408
|
}
|
|
@@ -367,8 +430,6 @@ export default class GenomeSpy {
|
|
|
367
430
|
return self._glHelper.dpr;
|
|
368
431
|
},
|
|
369
432
|
|
|
370
|
-
paramBroker: this._paramBroker,
|
|
371
|
-
|
|
372
433
|
requestLayoutReflow: () => {
|
|
373
434
|
// placeholder
|
|
374
435
|
},
|
|
@@ -463,6 +524,11 @@ export default class GenomeSpy {
|
|
|
463
524
|
VIEW_ROOT_NAME
|
|
464
525
|
);
|
|
465
526
|
|
|
527
|
+
this.#canvasWrapper.style.flexGrow =
|
|
528
|
+
calculateViewRootSize(this.viewRoot).height.grow > 0 ? "1" : "0";
|
|
529
|
+
|
|
530
|
+
this.#initializeParameterBindings();
|
|
531
|
+
|
|
466
532
|
checkForDuplicateScaleNames(this.viewRoot);
|
|
467
533
|
|
|
468
534
|
setImplicitScaleNames(this.viewRoot);
|
|
@@ -477,6 +543,7 @@ export default class GenomeSpy {
|
|
|
477
543
|
// We should now have a complete view hierarchy. Let's update the canvas size
|
|
478
544
|
// and ensure that the loading message is visible.
|
|
479
545
|
this._glHelper.invalidateSize();
|
|
546
|
+
this.#setupDpr();
|
|
480
547
|
|
|
481
548
|
// Collect all unit views to a list because they need plenty of initialization
|
|
482
549
|
const unitViews = /** @type {UnitView[]} */ (
|
|
@@ -506,12 +573,14 @@ export default class GenomeSpy {
|
|
|
506
573
|
view.mark.initializeData();
|
|
507
574
|
// Update WebGL buffers
|
|
508
575
|
view.mark.updateGraphicsData();
|
|
576
|
+
context.animator.requestRender();
|
|
509
577
|
}, view);
|
|
510
578
|
}
|
|
511
579
|
|
|
512
580
|
// Have to wait until asynchronous font loading is complete.
|
|
513
581
|
// Text mark's geometry builder needs font metrics before data can be
|
|
514
582
|
// converted into geometries.
|
|
583
|
+
// TODO: Make updateGraphicsData async and await font loading there.
|
|
515
584
|
await context.fontManager.waitUntilReady();
|
|
516
585
|
|
|
517
586
|
// Find all data sources and initiate loading
|
|
@@ -533,12 +602,6 @@ export default class GenomeSpy {
|
|
|
533
602
|
|
|
534
603
|
await graphicsInitialized;
|
|
535
604
|
|
|
536
|
-
this.viewRoot.visit((view) => {
|
|
537
|
-
for (const resolution of Object.values(view.resolutions.scale)) {
|
|
538
|
-
this._glHelper.createRangeTexture(resolution);
|
|
539
|
-
}
|
|
540
|
-
});
|
|
541
|
-
|
|
542
605
|
for (const view of unitViews) {
|
|
543
606
|
view.mark.finalizeGraphicsInitialization();
|
|
544
607
|
}
|
|
@@ -559,7 +622,7 @@ export default class GenomeSpy {
|
|
|
559
622
|
*/
|
|
560
623
|
async launch() {
|
|
561
624
|
try {
|
|
562
|
-
this
|
|
625
|
+
this.#prepareContainer();
|
|
563
626
|
|
|
564
627
|
await this._prepareViewsAndData();
|
|
565
628
|
|
|
@@ -578,7 +641,7 @@ export default class GenomeSpy {
|
|
|
578
641
|
|
|
579
642
|
return false;
|
|
580
643
|
} finally {
|
|
581
|
-
this.
|
|
644
|
+
this.#canvasWrapper.classList.remove("loading");
|
|
582
645
|
// Transition listener doesn't appear to work on observablehq
|
|
583
646
|
window.setTimeout(() => {
|
|
584
647
|
this.loadingMessageElement.style.display = "none";
|
|
@@ -914,3 +977,19 @@ function createMessageBox(container, message) {
|
|
|
914
977
|
messageBox.appendChild(messageText);
|
|
915
978
|
container.appendChild(messageBox);
|
|
916
979
|
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* @param {string} tag
|
|
983
|
+
* @param {Record<string, any>} attrs
|
|
984
|
+
*/
|
|
985
|
+
function element(tag, attrs) {
|
|
986
|
+
const el = document.createElement(tag);
|
|
987
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
988
|
+
if (["innerHTML", "innerText", "className"].includes(key)) {
|
|
989
|
+
// @ts-ignore
|
|
990
|
+
el[key] = value;
|
|
991
|
+
}
|
|
992
|
+
el.setAttribute(key, value);
|
|
993
|
+
}
|
|
994
|
+
return el;
|
|
995
|
+
}
|