@genome-spy/core 0.24.2 → 0.25.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/LICENSE +1 -1
- package/dist/index.js +38 -38
- package/package.json +2 -2
- package/src/data/dataFlow.js +39 -0
- package/src/data/sources/namedSource.js +20 -11
- package/src/embedApi.d.ts +12 -4
- package/src/genomeSpy.js +32 -3
- package/src/index.js +3 -0
- package/src/view/flowBuilder.js +5 -1
- package/src/view/viewContext.d.ts +1 -1
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
},
|
|
8
8
|
"contributors": [],
|
|
9
9
|
"license": "BSD-2-Clause",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.25.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": "1b8f0acaf7aaf15b1c6d348b7a1d891e41dbc977"
|
|
57
57
|
}
|
package/src/data/dataFlow.js
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* @typedef {import("./collector").default} Collector
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import NamedSource from "./sources/namedSource";
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
10
|
* @template H A key (string, object, whatever) that is used to retrieve
|
|
9
11
|
* data sources and collectors.
|
|
@@ -76,6 +78,43 @@ export default class DataFlow {
|
|
|
76
78
|
return this._dataSourcesByHost.get(key);
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
/**
|
|
82
|
+
*
|
|
83
|
+
* @param {string} name
|
|
84
|
+
*/
|
|
85
|
+
findNamedDataSource(name) {
|
|
86
|
+
/** @type {NamedSource} */
|
|
87
|
+
let namedSource;
|
|
88
|
+
/** @type {H[]} */
|
|
89
|
+
let hosts = [];
|
|
90
|
+
|
|
91
|
+
// Note: If a named sources with the same name are present at multiple locations in the
|
|
92
|
+
// view hierarchy, the should actually be exactly the same instance. It's arranged that
|
|
93
|
+
// way in the data flow optimization phase.
|
|
94
|
+
|
|
95
|
+
for (const [host, dataSource] of this._dataSourcesByHost.entries()) {
|
|
96
|
+
if (dataSource instanceof NamedSource) {
|
|
97
|
+
if (name == dataSource.identifier) {
|
|
98
|
+
if (namedSource && namedSource !== dataSource) {
|
|
99
|
+
// TODO: Write a test case for this and remove the runtime check.
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Found multiple instances of named data: ${name}. Data flow optimization is broken (it's a bug).`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
namedSource = dataSource;
|
|
105
|
+
hosts.push(host);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (namedSource) {
|
|
111
|
+
return {
|
|
112
|
+
dataSource: namedSource,
|
|
113
|
+
hosts,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
79
118
|
/**
|
|
80
119
|
*
|
|
81
120
|
* @param {Collector} collector
|
|
@@ -10,14 +10,20 @@ export function isNamedData(data) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
export default class NamedSource extends DataSource {
|
|
13
|
+
/**
|
|
14
|
+
* Data that has been provided explicitly using the updateDynamicData method
|
|
15
|
+
* @type {any[]}
|
|
16
|
+
*/
|
|
17
|
+
#explicitData;
|
|
18
|
+
|
|
13
19
|
/**
|
|
14
20
|
* @param {import("../../spec/data").NamedData} params
|
|
15
|
-
* @param {function(string):any[]}
|
|
21
|
+
* @param {function(string):any[]} provider Function that retrieves a dataset using a name
|
|
16
22
|
*/
|
|
17
|
-
constructor(params,
|
|
23
|
+
constructor(params, provider) {
|
|
18
24
|
super();
|
|
19
25
|
|
|
20
|
-
this.
|
|
26
|
+
this.provider = provider;
|
|
21
27
|
this.params = params;
|
|
22
28
|
}
|
|
23
29
|
|
|
@@ -28,17 +34,20 @@ export default class NamedSource extends DataSource {
|
|
|
28
34
|
return this.params.name;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Update the named data. If data is omitted, a data provider is used instead.
|
|
39
|
+
*
|
|
40
|
+
* @param {import("../flowNode").Datum[]} [data]
|
|
41
|
+
*/
|
|
42
|
+
updateDynamicData(data) {
|
|
43
|
+
// TODO: Throw is data is undefined and the provider is unable to provide any data
|
|
44
|
+
this.#explicitData = data;
|
|
45
|
+
this.loadSynchronously();
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
loadSynchronously() {
|
|
41
|
-
const data =
|
|
49
|
+
const data =
|
|
50
|
+
this.#explicitData ?? this.provider(this.params.name) ?? [];
|
|
42
51
|
|
|
43
52
|
/** @type {(x: any) => import("../flowNode").Datum} */
|
|
44
53
|
let wrap = (x) => x;
|
package/src/embedApi.d.ts
CHANGED
|
@@ -17,9 +17,9 @@ export type EmbedFunction = (
|
|
|
17
17
|
|
|
18
18
|
export interface EmbedOptions {
|
|
19
19
|
/**
|
|
20
|
-
* A function that allows retrieval of named data
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* A function that allows retrieval of named data. There are two ways to provide named data:
|
|
21
|
+
* 1. A data provider (this)
|
|
22
|
+
* 2. Explicit updates using the `updateNamedData` method (the other).
|
|
23
23
|
*/
|
|
24
24
|
namedDataProvider?: (name: string) => any[];
|
|
25
25
|
|
|
@@ -52,8 +52,16 @@ export interface EmbedResult {
|
|
|
52
52
|
removeEventListener: (type: string, listener: (event: any) => void) => void;
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
|
-
* Returns a named
|
|
55
|
+
* Returns a named `ScaleResolution` object that allows for attaching event
|
|
56
56
|
* listeners and controlling the scale domain.
|
|
57
57
|
*/
|
|
58
58
|
getScaleResolutionByName: (name: string) => ScaleResolutionApi;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Updates a named dataset
|
|
62
|
+
*
|
|
63
|
+
* @param name data source to update
|
|
64
|
+
* @param data new data. If left undefined, the data is retrieved from a provider.
|
|
65
|
+
*/
|
|
66
|
+
updateNamedData: (name: string, data?: any[]) => void;
|
|
59
67
|
}
|
package/src/genomeSpy.js
CHANGED
|
@@ -137,10 +137,9 @@ export default class GenomeSpy {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
|
-
*
|
|
141
140
|
* @param {string} name
|
|
142
141
|
*/
|
|
143
|
-
|
|
142
|
+
getNamedDataFromProvider(name) {
|
|
144
143
|
for (const provider of this.namedDataProviders) {
|
|
145
144
|
const data = provider(name);
|
|
146
145
|
if (data) {
|
|
@@ -149,6 +148,36 @@ export default class GenomeSpy {
|
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
150
|
|
|
151
|
+
/**
|
|
152
|
+
*
|
|
153
|
+
* @param {string} name
|
|
154
|
+
* @param {any[]} data
|
|
155
|
+
*/
|
|
156
|
+
updateNamedData(name, data) {
|
|
157
|
+
const namedSource =
|
|
158
|
+
this.viewRoot.context.dataFlow.findNamedDataSource(name);
|
|
159
|
+
if (!namedSource) {
|
|
160
|
+
throw new Error("No such named data source: " + name);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
namedSource.dataSource.updateDynamicData(data);
|
|
164
|
+
|
|
165
|
+
// Scale domains may need adjustment.
|
|
166
|
+
// TODO: Refactor so that Collectors handle scale extents etc.
|
|
167
|
+
for (const host of namedSource.hosts) {
|
|
168
|
+
host.visit((view) => {
|
|
169
|
+
for (const resolution of Object.values(
|
|
170
|
+
view.resolutions.scale
|
|
171
|
+
)) {
|
|
172
|
+
// TODO: Only update domain
|
|
173
|
+
resolution.reconfigure();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.animator.requestRender();
|
|
179
|
+
}
|
|
180
|
+
|
|
152
181
|
/**
|
|
153
182
|
* Broadcast a message to all views
|
|
154
183
|
*
|
|
@@ -243,7 +272,7 @@ export default class GenomeSpy {
|
|
|
243
272
|
// placeholder
|
|
244
273
|
},
|
|
245
274
|
updateTooltip: this.updateTooltip.bind(this),
|
|
246
|
-
|
|
275
|
+
getNamedDataFromProvider: this.getNamedDataFromProvider.bind(this),
|
|
247
276
|
getCurrentHover: () => this._currentHover,
|
|
248
277
|
|
|
249
278
|
addKeyboardListener: (type, listener) => {
|
package/src/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export { GenomeSpy, html, icon };
|
|
|
11
11
|
* Embeds GenomeSpy into the DOM
|
|
12
12
|
*
|
|
13
13
|
* @type {import("./embedApi.js").EmbedFunction}
|
|
14
|
+
* @returns {Promise<import("./embedApi").EmbedResult>}
|
|
14
15
|
*/
|
|
15
16
|
export async function embed(el, spec, options = {}) {
|
|
16
17
|
/** @type {HTMLElement} */
|
|
@@ -85,6 +86,8 @@ export async function embed(el, spec, options = {}) {
|
|
|
85
86
|
getScaleResolutionByName(name) {
|
|
86
87
|
return genomeSpy.getNamedScaleResolutions().get(name);
|
|
87
88
|
},
|
|
89
|
+
|
|
90
|
+
updateNamedData: genomeSpy.updateNamedData.bind(genomeSpy),
|
|
88
91
|
};
|
|
89
92
|
}
|
|
90
93
|
|
package/src/view/flowBuilder.js
CHANGED
|
@@ -116,7 +116,11 @@ export function buildDataFlow(root, existingFlow) {
|
|
|
116
116
|
const dataSource = isDynamicCallbackData(view.spec.data)
|
|
117
117
|
? view.getDynamicDataSource()
|
|
118
118
|
: isNamedData(view.spec.data)
|
|
119
|
-
?
|
|
119
|
+
? // TODO: Only one NamedSource instance per unique name should exists
|
|
120
|
+
new NamedSource(
|
|
121
|
+
view.spec.data,
|
|
122
|
+
view.context.getNamedDataFromProvider
|
|
123
|
+
)
|
|
120
124
|
: createDataSource(view.spec.data, view.getBaseUrl());
|
|
121
125
|
|
|
122
126
|
currentNode = dataSource;
|