@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.
Files changed (124) hide show
  1. package/dist/bundle/index.es.js +5231 -4324
  2. package/dist/bundle/index.js +197 -85
  3. package/dist/schema.json +723 -104
  4. package/dist/src/data/collector.d.ts.map +1 -1
  5. package/dist/src/data/collector.js +4 -2
  6. package/dist/src/data/flowOptimizer.test.js +12 -3
  7. package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
  8. package/dist/src/data/sources/dataUtils.js +3 -1
  9. package/dist/src/data/sources/lazy/axisTickSource.d.ts +1 -1
  10. package/dist/src/data/sources/lazy/axisTickSource.d.ts.map +1 -1
  11. package/dist/src/data/sources/lazy/axisTickSource.js +2 -2
  12. package/dist/src/data/sources/lazy/bigBedSource.d.ts +1 -1
  13. package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
  14. package/dist/src/data/sources/lazy/bigBedSource.js +52 -20
  15. package/dist/src/data/sources/lazy/bigWigSource.d.ts +6 -1
  16. package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
  17. package/dist/src/data/sources/lazy/bigWigSource.js +33 -9
  18. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +1 -1
  19. package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
  20. package/dist/src/data/sources/lazy/singleAxisLazySource.js +1 -3
  21. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts +13 -14
  22. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  23. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +70 -48
  24. package/dist/src/data/sources/sequenceSource.d.ts.map +1 -1
  25. package/dist/src/data/sources/sequenceSource.js +14 -5
  26. package/dist/src/data/sources/sequenceSource.test.js +23 -5
  27. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  28. package/dist/src/data/sources/urlSource.js +15 -2
  29. package/dist/src/data/transforms/aggregate.d.ts.map +1 -1
  30. package/dist/src/data/transforms/aggregate.js +5 -2
  31. package/dist/src/data/transforms/filterScoredLabels.js +1 -1
  32. package/dist/src/encoder/encoder.d.ts +2 -4
  33. package/dist/src/encoder/encoder.d.ts.map +1 -1
  34. package/dist/src/encoder/encoder.js +20 -10
  35. package/dist/src/encoder/encoder.test.js +3 -0
  36. package/dist/src/genomeSpy.d.ts +8 -5
  37. package/dist/src/genomeSpy.d.ts.map +1 -1
  38. package/dist/src/genomeSpy.js +121 -42
  39. package/dist/src/gl/glslScaleGenerator.d.ts +23 -3
  40. package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
  41. package/dist/src/gl/glslScaleGenerator.js +137 -42
  42. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  43. package/dist/src/gl/webGLHelper.js +5 -7
  44. package/dist/src/index.d.ts +1 -1
  45. package/dist/src/index.d.ts.map +1 -1
  46. package/dist/src/index.js +1 -1
  47. package/dist/src/marks/link.common.glsl.js +2 -0
  48. package/dist/src/marks/link.d.ts.map +1 -1
  49. package/dist/src/marks/link.js +19 -9
  50. package/dist/src/marks/link.vertex.glsl.js +1 -1
  51. package/dist/src/marks/mark.d.ts +25 -20
  52. package/dist/src/marks/mark.d.ts.map +1 -1
  53. package/dist/src/marks/mark.js +234 -129
  54. package/dist/src/marks/point.common.glsl.js +1 -1
  55. package/dist/src/marks/point.d.ts +1 -4
  56. package/dist/src/marks/point.d.ts.map +1 -1
  57. package/dist/src/marks/point.js +31 -23
  58. package/dist/src/marks/point.vertex.glsl.js +1 -1
  59. package/dist/src/marks/rect.common.glsl.js +2 -0
  60. package/dist/src/marks/rect.d.ts.map +1 -1
  61. package/dist/src/marks/rect.js +12 -12
  62. package/dist/src/marks/rect.vertex.glsl.js +1 -1
  63. package/dist/src/marks/rule.common.glsl.js +1 -1
  64. package/dist/src/marks/rule.js +2 -2
  65. package/dist/src/marks/text.common.glsl.js +1 -1
  66. package/dist/src/marks/text.d.ts.map +1 -1
  67. package/dist/src/marks/text.js +17 -9
  68. package/dist/src/spec/channel.d.ts +4 -3
  69. package/dist/src/spec/data.d.ts +11 -10
  70. package/dist/src/spec/mark.d.ts +28 -46
  71. package/dist/src/spec/parameter.d.ts +127 -0
  72. package/dist/src/spec/root.d.ts +1 -0
  73. package/dist/src/spec/scale.d.ts +2 -1
  74. package/dist/src/spec/title.d.ts +5 -4
  75. package/dist/src/spec/view.d.ts +20 -5
  76. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  77. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  78. package/dist/src/styles/genome-spy.css.js +52 -5
  79. package/dist/src/styles/genome-spy.scss +63 -10
  80. package/dist/src/styles/update.sh +6 -0
  81. package/dist/src/tooltip/dataTooltipHandler.js +1 -1
  82. package/dist/src/tooltip/refseqGeneTooltipHandler.js +1 -1
  83. package/dist/src/tooltip/tooltipHandler.d.ts +1 -1
  84. package/dist/src/tooltip/tooltipHandler.d.ts.map +1 -1
  85. package/dist/src/tooltip/tooltipHandler.ts +1 -1
  86. package/dist/src/types/embedApi.d.ts +6 -0
  87. package/dist/src/types/scaleResolutionApi.d.ts +7 -3
  88. package/dist/src/types/viewContext.d.ts +2 -3
  89. package/dist/src/utils/debounce.d.ts +2 -2
  90. package/dist/src/utils/debounce.d.ts.map +1 -1
  91. package/dist/src/utils/debounce.js +5 -2
  92. package/dist/src/utils/expression.d.ts +2 -2
  93. package/dist/src/utils/expression.d.ts.map +1 -1
  94. package/dist/src/utils/expression.js +3 -3
  95. package/dist/src/utils/formatObject.d.ts +2 -2
  96. package/dist/src/utils/formatObject.d.ts.map +1 -1
  97. package/dist/src/utils/formatObject.js +2 -2
  98. package/dist/src/utils/inputBinding.d.ts +5 -0
  99. package/dist/src/utils/inputBinding.d.ts.map +1 -0
  100. package/dist/src/utils/inputBinding.js +115 -0
  101. package/dist/src/utils/ui/tooltip.js +1 -1
  102. package/dist/src/view/axisView.js +3 -3
  103. package/dist/src/view/paramMediator.d.ts +108 -0
  104. package/dist/src/view/paramMediator.d.ts.map +1 -0
  105. package/dist/src/view/paramMediator.js +337 -0
  106. package/dist/src/view/paramMediator.test.js +211 -0
  107. package/dist/src/view/scaleResolution.d.ts +8 -18
  108. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  109. package/dist/src/view/scaleResolution.js +225 -126
  110. package/dist/src/view/scaleResolution.test.js +7 -7
  111. package/dist/src/view/unitView.d.ts.map +1 -1
  112. package/dist/src/view/unitView.js +10 -3
  113. package/dist/src/view/view.d.ts +4 -1
  114. package/dist/src/view/view.d.ts.map +1 -1
  115. package/dist/src/view/view.js +21 -7
  116. package/dist/src/view/viewFactory.d.ts.map +1 -1
  117. package/dist/src/view/viewFactory.js +45 -0
  118. package/dist/src/view/viewUtils.d.ts +5 -1
  119. package/dist/src/view/viewUtils.d.ts.map +1 -1
  120. package/dist/src/view/viewUtils.js +9 -4
  121. package/package.json +16 -17
  122. package/dist/src/paramBroker.d.ts +0 -30
  123. package/dist/src/paramBroker.d.ts.map +0 -1
  124. package/dist/src/paramBroker.js +0 -102
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  import { Align, Baseline, FontStyle, FontWeight } from "./font.js";
12
+ import { ExprRef } from "./parameter.js";
12
13
 
