@genome-spy/core 0.19.0 → 0.21.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.
Files changed (101) hide show
  1. package/dist/index.js +46 -119
  2. package/dist/schema.json +213 -25
  3. package/package.json +4 -3
  4. package/src/data/collector.test.js +2 -0
  5. package/src/data/dataFlow.test.js +2 -0
  6. package/src/data/flow.test.js +1 -0
  7. package/src/data/flowNode.test.js +1 -0
  8. package/src/data/flowOptimizer.test.js +1 -0
  9. package/src/data/formats/fasta.test.js +1 -0
  10. package/src/data/sources/inlineSource.test.js +1 -0
  11. package/src/data/sources/sequenceSource.test.js +1 -0
  12. package/src/data/transforms/clone.test.js +1 -0
  13. package/src/data/transforms/coverage.test.js +1 -0
  14. package/src/data/transforms/filter.test.js +1 -0
  15. package/src/data/transforms/flattenDelimited.test.js +1 -0
  16. package/src/data/transforms/flattenSequence.test.js +1 -0
  17. package/src/data/transforms/formula.test.js +1 -0
  18. package/src/data/transforms/identifier.test.js +1 -0
  19. package/src/data/transforms/pileup.test.js +1 -0
  20. package/src/data/transforms/project.test.js +1 -0
  21. package/src/data/transforms/regexExtract.test.js +1 -0
  22. package/src/data/transforms/regexFold.test.js +1 -0
  23. package/src/data/transforms/sample.test.js +1 -0
  24. package/src/data/transforms/stack.test.js +1 -0
  25. package/src/encoder/accessor.test.js +1 -0
  26. package/src/encoder/encoder.test.js +1 -0
  27. package/src/genome/genome.test.js +1 -0
  28. package/src/genome/scaleIndex.js +3 -2
  29. package/src/genome/scaleIndex.test.js +23 -6
  30. package/src/genome/scaleLocus.test.js +1 -0
  31. package/src/genomeSpy.js +16 -11
  32. package/src/gl/dataToVertices.js +52 -52
  33. package/src/gl/includes/common.glsl +12 -12
  34. package/src/gl/includes/picking.fragment.glsl +0 -2
  35. package/src/gl/includes/picking.vertex.glsl +0 -2
  36. package/src/gl/includes/scales.glsl +33 -2
  37. package/src/gl/point.vertex.glsl +0 -2
  38. package/src/gl/rule.vertex.glsl +1 -1
  39. package/src/gl/webGLHelper.js +0 -3
  40. package/src/marks/link.js +32 -39
  41. package/src/marks/mark.js +176 -106
  42. package/src/marks/pointMark.js +28 -59
  43. package/src/marks/rectMark.js +38 -33
  44. package/src/marks/rule.js +31 -21
  45. package/src/marks/text.js +18 -14
  46. package/src/scale/glslScaleGenerator.js +56 -17
  47. package/src/scale/scale.test.js +1 -0
  48. package/src/scale/ticks.test.js +1 -0
  49. package/src/spec/mark.d.ts +0 -3
  50. package/src/spec/scale.d.ts +0 -9
  51. package/src/spec/title.d.ts +102 -0
  52. package/src/spec/view.d.ts +6 -4
  53. package/src/tooltip/dataTooltipHandler.js +3 -2
  54. package/src/utils/addBaseUrl.test.js +1 -0
  55. package/src/utils/binnedIndex.js +147 -0
  56. package/src/utils/binnedIndex.test.js +73 -0
  57. package/src/utils/cloner.test.js +1 -0
  58. package/src/utils/coalesce.test.js +1 -0
  59. package/src/utils/concatIterables.test.js +1 -0
  60. package/src/utils/domainArray.test.js +1 -0
  61. package/src/utils/indexer.test.js +1 -0
  62. package/src/utils/iterateNestedMaps.test.js +1 -0
  63. package/src/utils/kWayMerge.test.js +1 -0
  64. package/src/utils/layout/flexLayout.js +35 -3
  65. package/src/utils/layout/flexLayout.test.js +15 -0
  66. package/src/utils/layout/grid.js +95 -0
  67. package/src/utils/layout/grid.test.js +71 -0
  68. package/src/utils/layout/padding.js +13 -0
  69. package/src/utils/layout/rectangle.js +6 -0
  70. package/src/utils/layout/rectangle.test.js +1 -0
  71. package/src/utils/mergeObjects.test.js +1 -0
  72. package/src/utils/numberExtractor.test.js +1 -0
  73. package/src/utils/propertyCacher.test.js +1 -0
  74. package/src/utils/propertyCoalescer.test.js +1 -0
  75. package/src/utils/reservationMap.test.js +1 -0
  76. package/src/utils/topK.test.js +1 -0
  77. package/src/utils/variableTools.test.js +1 -0
  78. package/src/view/axisResolution.test.js +1 -0
  79. package/src/view/axisView.js +3 -5
  80. package/src/view/concatView.js +24 -275
  81. package/src/view/flowBuilder.test.js +1 -0
  82. package/src/view/gridView.js +774 -0
  83. package/src/view/implicitRootView.js +14 -0
  84. package/src/view/layerView.js +15 -1
  85. package/src/view/renderingContext/deferredViewRenderingContext.js +3 -1
  86. package/src/view/renderingContext/simpleViewRenderingContext.js +3 -1
  87. package/src/view/scaleResolution.js +5 -11
  88. package/src/view/scaleResolution.test.js +1 -0
  89. package/src/view/title.js +165 -0
  90. package/src/view/unitView.js +9 -5
  91. package/src/view/view.js +35 -14
  92. package/src/view/view.test.js +1 -0
  93. package/src/view/viewContext.d.ts +6 -1
  94. package/src/view/viewFactory.test.js +1 -0
  95. package/src/view/viewUtils.js +1 -93
  96. package/src/view/zoom.js +89 -0
  97. package/src/gl/includes/fp64-arithmetic.glsl +0 -187
  98. package/src/gl/includes/fp64-utils.js +0 -142
  99. package/src/gl/includes/scales_fp64.glsl +0 -30
  100. package/src/utils/binnedRangeIndex.js +0 -83
  101. package/src/view/decoratorView.js +0 -513
