@genome-spy/core 0.68.0 → 0.69.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 (163) hide show
  1. package/dist/bundle/index.es.js +12108 -10682
  2. package/dist/bundle/index.js +119 -119
  3. package/dist/schema.json +6224 -6319
  4. package/dist/src/data/dataFlow.d.ts.map +1 -1
  5. package/dist/src/data/dataFlow.js +10 -0
  6. package/dist/src/data/flowNode.d.ts +25 -10
  7. package/dist/src/data/flowNode.d.ts.map +1 -1
  8. package/dist/src/data/flowNode.js +66 -13
  9. package/dist/src/data/flowTestUtils.d.ts +2 -2
  10. package/dist/src/data/flowTestUtils.d.ts.map +1 -1
  11. package/dist/src/data/flowTestUtils.js +5 -4
  12. package/dist/src/data/sources/dataSource.js +2 -2
  13. package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
  14. package/dist/src/data/sources/lazy/bigBedSource.js +11 -10
  15. package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
  16. package/dist/src/data/sources/lazy/bigWigSource.js +11 -10
  17. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +1 -1
  18. package/dist/src/data/sources/lazy/tabixSource.d.ts +0 -1
  19. package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
  20. package/dist/src/data/sources/lazy/tabixSource.js +41 -11
  21. package/dist/src/data/sources/sequenceSource.d.ts.map +1 -1
  22. package/dist/src/data/sources/sequenceSource.js +5 -3
  23. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  24. package/dist/src/data/sources/urlSource.js +7 -3
  25. package/dist/src/data/transforms/filter.d.ts +4 -4
  26. package/dist/src/data/transforms/filter.d.ts.map +1 -1
  27. package/dist/src/data/transforms/filter.js +13 -7
  28. package/dist/src/data/transforms/filterScoredLabels.d.ts.map +1 -1
  29. package/dist/src/data/transforms/filterScoredLabels.js +11 -6
  30. package/dist/src/data/transforms/filterScoredLabels.test.d.ts +2 -0
  31. package/dist/src/data/transforms/filterScoredLabels.test.d.ts.map +1 -0
  32. package/dist/src/data/transforms/formula.d.ts +4 -4
  33. package/dist/src/data/transforms/formula.d.ts.map +1 -1
  34. package/dist/src/data/transforms/formula.js +12 -6
  35. package/dist/src/data/transforms/measureText.d.ts +2 -2
  36. package/dist/src/data/transforms/measureText.d.ts.map +1 -1
  37. package/dist/src/data/transforms/measureText.js +16 -12
  38. package/dist/src/data/transforms/transform.d.ts +2 -2
  39. package/dist/src/data/transforms/transform.d.ts.map +1 -1
  40. package/dist/src/data/transforms/transform.js +3 -3
  41. package/dist/src/encoder/accessor.d.ts +8 -4
  42. package/dist/src/encoder/accessor.d.ts.map +1 -1
  43. package/dist/src/encoder/accessor.js +10 -10
  44. package/dist/src/encoder/encoder.js +5 -5
  45. package/dist/src/genome/genome.d.ts +8 -0
  46. package/dist/src/genome/genome.d.ts.map +1 -1
  47. package/dist/src/genome/genome.js +16 -1
  48. package/dist/src/genomeSpy/inputBindingManager.js +1 -1
  49. package/dist/src/genomeSpy/interactionController.d.ts.map +1 -1
  50. package/dist/src/genomeSpy/interactionController.js +7 -1
  51. package/dist/src/genomeSpy.js +1 -1
  52. package/dist/src/gl/glslScaleGenerator.js +1 -1
  53. package/dist/src/marks/mark.d.ts.map +1 -1
  54. package/dist/src/marks/mark.js +22 -30
  55. package/dist/src/marks/point.d.ts.map +1 -1
  56. package/dist/src/marks/point.js +4 -6
  57. package/dist/src/paramRuntime/expressionCompiler.d.ts +7 -0
  58. package/dist/src/paramRuntime/expressionCompiler.d.ts.map +1 -0
  59. package/dist/src/paramRuntime/expressionCompiler.js +10 -0
  60. package/dist/src/paramRuntime/expressionRef.d.ts +20 -0
  61. package/dist/src/paramRuntime/expressionRef.d.ts.map +1 -0
  62. package/dist/src/paramRuntime/expressionRef.js +95 -0
  63. package/dist/src/paramRuntime/expressionRef.test.d.ts +2 -0
  64. package/dist/src/paramRuntime/expressionRef.test.d.ts.map +1 -0
  65. package/dist/src/paramRuntime/graphRuntime.d.ts +176 -0
  66. package/dist/src/paramRuntime/graphRuntime.d.ts.map +1 -0
  67. package/dist/src/paramRuntime/graphRuntime.js +628 -0
  68. package/dist/src/paramRuntime/graphRuntime.test.d.ts +2 -0
  69. package/dist/src/paramRuntime/graphRuntime.test.d.ts.map +1 -0
  70. package/dist/src/paramRuntime/index.d.ts +9 -0
  71. package/dist/src/paramRuntime/index.d.ts.map +1 -0
  72. package/dist/src/paramRuntime/index.js +8 -0
  73. package/dist/src/paramRuntime/lifecycleRegistry.d.ts +27 -0
  74. package/dist/src/paramRuntime/lifecycleRegistry.d.ts.map +1 -0
  75. package/dist/src/paramRuntime/lifecycleRegistry.js +54 -0
  76. package/dist/src/paramRuntime/paramRuntime.d.ts +165 -0
  77. package/dist/src/paramRuntime/paramRuntime.d.ts.map +1 -0
  78. package/dist/src/paramRuntime/paramRuntime.js +222 -0
  79. package/dist/src/paramRuntime/paramRuntime.test.d.ts +2 -0
  80. package/dist/src/paramRuntime/paramRuntime.test.d.ts.map +1 -0
  81. package/dist/src/paramRuntime/paramStore.d.ts +68 -0
  82. package/dist/src/paramRuntime/paramStore.d.ts.map +1 -0
  83. package/dist/src/paramRuntime/paramStore.js +148 -0
  84. package/dist/src/paramRuntime/paramStore.test.d.ts +2 -0
  85. package/dist/src/paramRuntime/paramStore.test.d.ts.map +1 -0
  86. package/dist/src/paramRuntime/paramUtils.d.ts +86 -0
  87. package/dist/src/paramRuntime/paramUtils.d.ts.map +1 -0
  88. package/dist/src/paramRuntime/paramUtils.js +272 -0
  89. package/dist/src/paramRuntime/selectionStore.d.ts +6 -0
  90. package/dist/src/paramRuntime/selectionStore.d.ts.map +1 -0
  91. package/dist/src/paramRuntime/selectionStore.js +13 -0
  92. package/dist/src/paramRuntime/types.d.ts +16 -0
  93. package/dist/src/paramRuntime/types.d.ts.map +1 -0
  94. package/dist/src/paramRuntime/types.js +25 -0
  95. package/dist/src/paramRuntime/viewParamRuntime.d.ts +164 -0
  96. package/dist/src/paramRuntime/viewParamRuntime.d.ts.map +1 -0
  97. package/dist/src/paramRuntime/viewParamRuntime.js +443 -0
  98. package/dist/src/scales/scaleInstanceManager.d.ts +6 -3
  99. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
  100. package/dist/src/scales/scaleInstanceManager.js +17 -11
  101. package/dist/src/scales/scaleResolution.d.ts +1 -0
  102. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  103. package/dist/src/scales/scaleResolution.js +7 -1
  104. package/dist/src/selection/selection.js +1 -1
  105. package/dist/src/spec/coreSchemaRoot.d.ts +53 -0
  106. package/dist/src/spec/root.d.ts +1 -1
  107. package/dist/src/spec/view.d.ts +114 -33
  108. package/dist/src/tooltip/dataTooltipHandler.d.ts +1 -1
  109. package/dist/src/tooltip/dataTooltipHandler.js +23 -32
  110. package/dist/src/tooltip/dataTooltipHandler.test.d.ts +2 -0
  111. package/dist/src/tooltip/dataTooltipHandler.test.d.ts.map +1 -0
  112. package/dist/src/tooltip/flattenDatumRows.d.ts +13 -0
  113. package/dist/src/tooltip/flattenDatumRows.d.ts.map +1 -0
  114. package/dist/src/tooltip/flattenDatumRows.js +47 -0
  115. package/dist/src/tooltip/flattenDatumRows.test.d.ts +2 -0
  116. package/dist/src/tooltip/flattenDatumRows.test.d.ts.map +1 -0
  117. package/dist/src/tooltip/refseqGeneTooltipHandler.d.ts +1 -1
  118. package/dist/src/tooltip/refseqGeneTooltipHandler.js +7 -1
  119. package/dist/src/tooltip/tooltipContext.d.ts +13 -0
  120. package/dist/src/tooltip/tooltipContext.d.ts.map +1 -0
  121. package/dist/src/tooltip/tooltipContext.js +543 -0
  122. package/dist/src/tooltip/tooltipContext.test.d.ts +2 -0
  123. package/dist/src/tooltip/tooltipContext.test.d.ts.map +1 -0
  124. package/dist/src/tooltip/tooltipHandler.d.ts +40 -1
  125. package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -1
  126. package/dist/src/tooltip/tooltipHandler.ts +62 -1
  127. package/dist/src/types/encoder.d.ts +1 -1
  128. package/dist/src/utils/inputBinding.d.ts +10 -2
  129. package/dist/src/utils/inputBinding.d.ts.map +1 -1
  130. package/dist/src/utils/inputBinding.js +12 -3
  131. package/dist/src/view/flowBuilder.d.ts.map +1 -1
  132. package/dist/src/view/flowBuilder.js +12 -3
  133. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  134. package/dist/src/view/gridView/gridChild.js +8 -3
  135. package/dist/src/view/gridView/selectionRect.d.ts +6 -10
  136. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
  137. package/dist/src/view/gridView/selectionRect.js +3 -20
  138. package/dist/src/view/layerView.d.ts.map +1 -1
  139. package/dist/src/view/layerView.js +4 -2
  140. package/dist/src/view/multiscale.d.ts +35 -0
  141. package/dist/src/view/multiscale.d.ts.map +1 -0
  142. package/dist/src/view/multiscale.js +233 -0
  143. package/dist/src/view/multiscale.test.d.ts +2 -0
  144. package/dist/src/view/multiscale.test.d.ts.map +1 -0
  145. package/dist/src/view/unitView.d.ts.map +1 -1
  146. package/dist/src/view/unitView.js +10 -4
  147. package/dist/src/view/view.d.ts +5 -4
  148. package/dist/src/view/view.d.ts.map +1 -1
  149. package/dist/src/view/view.js +205 -28
  150. package/dist/src/view/viewFactory.d.ts +0 -12
  151. package/dist/src/view/viewFactory.d.ts.map +1 -1
  152. package/dist/src/view/viewFactory.js +35 -24
  153. package/dist/src/view/viewParamRuntime.test.d.ts +2 -0
  154. package/dist/src/view/viewParamRuntime.test.d.ts.map +1 -0
  155. package/dist/src/view/viewSelectors.d.ts.map +1 -1
  156. package/dist/src/view/viewSelectors.js +8 -5
  157. package/package.json +3 -3
  158. package/dist/src/spec/sampleView.d.ts +0 -197
  159. package/dist/src/view/paramMediator.d.ts +0 -168
  160. package/dist/src/view/paramMediator.d.ts.map +0 -1
  161. package/dist/src/view/paramMediator.js +0 -545
  162. package/dist/src/view/paramMediator.test.d.ts +0 -2
  163. package/dist/src/view/paramMediator.test.d.ts.map +0 -1