13
14
  export type TitleOrient = "none" | "left" | "right" | "top" | "bottom";
14
15
  export type TitleAnchor = null | "start" | "middle" | "end";
@@ -18,7 +19,7 @@ export interface Title {
18
19
  /**
19
20
  * The title text.
20
21
  */
21
- text: string;
22
+ text: string | ExprRef;
22
23
 
23
24
  /**
24
25
  * A mark style property to apply to the title text mark. If not specified, a default style of `"group-title"` is applied.
@@ -54,7 +55,7 @@ export interface Title {
54
55
  /**
55
56
  * Angle in degrees of title and subtitle text.
56
57
  */
57
- angle?: number;
58
+ angle?: number | ExprRef;
58
59
 
59
60
  /**
60
61
  * Vertical text baseline for title and subtitle text. One of `"alphabetic"` (default), `"top"`, `"middle"`, or `"bottom"`.
@@ -75,7 +76,7 @@ export interface Title {
75
76
  /**
76
77
  * Text color for title text.
77
78
  */
78
- color?: string;
79
+ color?: string | ExprRef;
79
80
 
80
81
  /**
81
82
  * Font name for title text.
@@ -87,7 +88,7 @@ export interface Title {
87
88
  *
88
89
  * @minimum 0
89
90
  */
90
- fontSize?: number;
91
+ fontSize?: number | ExprRef;
91
92
 
92
93
  /**
93
94
  * Font style for title text.
@@ -7,14 +7,15 @@ import {
7
7
  PrimaryPositionalChannel,
8
8
  } from "./channel.js";
9
9
  import {
10
- ExprRef,
11
10
  FillAndStrokeProps,
12
11
  MarkConfigAndType,
13
12
  MarkType,
14
13
  RectProps,
15
14
  } from "./mark.js";
15
+ import { ExprRef } from "./parameter.js";
16
16
  import { Title } from "./title.js";
17
17
  import { SampleSpec } from "./sampleView.js";
18
+ import { VariableParameter } from "./parameter.js";
18
19
 
19
20
  export interface SizeDef {
20
21
  /** Size in pixels */
@@ -108,6 +109,11 @@ export interface ViewSpecBase extends ResolveSpec {
108
109
  */
109
110
  padding?: PaddingConfig;
110
111
 
112
+ /**
113
+ * Dynamic variables that parameterize a visualization.
114
+ */
115
+ params?: VariableParameter[];
116
+
111
117
  data?: Data;
112
118
  transform?: TransformParams[];
113
119
  encoding?: Encoding;
@@ -212,14 +218,23 @@ export type ViewSpec =
212
218
  | ConcatSpec
213
219
  | SampleSpec;
214
220
 
215
- export interface ImportConfig {
216
- name?: string;
221
+ export interface ImportParams {
217
222
  url?: string;
218
- params?: object;
223
+
224
+ /**
225
+ * Name for the imported view. Overrides the name defined in the imported spec.
226
+ */
227
+ name?: string;
228
+
229
+ /**
230
+ * Dynamic variables that parameterize a visualization. Parameters defined here
231
+ * override the parameters defined in the imported spec.
232
+ */
233
+ params?: VariableParameter[] | Record<string, any>;
219
234
  }
220
235
 
221
236
  export interface ImportSpec {
222
- import: ImportConfig;
237
+ import: ImportParams;
223
238
  }
224
239
 
225
240
  export interface ConcatBase extends ViewSpecBase {
@@ -1,3 +1,3 @@
1
1
  export default css;
2
- declare const css: ".genome-spy {\n font-family: system-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n position: relative;\n}\n.genome-spy canvas {\n transform: scale(1, 1);\n opacity: 1;\n transition: transform 0.6s, opacity 0.6s;\n}\n.genome-spy .loading-message {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-message .message {\n color: #666;\n opacity: 0;\n transition: opacity 0.7s;\n}\n.genome-spy.loading canvas {\n transform: scale(0.95, 0.95);\n opacity: 0;\n}\n.genome-spy.loading .loading-message .message {\n opacity: 1;\n}\n.genome-spy.loading .ellipsis {\n animation: blinker 1s linear infinite;\n}\n@keyframes blinker {\n 50% {\n opacity: 0;\n }\n}\n.genome-spy .loading-indicators {\n position: absolute;\n inset: 0;\n user-select: none;\n pointer-events: none;\n}\n.genome-spy .loading-indicators div {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-indicators div > div {\n font-size: 11px;\n transition: opacity 0.2s;\n background: white;\n padding: 2px 5px;\n display: flex;\n border-radius: 3px;\n gap: 0.5em;\n opacity: 0;\n}\n.genome-spy .loading-indicators div > div.loading {\n opacity: 0.5;\n}\n.genome-spy .loading-indicators div > div > * {\n display: block;\n}\n.genome-spy .loading-indicators div > div img {\n width: 1.5em;\n height: 1.5em;\n}\n.genome-spy .tooltip {\n position: absolute;\n max-width: 450px;\n overflow: hidden;\n background: #f6f6f6;\n padding: 10px;\n font-size: 13px;\n box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);\n pointer-events: none;\n z-index: 100;\n}\n.genome-spy .tooltip > :last-child {\n margin-bottom: 0;\n}\n.genome-spy .tooltip > .title {\n padding-bottom: 5px;\n margin-bottom: 5px;\n border-bottom: 1px dashed #b6b6b6;\n}\n.genome-spy .tooltip .summary {\n font-size: 12px;\n}\n.genome-spy .tooltip table {\n border-collapse: collapse;\n}\n.genome-spy .tooltip table:first-child {\n margin-top: 0;\n}\n.genome-spy .tooltip table th,\n.genome-spy .tooltip table td {\n padding: 2px 0.4em;\n vertical-align: top;\n}\n.genome-spy .tooltip table th:first-child,\n.genome-spy .tooltip table td:first-child {\n padding-left: 0;\n}\n.genome-spy .tooltip table th {\n text-align: left;\n font-weight: bold;\n}\n.genome-spy .tooltip .color-legend {\n display: inline-block;\n width: 0.8em;\n height: 0.8em;\n margin-left: 0.4em;\n box-shadow: 0px 0px 3px 1px white;\n}\n.genome-spy .tooltip .attributes .hovered {\n background-color: #e0e0e0;\n}\n.genome-spy .tooltip .na {\n color: #aaa;\n font-style: italic;\n font-size: 80%;\n}\n.genome-spy .gene-track-tooltip .summary {\n font-size: 90%;\n}\n.genome-spy .message-box {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n top: 0;\n height: 100%;\n width: 100%;\n}\n.genome-spy .message-box > div {\n border: 1px solid red;\n padding: 10px;\n background: #fff0f0;\n}";
2
+ declare const css: "\n.genome-spy {\n font-family: system-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n position: relative;\n display: flex;\n flex-direction: column;\n}\n.genome-spy .canvas-wrapper {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n}\n.genome-spy canvas {\n transform: scale(1, 1);\n opacity: 1;\n transition: transform 0.6s, opacity 0.6s;\n}\n.genome-spy .loading-message {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-message .message {\n color: #666;\n opacity: 0;\n transition: opacity 0.7s;\n}\n.genome-spy .loading > canvas {\n transform: scale(0.95, 0.95);\n opacity: 0;\n}\n.genome-spy .loading > .loading-message .message {\n opacity: 1;\n}\n.genome-spy .loading > .loading-message .message .ellipsis {\n animation: blinker 1s linear infinite;\n}\n@keyframes blinker {\n 50% {\n opacity: 0;\n }\n}\n.genome-spy .loading-indicators {\n position: absolute;\n inset: 0;\n user-select: none;\n pointer-events: none;\n}\n.genome-spy .loading-indicators div {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-indicators div > div {\n font-size: 11px;\n transition: opacity 0.2s;\n background: white;\n padding: 2px 5px;\n display: flex;\n border-radius: 3px;\n gap: 0.5em;\n opacity: 0;\n}\n.genome-spy .loading-indicators div > div.loading {\n opacity: 0.5;\n}\n.genome-spy .loading-indicators div > div > * {\n display: block;\n}\n.genome-spy .loading-indicators div > div img {\n width: 1.5em;\n height: 1.5em;\n}\n.genome-spy .tooltip {\n position: absolute;\n max-width: 450px;\n overflow: hidden;\n background: #f6f6f6;\n padding: 10px;\n font-size: 13px;\n box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);\n pointer-events: none;\n z-index: 100;\n}\n.genome-spy .tooltip > :last-child {\n margin-bottom: 0;\n}\n.genome-spy .tooltip > .title {\n padding-bottom: 5px;\n margin-bottom: 5px;\n border-bottom: 1px dashed #b6b6b6;\n}\n.genome-spy .tooltip .summary {\n font-size: 12px;\n}\n.genome-spy .tooltip table {\n border-collapse: collapse;\n}\n.genome-spy .tooltip table:first-child {\n margin-top: 0;\n}\n.genome-spy .tooltip table th,\n.genome-spy .tooltip table td {\n padding: 2px 0.4em;\n vertical-align: top;\n}\n.genome-spy .tooltip table th:first-child,\n.genome-spy .tooltip table td:first-child {\n padding-left: 0;\n}\n.genome-spy .tooltip table th {\n text-align: left;\n font-weight: bold;\n}\n.genome-spy .tooltip .color-legend {\n display: inline-block;\n width: 0.8em;\n height: 0.8em;\n margin-left: 0.4em;\n box-shadow: 0px 0px 3px 1px white;\n}\n.genome-spy .tooltip .attributes .hovered {\n background-color: #e0e0e0;\n}\n.genome-spy .tooltip .na {\n color: #aaa;\n font-style: italic;\n font-size: 80%;\n}\n.genome-spy .gene-track-tooltip .summary {\n font-size: 90%;\n}\n.genome-spy .message-box {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n top: 0;\n height: 100%;\n width: 100%;\n}\n.genome-spy .message-box > div {\n border: 1px solid red;\n padding: 10px;\n background: #fff0f0;\n}\n\n.gs-input-binding {\n display: grid;\n grid-template-columns: max-content max-content;\n column-gap: 1em;\n row-gap: 0.3em;\n justify-items: start;\n}\n.gs-input-binding > select,\n.gs-input-binding > input:not([type=checkbox]) {\n width: 100%;\n}\n.gs-input-binding input[type=range] + span {\n display: inline-block;\n margin-left: 0.3em;\n min-width: 2.2em;\n font-variant-numeric: tabular-nums;\n}\n.gs-input-binding input[type=range],\n.gs-input-binding input[type=radio] {\n vertical-align: text-bottom;\n}\n.gs-input-binding .radio-group {\n display: flex;\n align-items: center;\n}\n.gs-input-binding .description {\n max-width: 26em;\n grid-column: 1/-1;\n color: #777;\n font-size: 90%;\n margin-top: -0.5em;\n}\n\n.gs-input-bindings {\n flex-basis: content;\n font-size: 14px;\n padding: 10px;\n}\n";
3
3
  //# sourceMappingURL=genome-spy.css.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"genome-spy.css.d.ts","sourceRoot":"","sources":["../../../src/styles/genome-spy.css.js"],"names":[],"mappings":";AAAA,0jGA4IG"}
1
+ {"version":3,"file":"genome-spy.css.d.ts","sourceRoot":"","sources":["../../../src/styles/genome-spy.css.js"],"names":[],"mappings":";AAAA,6iIA4LE"}
@@ -1,6 +1,14 @@
1
- const css = `.genome-spy {
1
+ const css = `
2
+ .genome-spy {
2
3
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
3
4
  position: relative;
5
+ display: flex;
6
+ flex-direction: column;
7
+ }
8
+ .genome-spy .canvas-wrapper {
9
+ position: relative;
10
+ flex-grow: 1;
11
+ overflow: hidden;
4
12
  }
5
13
  .genome-spy canvas {
6
14
  transform: scale(1, 1);
@@ -19,14 +27,14 @@ const css = `.genome-spy {
19
27
  opacity: 0;
20
28
  transition: opacity 0.7s;
21
29
  }
22
- .genome-spy.loading canvas {
30
+ .genome-spy .loading > canvas {
23
31
  transform: scale(0.95, 0.95);
24
32
  opacity: 0;
25
33
  }
26
- .genome-spy.loading .loading-message .message {
34
+ .genome-spy .loading > .loading-message .message {
27
35
  opacity: 1;
28
36
  }
29
- .genome-spy.loading .ellipsis {
37
+ .genome-spy .loading > .loading-message .message .ellipsis {
30
38
  animation: blinker 1s linear infinite;
31
39
  }
32
40
  @keyframes blinker {
@@ -138,6 +146,45 @@ const css = `.genome-spy {
138
146
  border: 1px solid red;
139
147
  padding: 10px;
140
148
  background: #fff0f0;
141
- }`;
149
+ }
150
+
151
+ .gs-input-binding {
152
+ display: grid;
153
+ grid-template-columns: max-content max-content;
154
+ column-gap: 1em;
155
+ row-gap: 0.3em;
156
+ justify-items: start;
157
+ }
158
+ .gs-input-binding > select,
159
+ .gs-input-binding > input:not([type=checkbox]) {
160
+ width: 100%;
161
+ }
162
+ .gs-input-binding input[type=range] + span {
163
+ display: inline-block;
164
+ margin-left: 0.3em;
165
+ min-width: 2.2em;
166
+ font-variant-numeric: tabular-nums;
167
+ }
168
+ .gs-input-binding input[type=range],
169
+ .gs-input-binding input[type=radio] {
170
+ vertical-align: text-bottom;
171
+ }
172
+ .gs-input-binding .radio-group {
173
+ display: flex;
174
+ align-items: center;
175
+ }
176
+ .gs-input-binding .description {
177
+ max-width: 26em;
178
+ grid-column: 1/-1;
179
+ color: #777;
180
+ font-size: 90%;
181
+ margin-top: -0.5em;
182
+ }
142
183
 
184
+ .gs-input-bindings {
185
+ flex-basis: content;
186
+ font-size: 14px;
187
+ padding: 10px;
188
+ }
189
+ `;
143
190
  export default css;
@@ -10,6 +10,15 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
10
10
 
11
11
  position: relative;
12
12
 
13
+ display: flex;
14
+ flex-direction: column;
15
+
16
+ .canvas-wrapper {
17
+ position: relative;
18
+ flex-grow: 1;
19
+ overflow: hidden;
20
+ }
21
+
13
22
  canvas {
14
23
  transform: scale(1, 1);
15
24
  opacity: 1;
@@ -31,23 +40,23 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
31
40
  }
32
41
  }
33
42
 
34
- &.loading {
35
- canvas {
43
+ .loading {
44
+ > canvas {
36
45
  transform: scale(0.95, 0.95);
37
46
  opacity: 0;
38
47
  }
39
48
 
40
- .loading-message .message {
49
+ > .loading-message .message {
41
50
  opacity: 1;
42
- }
43
51
 
44
- .ellipsis {
45
- animation: blinker 1s linear infinite;
46
- }
52
+ .ellipsis {
53
+ animation: blinker 1s linear infinite;
54
+ }
47
55
 
48
- @keyframes blinker {
49
- 50% {
50
- opacity: 0;
56
+ @keyframes blinker {
57
+ 50% {
58
+ opacity: 0;
59
+ }
51
60
  }
52
61
  }
53
62
  }
@@ -187,3 +196,47 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
187
196
  }
188
197
  }
189
198
  }
199
+
200
+ .gs-input-binding {
201
+ display: grid;
202
+ grid-template-columns: max-content max-content;
203
+ column-gap: 1em;
204
+ row-gap: 0.3em;
205
+ justify-items: start;
206
+
207
+ > select,
208
+ > input:not([type="checkbox"]) {
209
+ width: 100%;
210
+ }
211
+
212
+ input[type="range"] + span {
213
+ display: inline-block;
214
+ margin-left: 0.3em;
215
+ min-width: 2.2em;
216
+ font-variant-numeric: tabular-nums;
217
+ }
218
+
219
+ input[type="range"],
220
+ input[type="radio"] {
221
+ vertical-align: text-bottom;
222
+ }
223
+
224
+ .radio-group {
225
+ display: flex;
226
+ align-items: center;
227
+ }
228
+
229
+ .description {
230
+ max-width: 26em;
231
+ grid-column: 1 / -1;
232
+ color: #777;
233
+ font-size: 90%;
234
+ margin-top: -0.5em;
235
+ }
236
+ }
237
+
238
+ .gs-input-bindings {
239
+ flex-basis: content;
240
+ font-size: 14px;
241
+ padding: $basic-spacing;
242
+ }
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ echo "const css = \`" > genome-spy.css.js
3
+ sass genome-spy.scss >> genome-spy.css.js
4
+ echo "\`;" >> genome-spy.css.js
5
+ echo "export default css;" >> genome-spy.css.js
6
+
@@ -1,4 +1,4 @@
1
- import { html } from "lit-html";
1
+ import { html } from "lit";
2
2
  import formatObject from "../utils/formatObject.js";
3
3
 
4
4
  /**
@@ -1,5 +1,5 @@
1
1
  import { debounce } from "../utils/debounce.js";
2
- import { html } from "lit-html";
2
+ import { html } from "lit";
3
3
 
4
4
  /*
5
5
  * https://www.ncbi.nlm.nih.gov/books/NBK25500/
@@ -1,4 +1,4 @@
1
- import { TemplateResult } from "lit-html";
1
+ import { TemplateResult } from "lit";
2
2
  import Mark from "../marks/mark.js";
3
3
  /**
4
4
  * Converts a datum to tooltip (HTMLElement or lit's TemplateResult).
@@ -1 +1 @@
1
- {"version":3,"file":"tooltipHandler.d.ts","sourceRoot":"","sources":["../../../src/tooltip/tooltipHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,IAAI,MAAM,kBAAkB,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,IAAI,EAAE,IAAI;AACV,sDAAsD;AACtD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC3B,OAAO,CAAC,MAAM,GAAG,cAAc,GAAG,WAAW,CAAC,CAAC"}
1
+ {"version":3,"file":"tooltipHandler.d.ts","sourceRoot":"","sources":["../../../src/tooltip/tooltipHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AACrC,OAAO,IAAI,MAAM,kBAAkB,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,CACzB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,IAAI,EAAE,IAAI;AACV,sDAAsD;AACtD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC3B,OAAO,CAAC,MAAM,GAAG,cAAc,GAAG,WAAW,CAAC,CAAC"}
@@ -1,4 +1,4 @@
1
- import { TemplateResult } from "lit-html";
1
+ import { TemplateResult } from "lit";
2
2
  import Mark from "../marks/mark.js";
3
3
 
4
4
  /**
@@ -27,6 +27,12 @@ export interface EmbedOptions {
27
27
  * Custom tooltip handlers. Use `"default"` to override the default handler
28
28
  */
29
29
  tooltipHandlers?: Record<string, TooltipHandler>;
30
+
31
+ /**
32
+ * Where to put the input binding elements. The default is `"default"`, which means that
33
+ * the input binding elements are placed in the same container as the GenomeSpy instance.
34
+ */
35
+ inputBindingContainer?: HTMLElement | "none" | "default";
30
36
  }
31
37
 
32
38
  /**
@@ -1,8 +1,9 @@
1
1
  import { ComplexDomain, NumericDomain } from "../spec/scale.js";
2
2
  import ScaleResolution from "../view/scaleResolution.js";
3
3
 
4
+ export type ScaleResolutionEventType = "domain" | "range";
4
5
  export interface ScaleResolutionEvent {
5
- type: "domain";
6
+ type: ScaleResolutionEventType;
6
7
 
7
8
  scaleResolution: ScaleResolution;
8
9
  }
@@ -13,10 +14,13 @@ export type ScaleResolutionListener = (event: ScaleResolutionEvent) => void;
13
14
  * A public API for ScaleResolution
14
15
  */
15
16
  export interface ScaleResolutionApi {
16
- addEventListener(type: "domain", listener: ScaleResolutionListener): void;
17
+ addEventListener(
18
+ type: ScaleResolutionEventType,
19
+ listener: ScaleResolutionListener
20
+ ): void;
17
21
 
18
22
  removeEventListener(
19
- type: "domain",
23
+ type: ScaleResolutionEventType,
20
24
  listener: ScaleResolutionListener
21
25
  ): void;
22
26
 
@@ -1,4 +1,4 @@
1
- import { TemplateResult } from "lit-html";
1
+ import { TemplateResult } from "lit";
2
2
  import View, { BroadcastMessage } from "../view/view.js";
3
3
  import DataFlow from "../data/dataFlow.js";
4
4
  import AccessorFactory from "../encoder/accessor.js";
@@ -11,7 +11,7 @@ import { Datum } from "../data/flowNode.js";
11
11
  import { ImportSpec, ViewSpec } from "../spec/view.js";
12
12
  import ContainerView from "./containerView.js";
13
13
  import { BroadcastEventType } from "../genomeSpy.js";
14
- import ParamBroker from "../paramBroker.js";
14
+ import ParamMediator from "../view/paramMediator.js";
15
15
 
16
16
  export interface Hover {
17
17
  mark: Mark;
@@ -29,7 +29,6 @@ export default interface ViewContext {
29
29
  genomeStore?: GenomeStore;
30
30
  fontManager: BmFontManager;
31
31
 
32
- paramBroker: ParamBroker;
33
32
  devicePixelRatio: number;
34
33
 
35
34
  requestLayoutReflow: () => void;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @param {(...args:T) => R} func
3
- * @param {number} wait
3
+ * @param {number | (() => number)} wait
4
4
  * @template {any[]} T
5
5
  * @template R
6
6
  */
7
- export function debounce<T extends any[], R>(func: (...args: T) => R, wait: number, rejectOnDebounce?: boolean): (...args: T) => Promise<R>;
7
+ export function debounce<T extends any[], R>(func: (...args: T) => R, wait: number | (() => number), rejectOnDebounce?: boolean): (...args: T) => Promise<R>;
8
8
  //# sourceMappingURL=debounce.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"debounce.d.ts","sourceRoot":"","sources":["../../../src/utils/debounce.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,4EAJW,MAAM,0DAkChB"}
1
+ {"version":3,"file":"debounce.d.ts","sourceRoot":"","sources":["../../../src/utils/debounce.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,4EAJW,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,0DAqCjC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @param {(...args:T) => R} func
3
- * @param {number} wait
3
+ * @param {number | (() => number)} wait
4
4
  * @template {any[]} T
5
5
  * @template R
6
6
  */
@@ -29,7 +29,10 @@ export function debounce(func, wait, rejectOnDebounce = true) {
29
29
  clearTimeout(timeout);
30
30
 
31
31
  rejectPrevious = reject;
32
- timeout = window.setTimeout(later, wait);
32
+ timeout = window.setTimeout(
33
+ later,
34
+ typeof wait == "function" ? wait() : wait
35
+ );
33
36
  });
34
37
  };
35
38
 
@@ -4,7 +4,7 @@
4
4
  * @prop { string[] } globals
5
5
  * @prop { string } code
6
6
  *
7
- * @typedef { ((x: object) => any) & ExpressionProps } ExpressionFunction
7
+ * @typedef { ((datum?: object) => any) & ExpressionProps } ExpressionFunction
8
8
  *
9
9
  * @param {string} expr
10
10
  * @returns {ExpressionFunction}
@@ -15,5 +15,5 @@ export type ExpressionProps = {
15
15
  globals: string[];
16
16
  code: string;
17
17
  };
18
- export type ExpressionFunction = ((x: object) => any) & ExpressionProps;
18
+ export type ExpressionFunction = ((datum?: object) => any) & ExpressionProps;
19
19
  //# sourceMappingURL=expression.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../../src/utils/expression.js"],"names":[],"mappings":"AAyDA;;;;;;;;;;GAUG;AACH,6CAHW,MAAM,sBACJ,kBAAkB,CAyB9B;;YAhCU,MAAM,EAAE;aACR,MAAM,EAAE;UACR,MAAM;;sCAEE,MAAM,KAAK,GAAG"}
1
+ {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../../src/utils/expression.js"],"names":[],"mappings":"AAyDA;;;;;;;;;;GAUG;AACH,6CAHW,MAAM,sBACJ,kBAAkB,CAyB9B;;YAhCU,MAAM,EAAE;aACR,MAAM,EAAE;UACR,MAAM;;2CAEO,MAAM,KAAK,GAAG"}
@@ -61,7 +61,7 @@ const cg = codegenExpression({
61
61
  * @prop { string[] } globals
62
62
  * @prop { string } code
63
63
  *
64
- * @typedef { ((x: object) => any) & ExpressionProps } ExpressionFunction
64
+ * @typedef { ((datum?: object) => any) & ExpressionProps } ExpressionFunction
65
65
  *
66
66
  * @param {string} expr
67
67
  * @returns {ExpressionFunction}
@@ -79,8 +79,8 @@ export default function createFunction(expr, globalObject = {}) {
79
79
  ).bind(functionContext);
80
80
 
81
81
  /** @type { ExpressionFunction } */
82
- const exprFunction = /** @param {object} x */ (x) =>
83
- fn(x, globalObject);
82
+ const exprFunction = /** @param {object} datum */ (datum) =>
83
+ fn(datum, globalObject);
84
84
  exprFunction.fields = generatedCode.fields;
85
85
  exprFunction.globals = generatedCode.globals;
86
86
  exprFunction.code = generatedCode.code;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  *
3
3
  * @param {any} object Object to format
4
- * @returns {string | import("lit-html").TemplateResult}
4
+ * @returns {string | import("lit").TemplateResult}
5
5
  */
6
- export default function formatObject(object: any): string | import("lit-html").TemplateResult;
6
+ export default function formatObject(object: any): string | import("lit").TemplateResult;
7
7
  //# sourceMappingURL=formatObject.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"formatObject.d.ts","sourceRoot":"","sources":["../../../src/utils/formatObject.js"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,6CAHW,GAAG,GACD,MAAM,GAAG,OAAO,UAAU,EAAE,cAAc,CA0BtD"}
1
+ {"version":3,"file":"formatObject.d.ts","sourceRoot":"","sources":["../../../src/utils/formatObject.js"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,6CAHW,GAAG,GACD,MAAM,GAAG,OAAO,KAAK,EAAE,cAAc,CA0BjD"}
@@ -1,6 +1,6 @@
1
1
  import { isNumber, isString, isBoolean, isArray } from "vega-util";
2
2
  import { format as d3format } from "d3-format";
3
- import { html, nothing } from "lit-html";
3
+ import { html, nothing } from "lit";
4
4
 
5
5
  const numberFormat = d3format(".4~r");
6
6
  const exponentNumberFormat = d3format(".4~e");
@@ -8,7 +8,7 @@ const exponentNumberFormat = d3format(".4~e");
8
8
  /**
9
9
  *
10
10
  * @param {any} object Object to format
11
- * @returns {string | import("lit-html").TemplateResult}
11
+ * @returns {string | import("lit").TemplateResult}
12
12
  */
13
13
  export default function formatObject(object) {
14
14
  if (object === null || object === undefined) {
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @param {import("../view/paramMediator.js").default} mediator
3
+ */
4
+ export default function createBindingInputs(mediator: import("../view/paramMediator.js").default): import("lit-html").TemplateResult<2 | 1>[];
5
+ //# sourceMappingURL=inputBinding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputBinding.d.ts","sourceRoot":"","sources":["../../../src/utils/inputBinding.js"],"names":[],"mappings":"AAIA;;GAEG;AACH,sDAFW,OAAO,0BAA0B,EAAE,OAAO,8CA6GpD"}
@@ -0,0 +1,115 @@
1
+ import { html } from "lit";
2
+ import { debounce } from "./debounce.js";
3
+ import { tickStep } from "d3-array";
4
+
5
+ /**
6
+ * @param {import("../view/paramMediator.js").default} mediator
7
+ */
8
+ export default function createBindingInputs(mediator) {
9
+ const random = Math.floor(Math.random() * 0xffffff).toString(16);
10
+
11
+ /** @type {import("lit").TemplateResult[]} */
12
+ const inputs = [];
13
+
14
+ for (const param of mediator.paramConfigs.values()) {
15
+ const bind = param.bind;
16
+ if (!bind || !("input" in bind)) {
17
+ continue;
18
+ }
19
+
20
+ const name = param.name;
21
+ const setter = mediator.getSetter(name);
22
+ const value = mediator.getValue(name);
23
+ const label = bind.name ?? name;
24
+
25
+ // TODO: Implement two-way data binding, e.g. when an external agent changes
26
+ // the parameter value, the UI components should be updated.
27
+
28
+ const debouncedSetter = bind.debounce
29
+ ? debounce(setter, bind.debounce, false)
30
+ : setter;
31
+
32
+ const id = `${random}-param-${name}`;
33
+
34
+ if (bind.input == "range") {
35
+ // TODO: Show the value next to the slider
36
+ inputs.push(
37
+ html`<label for=${id}>${label}</label>
38
+ <div>
39
+ <input
40
+ id=${id}
41
+ type="range"
42
+ min=${bind.min ?? 0}
43
+ max=${bind.max ?? 100}
44
+ step=${bind.step ??
45
+ tickStep(bind.min, bind.max, 100)}
46
+ .value=${value}
47
+ @input=${(/** @type {any} */ e) => {
48
+ debouncedSetter(e.target.valueAsNumber);
49
+ e.target.nextElementSibling.textContent =
50
+ e.target.valueAsNumber;
51
+ }}
52
+ /><span>${value}</span>
53
+ </div>`
54
+ );
55
+ } else if (bind.input == "checkbox") {
56
+ inputs.push(
57
+ html`<label for=${id}>${label}</label>
58
+ <input
59
+ id=${id}
60
+ type="checkbox"
61
+ ?checked=${value}
62
+ @input=${(/** @type {any} */ e) =>
63
+ debouncedSetter(e.target.checked)}
64
+ />`
65
+ );
66
+ } else if (bind.input == "radio") {
67
+ inputs.push(
68
+ html`<span class="label">${label}</span>
69
+ <div class="radio-group">
70
+ ${bind.options.map(
71
+ (option, i) => html`<label>
72
+ <input
73
+ type="radio"
74
+ name=${name}
75
+ value=${option}
76
+ .checked=${value == option}
77
+ @input=${(/** @type {any} */ e) =>
78
+ debouncedSetter(e.target.value)}
79
+ />${bind.labels?.[i] ?? option}</label
80
+ >`
81
+ )}
82
+ </div>`
83
+ );
84
+ } else if (bind.input == "select") {
85
+ inputs.push(
86
+ html`<label for=${id}>${label}</label>
87
+ <select
88
+ id=${id}
89
+ @input=${(/** @type {any} */ e) =>
90
+ debouncedSetter(e.target.value)}
91
+ >
92
+ ${bind.options.map(
93
+ (option, i) => html`<option
94
+ value=${option}
95
+ ?selected=${value == option}
96
+ >
97
+ ${bind.labels?.[i] ?? option}
98
+ </option>`
99
+ )}
100
+ </select> `
101
+ );
102
+ } else {
103
+ // TODO: Support other types: "text", "number", "color".
104
+ throw new Error("Unsupported input type: " + bind.input);
105
+ }
106
+
107
+ if (bind.description) {
108
+ inputs.push(
109
+ html`<div class="description">${bind.description}</div>`
110
+ );
111
+ }
112
+ }
113
+
114
+ return inputs;
115
+ }
@@ -1,5 +1,5 @@
1
1
  import clientPoint from "../point.js";
2
- import { html, render } from "lit-html";
2
+ import { html, render } from "lit";
3
3
  import { peek } from "../arrayUtils.js";
4
4
 
5
5
  export const SUPPRESS_TOOLTIP_CLASS_NAME = "gs-suppress-tooltip";