@@ -1,22 +1,10 @@
1
- import { isHConcatSpec, isVConcatSpec } from "./viewFactory";
2
- import ContainerView from "./containerView";
3
- import {
4
- mapToPixelCoords,
5
- getMinimumSize,
6
- parseSizeDef,
7
- FlexDimensions,
8
- } from "../utils/layout/flexLayout";
9
- import Rectangle from "../utils/layout/rectangle";
10
- import Padding from "../utils/layout/padding";
11
- import { peek } from "../utils/arrayUtils";
1
+ import { isConcatSpec, isVConcatSpec } from "./viewFactory";
2
+ import GridView from "./gridView";
12
3
 
13
4
  /**
14
5
  * Creates a vertically or horizontally concatenated layout for children.
15
- *
16
- * @typedef {import("./view").default} View
17
- * @typedef { import("../utils/layout/flexLayout").SizeDef} SizeDef
18
6
  */
19
- export default class ConcatView extends ContainerView {
7
+ export default class ConcatView extends GridView {
20
8
  /**
21
9
  *
22
10
  * @param {import("./viewUtils").AnyConcatSpec} spec
@@ -25,272 +13,33 @@ export default class ConcatView extends ContainerView {
25
13
  * @param {string} name
26
14
  */
27
15
  constructor(spec, context, parent, name) {
28
- super(spec, context, parent, name);
16
+ super(
17
+ spec,
18
+ context,
19
+ parent,
20
+ name,
21
+ isConcatSpec(spec)
22
+ ? spec.columns
23
+ : isVConcatSpec(spec)
24
+ ? 1
25
+ : Infinity
26
+ );
29
27
 
30
28
  this.spec = spec;
29
+ }
31
30
 
32
- if (!("spacing" in this.spec)) {
33
- this.spec.spacing = 10; // TODO: Provide a global configuration (theme!)
34
- }
35
-
36
- /** @type {import("../spec/view").GeometricDimension } */
37
- this.mainDimension = isHConcatSpec(spec) ? "width" : "height";
38
- /** @type {import("../spec/view").GeometricDimension } */
39
- this.secondaryDimension =
40
- this.mainDimension == "width" ? "height" : "width";
41
-
42
- const childSpecs = isHConcatSpec(spec)
43
- ? spec.hconcat
31
+ _createChildren() {
32
+ const spec = this.spec;
33
+ const childSpecs = isConcatSpec(spec)
34
+ ? spec.concat
44
35
  : isVConcatSpec(spec)
45
36
  ? spec.vconcat
46
- : spec.concat;
37
+ : spec.hconcat;
47
38
 
48
- /** @type { View[] } */
49
- this.children = childSpecs.map((childSpec, i) =>
50
- context.createView(childSpec, this, "concat" + i)
39
+ this.setChildren(
40
+ childSpecs.map((childSpec, i) =>
41
+ this.context.createView(childSpec, this, "grid" + i)
42
+ )
51
43
  );
52
44
  }
53
-
54
- /*
55
- _getEffectiveChildPaddings() {
56
- return this.children
57
- .map((view) => view.getEffectivePadding())
58
- .map((padding) =>
59
- this.mainDimension == "height"
60
- ? [padding.left, padding.right]
61
- : [padding.top, padding.bottom]
62
- )
63
- }
64
- */
65
-
66
- getEffectivePadding() {
67
- return this._cache("size/effectivePadding", () => {
68
- const visibleChildren = this.children.filter((view) =>
69
- view.isVisible()
70
- );
71
-
72
- if (!visibleChildren.length) {
73
- return this.getPadding();
74
- }
75
-
76
- // Max paddings along the secondary dimension
77
-
78
- const paddings = visibleChildren
79
- .map((view) => view.getEffectivePadding())
80
- .map((padding) =>
81
- this.mainDimension == "height"
82
- ? [padding.left, padding.right]
83
- : [padding.top, padding.bottom]
84
- );
85
-
86
- const maxPaddings = getMaxEffectivePaddings(paddings);
87
-
88
- const effectiveChildPadding =
89
- this.mainDimension == "height"
90
- ? new Padding(
91
- visibleChildren[0].getEffectivePadding().top,
92
- maxPaddings[1],
93
- peek(visibleChildren).getEffectivePadding().bottom,
94
- maxPaddings[0]
95
- )
96
- : new Padding(
97
- maxPaddings[0],
98
- visibleChildren[0].getEffectivePadding().left,
99
- maxPaddings[1],
100
- peek(visibleChildren).getEffectivePadding().right
101
- );
102
-
103
- return this.getPadding().add(effectiveChildPadding);
104
- });
105
- }
106
-
107
- getSize() {
108
- return this._cache("size", () => {
109
- /** @type {SizeDef} */
110
- let mainSizeDef;
111
- if (this.spec[this.mainDimension]) {
112
- mainSizeDef = parseSizeDef(this.spec[this.mainDimension]);
113
- } else {
114
- const childMainSizeDefs = this.children
115
- .filter((view) => view.isVisible())
116
- .map((view) => view.getSize()[this.mainDimension]);
117
-
118
- mainSizeDef = {
119
- // Grows are summed to support sensible nesting of concatViews
120
- grow: childMainSizeDefs
121
- .map((sizeDef) => +sizeDef.grow)
122
- .reduce((a, b) => a + b, 0),
123
- px: getMinimumSize(childMainSizeDefs, {
124
- spacing: this.spec.spacing,
125
- }),
126
- };
127
- }
128
-
129
- const secondarySizeDef = (this.spec[this.secondaryDimension] &&
130
- parseSizeDef(this.spec[this.secondaryDimension])) || {
131
- grow: 1,
132
- };
133
-
134
- return (
135
- this.mainDimension == "height"
136
- ? new FlexDimensions(secondarySizeDef, mainSizeDef)
137
- : new FlexDimensions(mainSizeDef, secondarySizeDef)
138
- ).addPadding(this.getPadding());
139
- });
140
- }
141
-
142
- /**
143
- * @param {import("./renderingContext/viewRenderingContext").default} context
144
- * @param {import("../utils/layout/rectangle").default} coords
145
- * @param {import("./view").RenderingOptions} [options]
146
- */
147
- render(context, coords, options = {}) {
148
- if (!this.isVisible()) {
149
- return;
150
- }
151
-
152
- coords = coords.shrink(this.getPadding());
153
- context.pushView(this, coords);
154
-
155
- // This method produces piles of garbage when used with sample faceting.
156
- // TODO: Figure out something. Perhaps the rectangles could be cached because
157
- // they are identical for each sample facet.
158
-
159
- const visibleChildren = this.children.filter((view) =>
160
- view.isVisible()
161
- );
162
- const childSizeDefs = visibleChildren.map(
163
- (view) => view.getSize()[this.mainDimension]
164
- );
165
-
166
- const mappedCoords = mapToPixelCoords(
167
- childSizeDefs,
168
- coords[this.mainDimension],
169
- {
170
- spacing: this.spec.spacing,
171
- devicePixelRatio: this.context.glHelper.dpr,
172
- }
173
- );
174
-
175
- // Align the views.
176
- const paddings = visibleChildren
177
- .map((view) => view.getEffectivePadding())
178
- .map((padding) =>
179
- this.mainDimension == "height"
180
- ? [padding.left, padding.right]
181
- : [padding.top, padding.bottom]
182
- );
183
-
184
- const maxPaddings = getMaxEffectivePaddings(paddings);
185
-
186
- for (let i = 0; i < visibleChildren.length; i++) {
187
- const view = visibleChildren[i];
188
- const flexCoords = mappedCoords[i];
189
-
190
- const pa = maxPaddings[0] - paddings[i][0];
191
- const pb = maxPaddings[1] - paddings[i][1];
192
-
193
- const secondarySize = coords[this.secondaryDimension] - pa - pb;
194
-
195
- const childCoords =
196
- this.mainDimension == "height"
197
- ? new Rectangle(
198
- () => coords.x + pa,
199
- () => coords.y + flexCoords.location,
200
- () => secondarySize,
201
- () => flexCoords.size
202
- )
203
- : new Rectangle(
204
- () => coords.x + flexCoords.location,
205
- () => coords.y + pa,
206
- () => flexCoords.size,
207
- () => secondarySize
208
- );
209
-
210
- view.render(context, childCoords, options);
211
- }
212
-
213
- context.popView(this);
214
- }
215
-
216
- /**
217
- * @returns {IterableIterator<View>}
218
- */
219
- *[Symbol.iterator]() {
220
- for (const child of this.children) {
221
- yield child;
222
- }
223
- }
224
-
225
- /**
226
- * @param {import("./view").default} child
227
- * @param {import("./view").default} replacement
228
- */
229
- replaceChild(child, replacement) {
230
- const i = this.children.indexOf(child);
231
- if (i >= 0) {
232
- this.children[i] = replacement;
233
- } else {
234
- throw new Error("Not my child view!");
235
- }
236
- }
237
-
238
- /**
239
- * Adds a child using a spec. Does NOT perform any initializations.
240
- * Returns the newly added view instance.
241
- *
242
- * @param {import("./viewUtils").ViewSpec} viewSpec
243
- */
244
- addChildBySpec(viewSpec) {
245
- // TODO: Move to containerView
246
-
247
- // TODO: More robust solution. Will break in future when views can be removed
248
- const i = this.children.length;
249
-
250
- const view = this.context.createView(viewSpec, this, "concat" + i);
251
- this.children.push(view);
252
-
253
- return view;
254
- }
255
-
256
- /**
257
- * Adds a child. Does NOT perform any initializations.
258
- * Returns the newly added view instance.
259
- *
260
- * @param {View} view
261
- */
262
- addChild(view) {
263
- // TODO: Move to containerView
264
-
265
- // TODO: More robust solution. Will break in future when views can be removed
266
- const i = this.children.length;
267
-
268
- if (!view.name) {
269
- view.name = "concat" + i;
270
- }
271
- view.parent = this;
272
- this.children.push(view);
273
-
274
- return view;
275
- }
276
-
277
- /**
278
- * @param {string} channel
279
- * @param {import("./containerView").ResolutionTarget} resolutionType
280
- * @returns {import("../spec/view").ResolutionBehavior}
281
- */
282
- getDefaultResolution(channel, resolutionType) {
283
- // TODO: Default to shared when working with genomic coordinates
284
- return "independent";
285
- }
286
- }
287
-
288
- /**
289
- *
290
- * @param {number[][]} paddings
291
- */
292
- function getMaxEffectivePaddings(paddings) {
293
- return [0, 1].map((i) =>
294
- paddings.map((p) => p[i]).reduce((a, c) => Math.max(a, c), 0)
295
- );
296
45
  }
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import Collector from "../data/collector";
2
3
  import FlowNode from "../data/flowNode";
3
4
  import FilterTransform from "../data/transforms/filter";