@genome-spy/core 0.59.0 → 0.60.1

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 (85) hide show
  1. package/dist/bundle/index.es.js +6100 -5545
  2. package/dist/bundle/index.js +144 -119
  3. package/dist/schema.json +304 -22
  4. package/dist/src/data/collector.d.ts.map +1 -1
  5. package/dist/src/data/collector.js +1 -0
  6. package/dist/src/data/sources/dataUtils.d.ts +2 -1
  7. package/dist/src/data/sources/dataUtils.d.ts.map +1 -1
  8. package/dist/src/data/sources/dataUtils.js +3 -4
  9. package/dist/src/data/sources/inlineSource.d.ts +8 -0
  10. package/dist/src/data/sources/inlineSource.d.ts.map +1 -1
  11. package/dist/src/data/sources/inlineSource.js +17 -1
  12. package/dist/src/data/sources/urlSource.d.ts +1 -0
  13. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  14. package/dist/src/data/sources/urlSource.js +33 -4
  15. package/dist/src/encoder/encoder.d.ts +1 -1
  16. package/dist/src/genomeSpy.d.ts.map +1 -1
  17. package/dist/src/genomeSpy.js +39 -6
  18. package/dist/src/gl/colorUtils.d.ts +4 -0
  19. package/dist/src/gl/colorUtils.d.ts.map +1 -1
  20. package/dist/src/gl/colorUtils.js +8 -0
  21. package/dist/src/gl/glslScaleGenerator.d.ts +1 -1
  22. package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
  23. package/dist/src/gl/glslScaleGenerator.js +1 -9
  24. package/dist/src/gl/includes/common.glsl.js +1 -1
  25. package/dist/src/marks/link.d.ts.map +1 -1
  26. package/dist/src/marks/link.js +8 -0
  27. package/dist/src/marks/mark.d.ts +8 -0
  28. package/dist/src/marks/mark.d.ts.map +1 -1
  29. package/dist/src/marks/mark.js +101 -3
  30. package/dist/src/marks/point.fragment.glsl.js +1 -1
  31. package/dist/src/marks/point.vertex.glsl.js +1 -1
  32. package/dist/src/marks/rect.common.glsl.js +1 -1
  33. package/dist/src/marks/rect.d.ts.map +1 -1
  34. package/dist/src/marks/rect.fragment.glsl.js +1 -1
  35. package/dist/src/marks/rect.js +41 -0
  36. package/dist/src/marks/rect.vertex.glsl.js +1 -1
  37. package/dist/src/selection/selection.d.ts +27 -2
  38. package/dist/src/selection/selection.d.ts.map +1 -1
  39. package/dist/src/selection/selection.js +53 -3
  40. package/dist/src/spec/data.d.ts +18 -1
  41. package/dist/src/spec/mark.d.ts +58 -1
  42. package/dist/src/spec/parameter.d.ts +71 -31
  43. package/dist/src/spec/view.d.ts +9 -2
  44. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  45. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  46. package/dist/src/styles/genome-spy.css.js +12 -1
  47. package/dist/src/styles/genome-spy.scss +19 -1
  48. package/dist/src/types/selectionTypes.d.ts +4 -7
  49. package/dist/src/utils/expression.d.ts.map +1 -1
  50. package/dist/src/utils/expression.js +4 -0
  51. package/dist/src/utils/ui/tooltip.d.ts +6 -10
  52. package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
  53. package/dist/src/utils/ui/tooltip.js +74 -42
  54. package/dist/src/view/concatView.d.ts +1 -1
  55. package/dist/src/view/concatView.d.ts.map +1 -1
  56. package/dist/src/view/concatView.js +1 -1
  57. package/dist/src/view/gridView/gridChild.d.ts +53 -0
  58. package/dist/src/view/gridView/gridChild.d.ts.map +1 -0
  59. package/dist/src/view/gridView/gridChild.js +758 -0
  60. package/dist/src/view/gridView/gridView.d.ts +64 -0
  61. package/dist/src/view/gridView/gridView.d.ts.map +1 -0
  62. package/dist/src/view/{gridView.js → gridView/gridView.js} +40 -595
  63. package/dist/src/view/gridView/scrollbar.d.ts +32 -0
  64. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -0
  65. package/dist/src/view/gridView/scrollbar.js +186 -0
  66. package/dist/src/view/gridView/selectionRect.d.ts +10 -0
  67. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -0
  68. package/dist/src/view/gridView/selectionRect.js +182 -0
  69. package/dist/src/view/layout/rectangle.d.ts +11 -1
  70. package/dist/src/view/layout/rectangle.d.ts.map +1 -1
  71. package/dist/src/view/layout/rectangle.js +22 -2
  72. package/dist/src/view/layout/rectangle.test.js +12 -0
  73. package/dist/src/view/paramMediator.d.ts.map +1 -1
  74. package/dist/src/view/paramMediator.js +9 -0
  75. package/dist/src/view/scaleResolution.d.ts +1 -0
  76. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  77. package/dist/src/view/scaleResolution.js +43 -33
  78. package/dist/src/view/view.d.ts +6 -0
  79. package/dist/src/view/view.d.ts.map +1 -1
  80. package/dist/src/view/view.js +19 -0
  81. package/dist/src/view/viewFactory.d.ts.map +1 -1
  82. package/dist/src/view/viewFactory.js +13 -1
  83. package/package.json +2 -2
  84. package/dist/src/view/gridView.d.ts +0 -135
  85. package/dist/src/view/gridView.d.ts.map +0 -1