@@ -9,14 +9,15 @@ import {
9
9
  initPropertyCache,
10
10
  invalidatePrefix,
11
11
  } from "../utils/propertyCacher.js";
12
- import { isNumber, isString, span } from "vega-util";
12
+ import { isArray, isNumber, isString, span } from "vega-util";
13
13
  import { scaleLog } from "d3-scale";
14
14
  import { isFieldDef, getPrimaryChannel } from "../encoder/encoder.js";
15
15
  import { concatUrl } from "../utils/url.js";
16
16
  import { isDiscrete, bandSpace } from "vega-scale";
17
17
  import { peek } from "../utils/arrayUtils.js";
18
18
  import ViewError from "./viewError.js";
19
- import ParamMediator, { isExprRef } from "./paramMediator.js";
19
+ import ViewParamRuntime from "../paramRuntime/viewParamRuntime.js";
20
+ import { isExprRef } from "../paramRuntime/paramUtils.js";
20
21
  import { InternMap } from "internmap";
21
22
  import { endWithSlash } from "../utils/addBaseUrl.js";
22
23
 
@@ -160,15 +161,15 @@ export default class View {
160
161
  */
161
162
  this.needsAxes = { x: false, y: false };
162
163
 
163
- /** @type {ParamMediator} */
164
- this.paramMediator = new ParamMediator(
165
- () => this.dataParent?.paramMediator
164
+ /** @type {ViewParamRuntime} */
165
+ this.paramRuntime = new ViewParamRuntime(
166
+ () => this.dataParent?.paramRuntime
166
167
  );
167
168
 
168
169
  if (spec.params) {
169
170
  for (const param of spec.params) {
170
171
  // TODO: If interval selection, validate `encodings` or provides defaults
171
- this.paramMediator.registerParam(param);
172
+ this.paramRuntime.registerParam(param);
172
173
  }
173
174
  }
174
175
 
@@ -178,9 +179,9 @@ export default class View {
178
179
  // doesn't make much sense, but it's used in the App's SampleView
179
180
  // to set the height to sample facets' height.
180
181
  const allocateIfFree = (/** @type {string} */ name) =>
181
- this.paramMediator.findMediatorForParam(name)
182
+ this.paramRuntime.findRuntimeForParam(name)
182
183
  ? undefined
183
- : this.paramMediator.allocateSetter(name, 0);
184
+ : this.paramRuntime.allocateSetter(name, 0);
184
185
  this.#heightSetter = allocateIfFree("height");
185
186
  this.#widthSetter = allocateIfFree("width");
186
187
  }
@@ -510,6 +511,7 @@ export default class View {
510
511
  *
511
512
  * @param {string} type
512
513
  * @param {function(BroadcastMessage):void} handler
514
+ * @returns {() => void}
513
515
  */
514
516
  _addBroadcastHandler(type, handler) {
515
517
  let handlers = this.#broadcastHandlers[type];
@@ -518,6 +520,18 @@ export default class View {
518
520
  this.#broadcastHandlers[type] = handlers;
519
521
  }
520
522
  handlers.push(handler);
523
+
524
+ return () => {
525
+ const currentHandlers = this.#broadcastHandlers[type];
526
+ if (!currentHandlers) {
527
+ return;
528
+ }
529
+
530
+ const index = currentHandlers.indexOf(handler);
531
+ if (index >= 0) {
532
+ currentHandlers.splice(index, 1);
533
+ }
534
+ };
521
535
  }
522
536
 
523
537
  /**
@@ -642,6 +656,8 @@ export default class View {
642
656
  this.context.dataFlow.removeDataSource(handle.dataSource);
643
657
  }
644
658
 
659
+ this.paramRuntime.dispose();
660
+
645
661
  this.context.dataFlow.loadingStatusRegistry.delete(this);
646
662
 
647
663
  this.flowHandle = undefined;
@@ -875,7 +891,7 @@ export default class View {
875
891
  return isString(title)
876
892
  ? title
877
893
  : isExprRef(title.text)
878
- ? this.paramMediator.evaluateAndGet(title.text.expr)
894
+ ? this.paramRuntime.evaluateAndGet(title.text.expr)
879
895
  : title.text;
880
896
  }
881
897
  }
@@ -940,6 +956,16 @@ function isDynamicOpacity(opacity) {
940
956
  }
941
957
 
942
958
  /**
959
+ * Builds the effective opacity function for a view.
960
+ *
961
+ * The resulting function multiplies parent opacity with one of:
962
+ * 1. constant opacity (`number`)
963
+ * 2. zoom-driven dynamic opacity (`DynamicOpacity`) that maps the current
964
+ * units-per-pixel metric through a log interpolation
965
+ * 3. expression-driven opacity (`ExprRef`) that is evaluated reactively
966
+ *
967
+ * Dynamic opacity supports scale selection via `channel` (`x`, `y`, or
968
+ * `"auto"`), where `"auto"` averages available x/y metrics.
943
969
  *
944
970
  * @param {View} view
945
971
  * @returns {function(number):number}
@@ -951,46 +977,197 @@ function createViewOpacityFunction(view) {
951
977
  if (isNumber(opacityDef)) {
952
978
  return (parentOpacity) => parentOpacity * opacityDef;
953
979
  } else if (isDynamicOpacity(opacityDef)) {
954
- /** @type {(channel: import("../spec/channel.js").ChannelWithScale) => any} */
955
- const getScale = (channel) => {
956
- const scale = view.getScaleResolution(channel)?.getScale();
980
+ /**
981
+ * @param {import("../spec/channel.js").PrimaryPositionalChannel} channel
982
+ */
983
+ const getScaleContext = (channel) => {
984
+ const scaleResolution = view.getScaleResolution(channel);
985
+ const scale = scaleResolution?.getScale();
957
986
  // Only works on linear scales
958
987
  if (["linear", "index", "locus"].includes(scale?.type)) {
959
- return scale;
988
+ return { scale, scaleResolution };
960
989
  }
961
990
  };
962
991
 
963
- const scale = opacityDef.channel
964
- ? getScale(opacityDef.channel)
965
- : (getScale("x") ?? getScale("y"));
992
+ const opacityValues = asFiniteNumberArray(
993
+ opacityDef.values,
994
+ "opacity.values",
995
+ view
996
+ );
966
997
 
967
- if (!scale) {
998
+ if (!isArray(opacityDef.unitsPerPixel)) {
968
999
  throw new ViewError(
969
- "Cannot find a resolved quantitative scale for dynamic opacity!",
1000
+ '"opacity.unitsPerPixel" must be an array.',
970
1001
  view
971
1002
  );
972
1003
  }
973
1004
 
974
- const interpolate = scaleLog()
975
- .domain(opacityDef.unitsPerPixel)
976
- .range(opacityDef.values)
977
- .clamp(true);
1005
+ /** @type {function(number): number} */
1006
+ let interpolate = () => 1;
978
1007
 
979
- return (parentOpacity) => {
980
- const rangeSpan = 1000; //TODO: span(scale.range());
981
- const unitsPerPixel = span(scale.domain()) / rangeSpan;
1008
+ /** @type {(() => number)[]} */
1009
+ let stopReaders = [];
982
1010
 
983
- return interpolate(unitsPerPixel) * parentOpacity;
1011
+ const updateInterpolator = () => {
1012
+ const unitsPerPixel = asFiniteNumberArray(
1013
+ stopReaders.map((readStop) => readStop()),
1014
+ "opacity.unitsPerPixel",
1015
+ view
1016
+ );
1017
+
1018
+ validateDynamicOpacityStops(unitsPerPixel, opacityValues, view);
1019
+
1020
+ const scale = scaleLog()
1021
+ .domain(unitsPerPixel)
1022
+ .range(opacityValues)
1023
+ .clamp(true);
1024
+
1025
+ interpolate = (value) => scale(value);
1026
+ };
1027
+
1028
+ stopReaders = opacityDef.unitsPerPixel.map((stop) => {
1029
+ if (isExprRef(stop)) {
1030
+ const fn = view.paramRuntime.watchExpression(
1031
+ stop.expr,
1032
+ () => {
1033
+ updateInterpolator();
1034
+ view.context.animator.requestRender();
1035
+ }
1036
+ );
1037
+ return () => fn(null);
1038
+ } else {
1039
+ return () => stop;
1040
+ }
1041
+ });
1042
+
1043
+ updateInterpolator();
1044
+
1045
+ /**
1046
+ * @param {{ scale: any, scaleResolution: import("../scales/scaleResolution.js").default }} scaleContext
1047
+ */
1048
+ const getUnitsPerPixel = (scaleContext) => {
1049
+ const axisLength = scaleContext.scaleResolution.getAxisLength();
1050
+ const rangeSpan = axisLength || 1000;
1051
+ return span(scaleContext.scale.domain()) / rangeSpan;
1052
+ };
1053
+
1054
+ /** @type {() => number} */
1055
+ let getMetric;
1056
+
1057
+ if (opacityDef.channel === "auto") {
1058
+ const xScale = getScaleContext("x");
1059
+ const yScale = getScaleContext("y");
1060
+
1061
+ if (xScale && yScale) {
1062
+ getMetric = () =>
1063
+ (getUnitsPerPixel(xScale) + getUnitsPerPixel(yScale)) /
1064
+ 2;
1065
+ } else if (xScale) {
1066
+ getMetric = () => getUnitsPerPixel(xScale);
1067
+ } else if (yScale) {
1068
+ getMetric = () => getUnitsPerPixel(yScale);
1069
+ } else {
1070
+ throw new ViewError(
1071
+ "Cannot find a resolved quantitative x or y scale for dynamic opacity!",
1072
+ view
1073
+ );
1074
+ }
1075
+ } else {
1076
+ const scaleContext = opacityDef.channel
1077
+ ? getScaleContext(opacityDef.channel)
1078
+ : (getScaleContext("x") ?? getScaleContext("y"));
1079
+
1080
+ if (!scaleContext) {
1081
+ throw new ViewError(
1082
+ "Cannot find a resolved quantitative scale for dynamic opacity!",
1083
+ view
1084
+ );
1085
+ }
1086
+
1087
+ getMetric = () => getUnitsPerPixel(scaleContext);
1088
+ }
1089
+
1090
+ return (parentOpacity) => {
1091
+ return interpolate(getMetric()) * parentOpacity;
984
1092
  };
985
1093
  } else if (isExprRef(opacityDef)) {
986
- const fn = view.paramMediator.createExpression(opacityDef.expr);
987
- fn.addListener(() => view.context.animator.requestRender());
1094
+ const fn = view.paramRuntime.watchExpression(opacityDef.expr, () =>
1095
+ view.context.animator.requestRender()
1096
+ );
988
1097
  return (parentOpacity) => fn(null) * parentOpacity;
989
1098
  }
990
1099
  }
991
1100
  return (parentOpacity) => parentOpacity;
992
1101
  }
993
1102
 
1103
+ /**
1104
+ * @param {number[]} unitsPerPixel
1105
+ * @param {number[]} values
1106
+ * @param {View} view
1107
+ */
1108
+ function validateDynamicOpacityStops(unitsPerPixel, values, view) {
1109
+ if (!unitsPerPixel.length) {
1110
+ throw new ViewError(
1111
+ '"opacity.unitsPerPixel" must contain at least one stop.',
1112
+ view
1113
+ );
1114
+ }
1115
+
1116
+ if (unitsPerPixel.length !== values.length) {
1117
+ throw new ViewError(
1118
+ '"opacity.unitsPerPixel" and "opacity.values" must have the same length.',
1119
+ view
1120
+ );
1121
+ }
1122
+
1123
+ unitsPerPixel.forEach((value, index) => {
1124
+ if (value <= 0) {
1125
+ throw new ViewError(
1126
+ "Invalid opacity.unitsPerPixel value at index " +
1127
+ index +
1128
+ ". Stop values must be positive.",
1129
+ view
1130
+ );
1131
+ }
1132
+ });
1133
+
1134
+ for (let i = 1; i < unitsPerPixel.length; i++) {
1135
+ if (unitsPerPixel[i - 1] <= unitsPerPixel[i]) {
1136
+ throw new ViewError(
1137
+ '"opacity.unitsPerPixel" must be strictly decreasing.',
1138
+ view
1139
+ );
1140
+ }
1141
+ }
1142
+ }
1143
+
1144
+ /**
1145
+ * @param {unknown} value
1146
+ * @param {string} label
1147
+ * @param {View} view
1148
+ * @returns {number[]}
1149
+ */
1150
+ function asFiniteNumberArray(value, label, view) {
1151
+ if (!isArray(value)) {
1152
+ throw new ViewError('"' + label + '" must evaluate to an array.', view);
1153
+ }
1154
+
1155
+ return value.map((item, index) => {
1156
+ if (!isNumber(item) || !Number.isFinite(item)) {
1157
+ throw new ViewError(
1158
+ "Invalid " +
1159
+ label +
1160
+ " value at index " +
1161
+ index +
1162
+ ". Expected a finite number.",
1163
+ view
1164
+ );
1165
+ }
1166
+
1167
+ return item;
1168
+ });
1169
+ }
1170
+
994
1171
  /**
995
1172
  *
996
1173
  * @param {any} size
@@ -16,12 +16,6 @@ export function isLayerSpec(spec: import("../spec/view.js").ViewSpec): spec is i
16
16
  * @returns {spec is LayerSpec}
17
17
  */
18
18
  export function isFacetSpec(spec: import("../spec/view.js").ViewSpec): spec is import("../spec/view.js").LayerSpec;
19
- /**
20
- *
21
- * @param {ViewSpec} spec
22
- * @returns {spec is import("../spec/view.js").AggregateSamplesSpec}
23
- */
24
- export function isAggregateSamplesSpec(spec: import("../spec/view.js").ViewSpec): spec is import("../spec/view.js").AggregateSamplesSpec;
25
19
  /**
26
20
  *
27
21
  * @param {object} spec
@@ -46,12 +40,6 @@ export function isHConcatSpec(spec: import("../spec/view.js").ViewSpec): spec is
46
40
  * @returns {spec is ConcatSpec}
47
41
  */
48
42
  export function isConcatSpec(spec: import("../spec/view.js").ViewSpec): spec is import("../spec/view.js").ConcatSpec;
49
- /**
50
- *
51
- * @param {ViewSpec} spec
52
- * @returns {spec is SampleSpec}
53
- */
54
- export function isSampleSpec(spec: import("../spec/view.js").ViewSpec): spec is import("../spec/sampleView.js").SampleSpec;
55
43
  export const VIEW_ROOT_NAME: "viewRoot";
56
44
  /**
57
45
  * @typedef {object} ViewFactoryOptions
@@ -1 +1 @@
1
- {"version":3,"file":"viewFactory.d.ts","sourceRoot":"","sources":["../../../src/view/viewFactory.js"],"names":[],"mappings":"AA+SA;;;;GAIG;AACH,sEAFa,IAAI,sCAAY,CAI5B;AAED;;;;GAIG;AACH,uEAFa,IAAI,uCAAa,CAI7B;AAED;;;;GAIG;AACH,uEAFa,IAAI,uCAAa,CAS7B;AAED;;;;GAIG;AACH,kFAFa,IAAI,IAAI,OAAO,iBAAiB,EAAE,oBAAoB,CAQlE;AAED;;;;GAIG;AACH,mCAHW,MAAM,GACJ,IAAI,IAAI,OAAO,iBAAiB,EAAE,UAAU,CAIxD;AAED;;;;GAIG;AACH,yEAFa,IAAI,yCAAe,CAI/B;AAED;;;;GAIG;AACH,yEAFa,IAAI,IAAI,WAAW,CAI/B;AAED;;;;GAIG;AACH,wEAFa,IAAI,wCAAc,CAI9B;AAED;;;;GAIG;AACH,wEAFa,IAAI,8CAAc,CAS9B;AA3XD,6BAA8B,UAAU,CAAC;AAEzC;;;;GAIG;AAEH;;GAEG;AACH;IAiBI;;OAEG;IACH,sBAFW,kBAAkB,EAoC5B;IAjCG,2CAA2C;IAC3C,SADW,QAAQ,CAAC,kBAAkB,CAAC,CAKtC;IA8BL;;;OAGG;IACH,qEAlDiC,OAAO,yHAC2B,OAAO,oBAAoB,EAAE,OAAO,eAAe,OAAO,WAAW,EAAE,OAAO,gBAAgB,MAAM,KAAK,IAAI,QAmD/K;IAED;;;;;;OAMG;IACH,wHAJW,OAAO,oBAAoB,EAAE,OAAO,eACpC,OAAO,WAAW,EAAE,OAAO,gBAC3B,MAAM,QAmBhB;IAED;;;;OAIG;IACH,sDAFa,IAAI,sCAAY,CAU5B;IAED;;;;;;;;;;OAUG;IACH,yBAPW,qCAAW,OAAO,iBAAiB,EAAE,UAAU,qEAE/C,OAAO,oBAAoB,EAAE,OAAO,eACpC,OAAO,WAAW,EAAE,OAAO,gBAC3B,MAAM,cACN,CAAC,IAAI,oCAAU,KAAK,IAAI,iBAgGlC;;CACJ;;;;;kBA1Na,OAAO;eACP,OAAO;;iBArBJ,WAAW"}
1
+ {"version":3,"file":"viewFactory.d.ts","sourceRoot":"","sources":["../../../src/view/viewFactory.js"],"names":[],"mappings":"AAwUA;;;;GAIG;AACH,sEAFa,IAAI,sCAAY,CAI5B;AAED;;;;GAIG;AACH,uEAFa,IAAI,uCAAa,CAI7B;AAED;;;;GAIG;AACH,uEAFa,IAAI,uCAAa,CAS7B;AAED;;;;GAIG;AACH,mCAHW,MAAM,GACJ,IAAI,IAAI,OAAO,iBAAiB,EAAE,UAAU,CAIxD;AAED;;;;GAIG;AACH,yEAFa,IAAI,yCAAe,CAI/B;AAED;;;;GAIG;AACH,yEAFa,IAAI,IAAI,WAAW,CAI/B;AAED;;;;GAIG;AACH,wEAFa,IAAI,wCAAc,CAI9B;AAxXD,6BAA8B,UAAU,CAAC;AAEzC;;;;GAIG;AAEH;;GAEG;AACH;IAiBI;;OAEG;IACH,sBAFW,kBAAkB,EAiD5B;IA9CG,2CAA2C;IAC3C,SADW,QAAQ,CAAC,kBAAkB,CAAC,CAKtC;IA2CL;;;OAGG;IACH,qEA/DiC,OAAO,yHAC2B,OAAO,oBAAoB,EAAE,OAAO,eAAe,OAAO,WAAW,EAAE,OAAO,gBAAgB,MAAM,KAAK,IAAI,QAgE/K;IAED;;;;;;OAMG;IACH,wHAJW,OAAO,oBAAoB,EAAE,OAAO,eACpC,OAAO,WAAW,EAAE,OAAO,gBAC3B,MAAM,QAyBhB;IAED;;;;OAIG;IACH,sDAFa,IAAI,sCAAY,CAU5B;IAED;;;;;;;;;;OAUG;IACH,yBAPW,qCAAW,OAAO,iBAAiB,EAAE,UAAU,qEAE/C,OAAO,oBAAoB,EAAE,OAAO,eACpC,OAAO,WAAW,EAAE,OAAO,gBAC3B,MAAM,cACN,CAAC,IAAI,oCAAU,KAAK,IAAI,iBAiGlC;;CACJ;;;;;kBA9Oa,OAAO;eACP,OAAO;;iBAtBJ,WAAW"}
@@ -8,12 +8,13 @@ import { isArray, isObject, isString } from "vega-util";
8
8
  import { loadExternalViewSpec } from "./viewUtils.js";
9
9
  import ContainerView from "./containerView.js";
10
10
  import ViewError from "./viewError.js";
11
- import { isSelectionParameter } from "./paramMediator.js";
11
+ import { isSelectionParameter } from "../paramRuntime/paramUtils.js";
12
12
  import { asSelectionConfig } from "../selection/selection.js";
13
13
  import {
14
14
  markViewAsNonAddressable,
15
15
  registerImportInstance,
16
16
  } from "./viewSelectors.js";
17
+ import { isMultiscaleSpec, normalizeMultiscaleSpec } from "./multiscale.js";
17
18
 
18
19
  export const VIEW_ROOT_NAME = "viewRoot";
19
20
 
@@ -32,9 +33,9 @@ export class ViewFactory {
32
33
  * @typedef {import("../spec/view.js").UnitSpec} UnitSpec
33
34
  * @typedef {import("../spec/view.js").ViewSpec} ViewSpec
34
35
  * @typedef {import("../spec/view.js").LayerSpec} LayerSpec
36
+ * @typedef {import("../spec/view.js").MultiscaleSpec} MultiscaleSpec
35
37
  * @typedef {import("../spec/view.js").VConcatSpec} VConcatSpec
36
38
  * @typedef {import("../spec/view.js").ConcatSpec} ConcatSpec
37
- * @typedef {import("../spec/sampleView.js").SampleSpec} SampleSpec
38
39
  *
39
40
  * @typedef {(spec: ViewSpec) => boolean} SpecGuard
40
41
  * @typedef {(spec: ViewSpec, context: ViewContext, layoutParent?: import("./containerView.js").default, dataParent?: import("./view.js").default, defaultName?: string) => View} Factory
@@ -69,17 +70,30 @@ export class ViewFactory {
69
70
  );
70
71
 
71
72
  this.addViewType(isLayerSpec, makeDefaultFactory(LayerView));
73
+ this.addViewType(
74
+ isMultiscaleSpec,
75
+ /** @type {Factory} */ (
76
+ (spec, context, layoutParent, dataParent, defaultName) =>
77
+ /** @type {View} */ (
78
+ new LayerView(
79
+ normalizeMultiscaleSpec(
80
+ /** @type {import("../spec/view.js").MultiscaleSpec} */ (
81
+ spec
82
+ )
83
+ ),
84
+ context,
85
+ layoutParent,
86
+ dataParent,
87
+ defaultName
88
+ )
89
+ )
90
+ )
91
+ );
72
92
  this.addViewType(isUnitSpec, makeDefaultFactory(UnitView));
73
93
  this.addViewType(isVConcatSpec, makeDefaultFactory(ConcatView));
74
94
  this.addViewType(isHConcatSpec, makeDefaultFactory(ConcatView));
75
95
  this.addViewType(isConcatSpec, makeDefaultFactory(ConcatView));
76
96
  //this.addViewType(isFacetSpec, makeDefaultFactory(FacetView));
77
-
78
- this.addViewType(isSampleSpec, () => {
79
- throw new Error(
80
- "SampleView is not supported by the @genome-spy/core package. Use @genome-spy/app instead!"
81
- );
82
- });
83
97
  }
84
98
 
85
99
  /**
@@ -110,6 +124,12 @@ export class ViewFactory {
110
124
  }
111
125
  }
112
126
 
127
+ if (isSampleSpec(spec)) {
128
+ throw new Error(
129
+ "SampleView is not supported by the @genome-spy/core package. Use @genome-spy/app instead!"
130
+ );
131
+ }
132
+
113
133
  throw new Error(
114
134
  "Invalid spec, cannot figure out the view type from the properties: " +
115
135
  JSON.stringify([...Object.keys(spec)])
@@ -203,6 +223,7 @@ export class ViewFactory {
203
223
  this.options.wrapRoot &&
204
224
  (isUnitSpec(viewSpec) ||
205
225
  isLayerSpec(viewSpec) ||
226
+ isMultiscaleSpec(viewSpec) ||
206
227
  hasIntervalSelection(viewSpec)) &&
207
228
  defaultName === VIEW_ROOT_NAME
208
229
  ) {
@@ -268,6 +289,10 @@ function applyParamsToImportedSpec(importedSpec, importSpec) {
268
289
  importedSpec.name = importSpec.name;
269
290
  }
270
291
 
292
+ if (importSpec.visible != null) {
293
+ importedSpec.visible = importSpec.visible;
294
+ }
295
+
271
296
  const params = isArray(importSpec.params)
272
297
  ? importSpec.params
273
298
  : isObject(importSpec.params)
@@ -333,19 +358,6 @@ export function isFacetSpec(spec) {
333
358
  );
334
359
  }
335
360
 
336
- /**
337
- *
338
- * @param {ViewSpec} spec
339
- * @returns {spec is import("../spec/view.js").AggregateSamplesSpec}
340
- */
341
- export function isAggregateSamplesSpec(spec) {
342
- return (
343
- spec &&
344
- (isUnitSpec(spec) || isLayerSpec(spec)) &&
345
- "aggregateSamples" in spec
346
- );
347
- }
348
-
349
361
  /**
350
362
  *
351
363
  * @param {object} spec
@@ -384,10 +396,9 @@ export function isConcatSpec(spec) {
384
396
 
385
397
  /**
386
398
  *
387
- * @param {ViewSpec} spec
388
- * @returns {spec is SampleSpec}
399
+ * @param {object} spec
389
400
  */
390
- export function isSampleSpec(spec) {
401
+ function isSampleSpec(spec) {
391
402
  return (
392
403
  "samples" in spec &&
393
404
  isObject(spec.samples) &&
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=viewParamRuntime.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewParamRuntime.test.d.ts","sourceRoot":"","sources":["../../../src/view/viewParamRuntime.test.js"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"viewSelectors.d.ts","sourceRoot":"","sources":["../../../src/view/viewSelectors.js"],"names":[],"mappings":"AA8BA;;;;;GAKG;AACH,6CAHW,OAAO,WAAW,EAAE,OAAO,aAC3B,MAAM,GAAG,IAAI,QAQvB;AAED;;;;;GAKG;AACH,yCAHW,OAAO,WAAW,EAAE,OAAO,GACzB,eAAe,GAAG,SAAS,CAIvC;AAED;;;;;GAKG;AACH,+CAHW,OAAO,WAAW,EAAE,OAAO,YAC3B,kBAAkB,QAM5B;AAED;;;;;GAKG;AACH,wCAHW,OAAO,WAAW,EAAE,OAAO,GACzB,MAAM,EAAE,CAgBpB;AAED;;;;;GAKG;AACH,sCAHW,OAAO,WAAW,EAAE,OAAO,GACzB,YAAY,CAYxB;AAED;;;;;;GAMG;AACH,uCAJW,OAAO,WAAW,EAAE,OAAO,aAC3B,MAAM,GACJ,aAAa,CAazB;AAED;;;;;GAKG;AACH,+CAHW,aAAa,GACX,MAAM,CAQlB;AAED;;;;;GAKG;AACH,0CAHW,OAAO,WAAW,EAAE,OAAO,GACzB,OAAO,WAAW,EAAE,OAAO,EAAE,CAWzC;AAED;;;;;GAKG;AACH,4CAHW,OAAO,WAAW,EAAE,OAAO,WAC3B,OAAO,WAAW,EAAE,OAAO,QAerC;AAED;;;;;;GAMG;AACH,0CAJW,OAAO,WAAW,EAAE,OAAO,YAC3B,YAAY,GACV,OAAO,WAAW,EAAE,OAAO,GAAG,SAAS,CAmCnD;AAED;;;;;;GAMG;AACH,2CAJW,OAAO,WAAW,EAAE,OAAO,YAC3B,aAAa,GACX,aAAa,GAAG,SAAS,CAuCrC;AAED;;;;;GAKG;AACH,8CAHW,OAAO,WAAW,EAAE,OAAO,WAC3B,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,QAyBjD;AAED;;;;;GAKG;AACH,4CAHW,OAAO,WAAW,EAAE,OAAO,GACzB,sBAAsB,EAAE,CAOpC;AAED;;;;;GAKG;AACH,kDAHW,OAAO,WAAW,EAAE,OAAO,GACzB,uBAAuB,EAAE,CAcrC;AArUD;;;;;;GAMG;AAEH;;;;;;;;;GASG;AAEH,wCAAyC,IAAI,CAAC;2BAVjC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;4BACjC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;qCAClC;IAAE,IAAI,EAAE,OAAO,WAAW,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,sBAAsB,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE;sCAC/G;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE;8BACpC;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;kCACvB,SAAS,GAAG,gBAAgB;iCAC5B;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE;4BACzB;IAAE,IAAI,EAAE,OAAO,WAAW,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,sBAAsB,EAAE,SAAS,CAAA;CAAE"}
1
+ {"version":3,"file":"viewSelectors.d.ts","sourceRoot":"","sources":["../../../src/view/viewSelectors.js"],"names":[],"mappings":"AAiCA;;;;;GAKG;AACH,6CAHW,OAAO,WAAW,EAAE,OAAO,aAC3B,MAAM,GAAG,IAAI,QAQvB;AAED;;;;;GAKG;AACH,yCAHW,OAAO,WAAW,EAAE,OAAO,GACzB,eAAe,GAAG,SAAS,CAIvC;AAED;;;;;GAKG;AACH,+CAHW,OAAO,WAAW,EAAE,OAAO,YAC3B,kBAAkB,QAM5B;AAED;;;;;GAKG;AACH,wCAHW,OAAO,WAAW,EAAE,OAAO,GACzB,MAAM,EAAE,CAgBpB;AAED;;;;;GAKG;AACH,sCAHW,OAAO,WAAW,EAAE,OAAO,GACzB,YAAY,CAYxB;AAED;;;;;;GAMG;AACH,uCAJW,OAAO,WAAW,EAAE,OAAO,aAC3B,MAAM,GACJ,aAAa,CAazB;AAED;;;;;GAKG;AACH,+CAHW,aAAa,GACX,MAAM,CAQlB;AAED;;;;;GAKG;AACH,0CAHW,OAAO,WAAW,EAAE,OAAO,GACzB,OAAO,WAAW,EAAE,OAAO,EAAE,CAWzC;AAED;;;;;GAKG;AACH,4CAHW,OAAO,WAAW,EAAE,OAAO,WAC3B,OAAO,WAAW,EAAE,OAAO,QAerC;AAED;;;;;;GAMG;AACH,0CAJW,OAAO,WAAW,EAAE,OAAO,YAC3B,YAAY,GACV,OAAO,WAAW,EAAE,OAAO,GAAG,SAAS,CAmCnD;AAED;;;;;;GAMG;AACH,2CAJW,OAAO,WAAW,EAAE,OAAO,YAC3B,aAAa,GACX,aAAa,GAAG,SAAS,CAuCrC;AAED;;;;;GAKG;AACH,8CAHW,OAAO,WAAW,EAAE,OAAO,WAC3B,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,QAyBjD;AAED;;;;;GAKG;AACH,4CAHW,OAAO,WAAW,EAAE,OAAO,GACzB,sBAAsB,EAAE,CAOpC;AAED;;;;;GAKG;AACH,kDAHW,OAAO,WAAW,EAAE,OAAO,GACzB,uBAAuB,EAAE,CAcrC;AArUD;;;;;;GAMG;AAEH;;;;;;;;;GASG;AAEH,wCAAyC,IAAI,CAAC;2BAVjC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;4BACjC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;qCAClC;IAAE,IAAI,EAAE,OAAO,WAAW,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,sBAAsB,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE;sCAC/G;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE;8BACpC;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE;kCACvB,SAAS,GAAG,gBAAgB;iCAC5B;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE;4BACzB;IAAE,IAAI,EAAE,OAAO,WAAW,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,sBAAsB,EAAE,SAAS,CAAA;CAAE"}
@@ -1,5 +1,8 @@
1
1
  import { VISIT_SKIP, VISIT_STOP } from "./view.js";
2
- import { isSelectionParameter, isVariableParameter } from "./paramMediator.js";
2
+ import {
3
+ isSelectionParameter,
4
+ isVariableParameter,
5
+ } from "../paramRuntime/paramUtils.js";
3
6
 
4
7
  /**
5
8
  * Selectors identify views and parameters in a way that stays stable when the
@@ -237,7 +240,7 @@ export function resolveParamSelector(root, selector) {
237
240
  const matches = [];
238
241
 
239
242
  visitViewsInScope(scopeRoot, (view) => {
240
- for (const [name, param] of view.paramMediator.paramConfigs) {
243
+ for (const [name, param] of view.paramRuntime.paramConfigs) {
241
244
  if (name !== selector.param) {
242
245
  continue;
243
246
  }
@@ -281,7 +284,7 @@ export function visitBookmarkableParams(root, visitor) {
281
284
  return;
282
285
  }
283
286
 
284
- for (const [name, param] of view.paramMediator.paramConfigs) {
287
+ for (const [name, param] of view.paramRuntime.paramConfigs) {
285
288
  if (!isBookmarkableParam(param)) {
286
289
  continue;
287
290
  }
@@ -530,7 +533,7 @@ function validateParamNamesInScope(scopeRoot, scope, issues) {
530
533
  const names = new Map();
531
534
 
532
535
  visitViewsInScope(scopeRoot, (view) => {
533
- for (const [name, param] of view.paramMediator.paramConfigs) {
536
+ for (const [name, param] of view.paramRuntime.paramConfigs) {
534
537
  if (!isBookmarkableParam(param)) {
535
538
  continue;
536
539
  }
@@ -672,7 +675,7 @@ function hasAddressableFeatures(root) {
672
675
  return VISIT_STOP;
673
676
  }
674
677
 
675
- for (const param of view.paramMediator.paramConfigs.values()) {
678
+ for (const param of view.paramRuntime.paramConfigs.values()) {
676
679
  if (isBookmarkableParam(param)) {
677
680
  found = true;
678
681
  return VISIT_STOP;
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "contributors": [],
9
9
  "license": "MIT",
10
- "version": "0.68.0",
10
+ "version": "0.69.0",
11
11
  "jsdelivr": "dist/bundle/index.js",
12
12
  "unpkg": "dist/bundle/index.js",
13
13
  "browser": "dist/bundle/index.js",
@@ -30,7 +30,7 @@
30
30
  "build": "rm -rf dist && mkdir -p dist && node scripts/build.mjs && vite build && npm run build:schema && npm run build:typings",
31
31
  "prepublishOnly": "npm run build",
32
32
  "test:tsc": "tsc -p tsconfig.json --noEmit",
33
- "build:schema": "mkdir -p dist && ts-json-schema-generator --path 'src/spec/*.ts' --type RootSpec > dist/schema.json",
33
+ "build:schema": "mkdir -p dist && ts-json-schema-generator --path 'src/spec/*.ts' --type CoreRootSpec > dist/schema.json",
34
34
  "build:typings": "tsc -p tsconfig.json --declaration --emitDeclarationOnly --declarationMap --outDir dist/src",
35
35
  "prepack": "node scripts/prepack.mjs",
36
36
  "postpack": "node scripts/postpack.mjs"
@@ -67,5 +67,5 @@
67
67
  "devDependencies": {
68
68
  "@types/long": "^4.0.1"
69
69
  },
70
- "gitHead": "74e4d56c67c8aa0da1884b16ff29185b16d418c3"
70
+ "gitHead": "bfb9bd98ceb875f90a458b876208b15b6c12c9f3"
71
71
  }