@@ -25,6 +25,20 @@ export function createMultiPointSelection(data) {
25
25
  };
26
26
  }
27
27
 
28
+ /**
29
+ *
30
+ * @param {import("../spec/channel.js").ChannelWithScale[]} channels
31
+ * @returns {import("../types/selectionTypes.js").IntervalSelection}
32
+ */
33
+ export function createIntervalSelection(channels) {
34
+ return {
35
+ type: "interval",
36
+ intervals: Object.fromEntries(
37
+ channels.map((c) => [c, /** @type {number[]} */ (null)])
38
+ ),
39
+ };
40
+ }
41
+
28
42
  /**
29
43
  * Updates the backing data and returns a new instance of the selection object.
30
44
  * A new instance is required to trigger reactivity in parameters.
@@ -78,6 +92,8 @@ export function selectionTest(selection, datum, empty = true) {
78
92
  return selection.data.size == 0
79
93
  ? empty
80
94
  : selection.data.has(datum[UNIQUE_ID_KEY]); // TODO: Binary search
95
+ } else if (isIntervalSelection(selection)) {
96
+ throw new Error("TODO: Implement interval selection test");
81
97
  } else {
82
98
  throw new Error("Not a selection: " + JSON.stringify(selection));
83
99
  }
@@ -94,10 +110,10 @@ export function makeSelectionTestExpression(params) {
94
110
 
95
111
  /**
96
112
  * @param {import("../types/selectionTypes.js").Selection} selection
97
- * @returns {selection is import("../types/selectionTypes.js").RangeSelection}
113
+ * @returns {selection is import("../types/selectionTypes.js").IntervalSelection}
98
114
  */
99
- export function isRangeSelection(selection) {
100
- return selection.type === "range";
115
+ export function isIntervalSelection(selection) {
116
+ return selection.type === "interval";
101
117
  }
102
118
 
103
119
  /**
@@ -152,3 +168,37 @@ export function asSelectionConfig(typeOrConfig) {
152
168
  export function isPointSelectionConfig(config) {
153
169
  return config && config.type == "point";
154
170
  }
171
+
172
+ /**
173
+ *
174
+ * @param {import("../spec/parameter.js").SelectionConfig} config
175
+ * @returns {config is import("../spec/parameter.js").IntervalSelectionConfig}
176
+ */
177
+ export function isIntervalSelectionConfig(config) {
178
+ return config && config.type == "interval";
179
+ }
180
+
181
+ /**
182
+ * @param {import("../types/selectionTypes.js").IntervalSelection} selection
183
+ */
184
+ export function isActiveIntervalSelection(selection) {
185
+ return Object.values(selection.intervals).some(
186
+ (interval) => interval && interval.length === 2
187
+ );
188
+ }
189
+
190
+ /**
191
+ * @typedef {import("../types/selectionTypes.js").IntervalSelection} IntervalSelection
192
+ * @typedef {Partial<Record<keyof IntervalSelection["intervals"], number>>} IntervalPoint
193
+ * @param {IntervalSelection} selection
194
+ * @param {IntervalPoint} point
195
+ */
196
+ export function selectionContainsPoint(selection, point) {
197
+ return Object.entries(selection.intervals).every(
198
+ ([channel, interval]) =>
199
+ (channel == "x" || channel == "y") &&
200
+ interval &&
201
+ interval[0] <= point[channel] &&
202
+ interval[1] >= point[channel]
203
+ );
204
+ }
@@ -119,12 +119,29 @@ export interface DataBase {
119
119
  name?: string;
120
120
  }
121
121
 
122
+ export interface UrlList {
123
+ /**
124
+ * A URL that returns a list of URLs to load the data set.
125
+ * The URLs in the list can be absolute or relative to the URL of the list.
126
+ */
127
+ urlsFromFile: string;
128
+
129
+ /**
130
+ * The format of the data in the list.
131
+ * If the type is `"json"`, the list is expected to be an array of strings.
132
+ * If the type is `"csv"` or `"tsv"`, the list is expected to be a table with a single column named `file`.
133
+ *
134
+ * __Default value:__ `"txt"`
135
+ */
136
+ type?: "json" | "csv" | "tsv";
137
+ }
138
+
122
139
  export interface UrlData extends DataBase {
123
140
  /**
124
141
  * An URL or an array of URLs from which to load the data set.
125
142
  * Use the `format.type` property to ensure the loaded data is correctly parsed.
126
143
  */
127
- url: string | string[] | ExprRef;
144
+ url: string | string[] | ExprRef | UrlList;
128
145
  }
129
146
 
130
147
  export interface InlineData extends DataBase {
@@ -110,6 +110,43 @@ export interface FillAndStrokeProps {
110
110
  strokeOpacity?: number | ExprRef;
111
111
  }
112
112
 
113
+ export interface ShadowProps {
114
+ /**
115
+ * The color of the drop shadow. Any valid CSS color string is allowed.
116
+ *
117
+ * **Default value:** `"black"`
118
+ */
119
+ shadowColor?: string | ExprRef;
120
+
121
+ /**
122
+ * The opacity of the drop shadow. Value between `0` (fully transparent) and `1` (fully opaque).
123
+ *
124
+ * **Default value:** `0` (disabled)
125
+ */
126
+ shadowOpacity?: number | ExprRef;
127
+
128
+ /**
129
+ * The horizontal offset of the drop shadow in pixels. Positive values move the shadow to the right.
130
+ *
131
+ * **Default value:** `0`
132
+ */
133
+ shadowOffsetX?: number | ExprRef;
134
+
135
+ /**
136
+ * The vertical offset of the drop shadow in pixels. Positive values move the shadow downward.
137
+ *
138
+ * **Default value:** `0`
139
+ */
140
+ shadowOffsetY?: number | ExprRef;
141
+
142
+ /**
143
+ * The blur radius of the drop shadow in pixels. Higher values produce a more diffuse shadow.
144
+ *
145
+ * **Default value:** `0`
146
+ */
147
+ shadowBlur?: number | ExprRef;
148
+ }
149
+
113
150
  export interface SecondaryPositionProps {
114
151
  /**
115
152
  * The secondary position on the x axis.
@@ -161,7 +198,8 @@ export interface ViewportEdgeFadeProps {
161
198
  export interface RectProps
162
199
  extends MarkPropsBase,
163
200
  SecondaryPositionProps,
164
- FillAndStrokeProps {
201
+ FillAndStrokeProps,
202
+ ShadowProps {
165
203
  type: "rect";
166
204
 
167
205
  /**
@@ -232,6 +270,25 @@ export interface RectProps
232
270
  * **Default value:** (None)
233
271
  */
234
272
  cornerRadiusBottomRight?: number | ExprRef;
273
+
274
+ /**
275
+ * A hatch pattern drawn inside the mark using the stroke width, color, and opacity.
276
+ * The pattern is aligned in screen space and scaled by the stroke width.
277
+ *
278
+ * **Default value:** `"none"`
279
+ */
280
+ hatch?:
281
+ | "none"
282
+ | "diagonal"
283
+ | "antiDiagonal"
284
+ | "cross"
285
+ | "vertical"
286
+ | "horizontal"
287
+ | "grid"
288
+ | "dots"
289
+ | "rings"
290
+ | "ringsLarge"
291
+ | ExprRef;
235
292
  }
236
293
 
237
294
  export interface RuleProps
@@ -1,4 +1,5 @@
1
- import { ChannelWithScale, Scalar } from "./channel.js";
1
+ import { PrimaryPositionalChannel, Scalar } from "./channel.js";
2
+ import { ShadowProps } from "./mark.js";
2
3
 
3
4
  export interface ExprRef {
4
5
  /**
@@ -177,22 +178,6 @@ export interface BaseSelectionConfig<T extends SelectionType = SelectionType> {
177
178
  /**
178
179
  */
179
180
  on?: "click" | "mouseover" | "pointerover";
180
-
181
- /**
182
- * An array of encoding channels. The corresponding data field values
183
- * must match for a data tuple to fall within the selection.
184
- *
185
- * __See also:__ The [projection with `encodings` and `fields` section](https://vega.github.io/vega-lite/docs/selection.html#project) in the documentation.
186
- */
187
- encodings?: ChannelWithScale[];
188
-
189
- /**
190
- * An array of field names whose values must match for a data tuple to
191
- * fall within the selection.
192
- *
193
- * __See also:__ The [projection with `encodings` and `fields` section](https://vega.github.io/vega-lite/docs/selection.html#project) in the documentation.
194
- */
195
- fields?: string[];
196
181
  }
197
182
 
198
183
  export interface PointSelectionConfig extends BaseSelectionConfig<"point"> {
@@ -219,7 +204,67 @@ export interface PointSelectionConfig extends BaseSelectionConfig<"point"> {
219
204
 
220
205
  export interface IntervalSelectionConfig
221
206
  extends BaseSelectionConfig<"interval"> {
222
- // TODO
207
+ type: "interval";
208
+
209
+ /**
210
+ * An array of encoding channels that define the interval selection.
211
+ */
212
+ encodings?: PrimaryPositionalChannel[];
213
+
214
+ /**
215
+ * Interval selections display a rectangle mark to show the selected range.
216
+ * Use the `mark` property to adjust the appearance of this rectangle.
217
+ */
218
+ mark?: BrushConfig;
219
+ }
220
+
221
+ export interface BrushConfig extends ShadowProps {
222
+ /**
223
+ * The fill color of the interval mark.
224
+ *
225
+ * __Default value:__ `"#808080"`
226
+ *
227
+ */
228
+ fill?: string;
229
+
230
+ /**
231
+ * The fill opacity of the interval mark (a value between `0` and `1`).
232
+ *
233
+ * __Default value:__ `0.05`
234
+ */
235
+ fillOpacity?: number;
236
+
237
+ /**
238
+ * The stroke color of the interval mark.
239
+ *
240
+ * __Default value:__ `"black"`
241
+ */
242
+ stroke?: string;
243
+
244
+ /**
245
+ * The stroke opacity of the interval mark (a value between `0` and `1`).
246
+ *
247
+ * __Default value:__ `0.2`
248
+ */
249
+ strokeOpacity?: number;
250
+
251
+ /**
252
+ * The stroke width of the interval mark.
253
+ *
254
+ * __Default value:__ `1`
255
+ */
256
+ strokeWidth?: number;
257
+
258
+ /**
259
+ * Where to display the measurement text (e.g., number of base pairs) for the interval selection.
260
+ *
261
+ * - `"none"` -- do not show the measurement.
262
+ * - `"inside"` -- show inside the brush rectangle.
263
+ * - `"outside"` -- show outside the brush rectangle.
264
+ *
265
+ * __Default value:__ `"none"`
266
+ */
267
+ measure?: "none" | "inside" | "outside";
223
268
  }
224
269
 
225
270
  export interface SelectionParameter<T extends SelectionType = SelectionType>
@@ -238,21 +283,16 @@ export interface SelectionParameter<T extends SelectionType = SelectionType>
238
283
  ? IntervalSelectionConfig
239
284
  : never);
240
285
 
241
- /*
242
- * Initialize the selection with a mapping between [projected channels or field names](https://vega.github.io/vega-lite/docs/selection.html#project) and initial values.
243
- *
244
- * __See also:__ [`init`](https://vega.github.io/vega-lite/docs/value.html) documentation.
245
- */
246
- /*
247
- // TODO TODO TODO TODO TODO TODO TODO TODO
248
- value?: T extends "point"
249
- ? SelectionInit | SelectionInitMapping[]
250
- : T extends "interval"
251
- ? SelectionInitIntervalMapping
252
- : never;
253
- */
286
+ /**
287
+ * Initial value for the selection.
288
+ */
289
+ value?: T extends "interval" ? SelectionInitIntervalMapping : never;
254
290
  }
255
291
 
292
+ export type SelectionInitIntervalMapping = Partial<
293
+ Record<PrimaryPositionalChannel, [number, number]>
294
+ >;
295
+
256
296
  export type SelectionConfig = PointSelectionConfig | IntervalSelectionConfig;
257
297
  export type SelectionTypeOrConfig = SelectionType | SelectionConfig;
258
298
 
@@ -6,7 +6,13 @@ import {
6
6
  FacetFieldDef,
7
7
  PrimaryPositionalChannel,
8
8
  } from "./channel.js";
9
- import { FillAndStrokeProps, MarkProps, MarkType, RectProps } from "./mark.js";
9
+ import {
10
+ FillAndStrokeProps,
11
+ MarkProps,
12
+ MarkType,
13
+ RectProps,
14
+ ShadowProps,
15
+ } from "./mark.js";
10
16
  import { ExprRef } from "./parameter.js";
11
17
  import { Title } from "./title.js";
12
18
  import { SampleSpec } from "./sampleView.js";
@@ -74,7 +80,8 @@ interface CompleteViewBackground extends RectProps, FillAndStrokeProps {
74
80
  export type ViewBackground = Pick<
75
81
  CompleteViewBackground,
76
82
  "fill" | "fillOpacity" | "stroke" | "strokeWidth" | "strokeOpacity"
77
- >;
83
+ > &
84
+ ShadowProps;
78
85
 
79
86
  export interface ViewSpecBase extends ResolveSpec {
80
87
  /**
@@ -1,3 +1,3 @@
1
1
  export default css;
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 display: block;\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.error {\n opacity: 0.8;\n color: firebrick;\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: 12px;\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";
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 display: block;\n transform: scale(1, 1);\n opacity: 1;\n transition: transform 0.6s, opacity 0.6s;\n}\n.genome-spy canvas:focus, .genome-spy canvas:focus-visible {\n outline: none;\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.error {\n opacity: 0.8;\n color: firebrick;\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: 12px;\n box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);\n transition: outline-color 0.3s ease-in-out, box-shadow 0.3s ease-in-out;\n outline: 0px solid transparent;\n z-index: 100;\n}\n.genome-spy .tooltip:not(.sticky) {\n pointer-events: none;\n}\n.genome-spy .tooltip.sticky {\n outline: 2px solid black;\n box-shadow: 0px 3px 18px 0px rgba(0, 0, 0, 0.3);\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,4pIAiME"}
1
+ {"version":3,"file":"genome-spy.css.d.ts","sourceRoot":"","sources":["../../../src/styles/genome-spy.css.js"],"names":[],"mappings":";AAAA,y/IA4ME"}
@@ -16,6 +16,9 @@ const css = `
16
16
  opacity: 1;
17
17
  transition: transform 0.6s, opacity 0.6s;
18
18
  }
19
+ .genome-spy canvas:focus, .genome-spy canvas:focus-visible {
20
+ outline: none;
21
+ }
19
22
  .genome-spy .loading-message {
20
23
  position: absolute;
21
24
  inset: 0;
@@ -87,9 +90,17 @@ const css = `
87
90
  padding: 10px;
88
91
  font-size: 12px;
89
92
  box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);
90
- pointer-events: none;
93
+ transition: outline-color 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
94
+ outline: 0px solid transparent;
91
95
  z-index: 100;
92
96
  }
97
+ .genome-spy .tooltip:not(.sticky) {
98
+ pointer-events: none;
99
+ }
100
+ .genome-spy .tooltip.sticky {
101
+ outline: 2px solid black;
102
+ box-shadow: 0px 3px 18px 0px rgba(0, 0, 0, 0.3);
103
+ }
93
104
  .genome-spy .tooltip > :last-child {
94
105
  margin-bottom: 0;
95
106
  }
@@ -26,6 +26,11 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
26
26
  transition:
27
27
  transform 0.6s,
28
28
  opacity 0.6s;
29
+
30
+ &:focus,
31
+ &:focus-visible {
32
+ outline: none;
33
+ }
29
34
  }
30
35
 
31
36
  .loading-message {
@@ -121,7 +126,20 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
121
126
 
122
127
  box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);
123
128
 
124
- pointer-events: none;
129
+ &:not(.sticky) {
130
+ pointer-events: none;
131
+ }
132
+
133
+ transition:
134
+ outline-color 0.3s ease-in-out,
135
+ box-shadow 0.3s ease-in-out;
136
+
137
+ outline: 0px solid transparent;
138
+ &.sticky {
139
+ outline: 2px solid black;
140
+ box-shadow: 0px 3px 18px 0px rgba(0, 0, 0, 0.3);
141
+ }
142
+
125
143
  z-index: 100;
126
144
 
127
145
  > :last-child {
@@ -5,13 +5,10 @@ export interface SelectionBase {
5
5
  type: string;
6
6
  }
7
7
 
8
- export interface RangeSelection extends SelectionBase {
9
- type: "range";
8
+ export interface IntervalSelection extends SelectionBase {
9
+ type: "interval";
10
10
 
11
- fields?: string[];
12
- channels?: ChannelWithScale[];
13
-
14
- ranges: number[][];
11
+ intervals: Partial<Record<ChannelWithScale, number[] | null>>;
15
12
  }
16
13
 
17
14
  export interface ProjectedSelection extends SelectionBase {
@@ -38,7 +35,7 @@ export interface MultiPointSelection extends SelectionBase {
38
35
  }
39
36
 
40
37
  export type Selection =
41
- | RangeSelection
38
+ | IntervalSelection
42
39
  | ProjectedSelection
43
40
  | SinglePointSelection
44
41
  | MultiPointSelection;
@@ -1 +1 @@
1
- {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../../src/utils/expression.js"],"names":[],"mappings":"AAkEA;;;;;;;;;;GAUG;AACH,6CAHW,MAAM,sBACJ,kBAAkB,CAgC9B;;YAvCU,MAAM,EAAE;aACR,MAAM,EAAE;UACR,MAAM;;iCAEH,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,qBAAqB,EAAE,KAAK,KAAK,GAAG,CAAC,GAAG,eAAe"}
1
+ {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../../src/utils/expression.js"],"names":[],"mappings":"AAsEA;;;;;;;;;;GAUG;AACH,6CAHW,MAAM,sBACJ,kBAAkB,CAgC9B;;YAvCU,MAAM,EAAE;aACR,MAAM,EAAE;UACR,MAAM;;iCAEH,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,qBAAqB,EAAE,KAAK,KAAK,GAAG,CAAC,GAAG,eAAe"}
@@ -8,6 +8,7 @@ import {
8
8
  isString,
9
9
  lerp,
10
10
  } from "vega-util";
11
+ import { format as d3format } from "d3-format";
11
12
  import smoothstep from "./smoothstep.js";
12
13
  import clamp from "./clamp.js";
13
14
  import linearstep from "./linearstep.js";
@@ -18,6 +19,9 @@ import { selectionTest } from "../selection/selection.js";
18
19
  */
19
20
  const functionContext = {
20
21
  clamp,
22
+ format(/** @type {number} */ value, /** @type {string} */ format) {
23
+ return d3format(format)(value);
24
+ },
21
25
  isArray,
22
26
  isBoolean,
23
27
  isDefined(/** @type {any} */ _) {
@@ -4,16 +4,11 @@ export default class Tooltip {
4
4
  * @param {HTMLElement} container
5
5
  */
6
6
  constructor(container: HTMLElement);
7
- container: HTMLElement;
8
- element: HTMLDivElement;
9
- _visible: boolean;
10
- /** @type {any} */
11
- _previousTooltipDatum: any;
12
- enabledStack: boolean[];
13
- _penaltyUntil: number;
14
- /** @type {[number, number]} */
15
- _lastCoords: [number, number];
16
- _previousMove: number;
7
+ /**
8
+ * @param {boolean} sticky
9
+ */
10
+ set sticky(sticky: boolean);
11
+ get sticky(): boolean;
17
12
  /**
18
13
  * @param {boolean} visible
19
14
  */
@@ -46,5 +41,6 @@ export default class Tooltip {
46
41
  */
47
42
  updateWithDatum<T>(datum: T, converter?: (arg0: T) => Promise<string | HTMLElement | import("lit").TemplateResult>): void;
48
43
  _isPenalty(): boolean;
44
+ #private;
49
45
  }
50
46
  //# sourceMappingURL=tooltip.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../../src/utils/ui/tooltip.js"],"names":[],"mappings":"AAIA,0CAA2C,qBAAqB,CAAC;AAEjE;IACI;;OAEG;IACH,uBAFW,WAAW,EAsBrB;IAnBG,uBAA0B;IAE1B,wBAA4C;IAE5C,kBAAoB;IAGpB,kBAAkB;IAClB,uBADW,GAAG,CACwB;IAEtC,wBAA0B;IAE1B,sBAAsB;IACtB,+BAA+B;IAC/B,aADW,CAAC,MAAM,EAAE,MAAM,CAAC,CACC;IAE5B,sBAAsB;IAK1B;;OAEG;IACH,qBAFW,OAAO,EAOjB;IAED,eATW,OAAO,CAWjB;IAED,uBAEC;IAED;;OAEG;IACH,0BAFW,OAAO,QAOjB;IAED,wBAEC;IAED;;OAEG;IACH,4BAFW,UAAU,QAkCpB;IA/BG,8BAA0D;IAiC9D,wBAiBC;IAED;;OAEG;IACH,oBAFW,MAAM,GAAG,OAAO,KAAK,EAAE,cAAc,GAAG,WAAW,QAiB7D;IAED,cAGC;IAED;;;;;;;OAOG;IACH,gBAFa,CAAC,SAFH,CAAC,cACD,CAAS,IAAC,EAAD,CAAC,KAAE,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAmBlF;IAED,sBAEC;CACJ"}
1
+ {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../../src/utils/ui/tooltip.js"],"names":[],"mappings":"AAIA,0CAA2C,qBAAqB,CAAC;AAEjE;IAsBI;;OAEG;IACH,uBAFW,WAAW,EAUrB;IAED;;OAEG;IACH,mBAFW,OAAO,EAQjB;IAED,cAVW,OAAO,CAYjB;IAED;;OAEG;IACH,qBAFW,OAAO,EAOjB;IAED,eATW,OAAO,CAWjB;IAED,uBAEC;IAED;;OAEG;IACH,0BAFW,OAAO,QAOjB;IAED,wBAEC;IAED;;OAEG;IACH,4BAFW,UAAU,QAsCpB;IA/BG,8BAA2D;IAiC/D,wBAiBC;IAED;;OAEG;IACH,oBAFW,MAAM,GAAG,OAAO,KAAK,EAAE,cAAc,GAAG,WAAW,QAqB7D;IAED,cAGC;IAED;;;;;;;OAOG;IACH,gBAFa,CAAC,SAFH,CAAC,cACD,CAAS,IAAC,EAAD,CAAC,KAAE,OAAO,CAAC,MAAM,GAAG,WAAW,GAAG,OAAO,KAAK,EAAE,cAAc,CAAC,QAmBlF;IAED,sBAEC;;CACJ"}