higlass 1.13.0 → 1.13.2

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.
@@ -1,41 +1,62 @@
1
+ // @ts-check
1
2
  import { scaleLinear } from 'd3-scale';
2
3
  import { fake as fakePubSub } from './hocs/with-pub-sub';
3
4
 
4
5
  // Services
5
6
  import { isWithin } from './utils';
6
7
 
8
+ /**
9
+ * @typedef TrackContext
10
+ * @property {string} id - The track ID.
11
+ * @property {import('pub-sub-es').PubSub & { __fake__?: boolean }} [pubSub] - The pub-sub channel.
12
+ * @property {() => import('./types').Theme} [getTheme] - A function that returns the current theme.
13
+ */
14
+
15
+ /**
16
+ * @template T
17
+ * @typedef {T & TrackContext} ExtendedTrackContext
18
+ */
19
+
20
+ /** @template Options */
7
21
  class Track {
8
- constructor(context) {
22
+ /**
23
+ * @param {TrackContext} context
24
+ * @param {Options} options
25
+ */
26
+ constructor(context, options) {
9
27
  this.context = context;
10
28
 
11
29
  const { id, pubSub, getTheme } = context;
12
- if (pubSub) {
13
- this.pubSub = pubSub;
14
- } else {
15
- this.pubSub = fakePubSub;
16
- }
30
+ /** @type {import('pub-sub-es').PubSub} */
31
+ this.pubSub = pubSub ?? fakePubSub;
17
32
 
33
+ /** @type {string} */
18
34
  this.id = id;
35
+ /** @type {import('./types').Scale} */
19
36
  this._xScale = scaleLinear();
37
+ /** @type {import('./types').Scale} */
20
38
  this._yScale = scaleLinear();
21
39
 
22
40
  // reference scales used for tracks that can translate and scale
23
41
  // their graphics
24
42
  // They will draw their graphics on the reference scales and then translate
25
43
  // and pan them as needed
44
+ /** @type {import('./types').Scale} */
26
45
  this._refXScale = scaleLinear();
46
+ /** @type {import('./types').Scale} */
27
47
  this._refYScale = scaleLinear();
28
48
 
49
+ /** @type {[number, number]} */
29
50
  this.position = [0, 0];
51
+ /** @type {[number, number]} */
30
52
  this.dimensions = [1, 1];
31
- this.options = {};
53
+ /** @type {Options} */
54
+ this.options = options;
55
+ /** @type {Array<import('pub-sub-es').Subscription>} */
32
56
  this.pubSubs = [];
33
57
 
34
- if (getTheme) {
35
- this.getTheme = getTheme;
36
- } else {
37
- this.getTheme = () => {};
38
- }
58
+ /** @type {() => (import('./types').Theme | undefined)} */
59
+ this.getTheme = getTheme ?? (() => undefined);
39
60
 
40
61
  this.pubSubs.push(
41
62
  this.pubSub.subscribe(
@@ -43,14 +64,16 @@ class Track {
43
64
  this.defaultMouseMoveHandler.bind(this),
44
65
  ),
45
66
  );
67
+
68
+ this.isLeftModified = false;
46
69
  }
47
70
 
48
71
  /**
49
72
  * Check if a 2d location (x, y) is within the bounds of this track.
50
73
  *
51
- * @param {Number} x X position to be tested.
52
- * @param {Number} y Y position to be tested.
53
- * @return {Boolean} If `true` location is within the track.
74
+ * @param {number} x - X position to be tested.
75
+ * @param {number} y - Y position to be tested.
76
+ * @return {boolean} If `true` location is within the track.
54
77
  */
55
78
  isWithin(x, y) {
56
79
  let xx = x;
@@ -75,14 +98,26 @@ class Track {
75
98
  );
76
99
  }
77
100
 
101
+ /**
102
+ * Get a property from the track.
103
+ * @template {keyof this} T
104
+ * @param {T} prop - The property to get.
105
+ * @return {() => this[T]}
106
+ */
78
107
  getProp(prop) {
79
108
  return () => this[prop];
80
109
  }
81
110
 
82
111
  getData() {}
83
112
 
84
- /** Capture click events. x and y are relative to the track
85
- * position */
113
+ /**
114
+ * Capture click events. x and y are relative to the track position
115
+ * @template T
116
+ * @param {number} x - X position of the click event.
117
+ * @param {number} y - Y position of the click event.
118
+ * @param {T} evt - The event.
119
+ * @return {{ type: 'generic', event: T, payload: null }}
120
+ */
86
121
  click(x, y, evt) {
87
122
  return {
88
123
  type: 'generic',
@@ -94,10 +129,12 @@ class Track {
94
129
  /** There was a click event outside the track * */
95
130
  clickOutside() {}
96
131
 
132
+ /** @returns {[number, number]} */
97
133
  getDimensions() {
98
134
  return this.dimensions;
99
135
  }
100
136
 
137
+ /** @param {[number, number]} newDimensions */
101
138
  setDimensions(newDimensions) {
102
139
  this.dimensions = newDimensions;
103
140
 
@@ -105,82 +142,136 @@ class Track {
105
142
  this._yScale.range([0, this.dimensions[1]]);
106
143
  }
107
144
 
145
+ /**
146
+ * @overload
147
+ * @return {import('./types').Scale}
148
+ */
149
+ /**
150
+ * @overload
151
+ * @param {import('./types').Scale} scale
152
+ * @return {this}
153
+ */
108
154
  /**
109
155
  * Either get or set the reference xScale
156
+ *
157
+ * @param {import('./types').Scale=} scale
158
+ * @return {import('./types').Scale | this}
110
159
  */
111
- refXScale(_) {
112
- if (!arguments.length) return this._refXScale;
113
-
114
- this._refXScale = _;
115
-
160
+ refXScale(scale) {
161
+ if (!scale) return this._refXScale;
162
+ this._refXScale = scale;
116
163
  return this;
117
164
  }
118
165
 
166
+ /**
167
+ * @overload
168
+ * @return {import('./types').Scale}
169
+ */
170
+ /**
171
+ * @overload
172
+ * @param {import('./types').Scale} scale
173
+ * @return {this}
174
+ */
119
175
  /**
120
176
  * Either get or set the reference yScale
177
+ *
178
+ * @param {import('./types').Scale=} scale
179
+ * @return {import('./types').Scale | this}
121
180
  */
122
- refYScale(_) {
123
- if (!arguments.length) return this._refYScale;
124
-
125
- this._refYScale = _;
126
-
181
+ refYScale(scale) {
182
+ if (!scale) return this._refYScale;
183
+ this._refYScale = scale;
127
184
  return this;
128
185
  }
129
186
 
187
+ /**
188
+ * @overload
189
+ * @return {import('./types').Scale}
190
+ */
191
+ /**
192
+ * @overload
193
+ * @param {import('./types').Scale} scale
194
+ * @return {this}
195
+ */
130
196
  /**
131
197
  * Either get or set the xScale
198
+ *
199
+ * @param {import('./types').Scale=} scale
200
+ * @return {import('./types').Scale | this}
132
201
  */
133
- xScale(_) {
134
- if (!arguments.length) return this._xScale;
135
-
136
- this._xScale = _;
137
-
202
+ xScale(scale) {
203
+ if (!scale) return this._xScale;
204
+ this._xScale = scale;
138
205
  return this;
139
206
  }
140
207
 
208
+ /**
209
+ * @overload
210
+ * @return {import('./types').Scale}
211
+ */
212
+ /**
213
+ * @overload
214
+ * @param {import('./types').Scale} scale
215
+ * @return {this}
216
+ */
141
217
  /**
142
218
  * Either get or set the yScale
219
+ *
220
+ * @param {import('./types').Scale=} scale
221
+ * @return {import('./types').Scale | this}
143
222
  */
144
- yScale(_) {
145
- if (!arguments.length) {
146
- return this._yScale;
147
- }
148
-
149
- this._yScale = _;
150
-
223
+ yScale(scale) {
224
+ if (!scale) return this._yScale;
225
+ this._yScale = scale;
151
226
  return this;
152
227
  }
153
228
 
229
+ /**
230
+ * @param {import('./types').Scale} newXScale
231
+ * @param {import('./types').Scale} newYScale
232
+ * @returns {void}
233
+ */
154
234
  zoomed(newXScale, newYScale) {
155
235
  this.xScale(newXScale);
156
236
  this.yScale(newYScale);
157
237
  }
158
238
 
239
+ /**
240
+ * @param {import('./types').Scale} refXScale
241
+ * @param {import('./types').Scale} refYScale
242
+ * @returns {void}
243
+ */
159
244
  refScalesChanged(refXScale, refYScale) {
160
245
  this._refXScale = refXScale;
161
246
  this._refYScale = refYScale;
162
247
  }
163
248
 
249
+ /** @returns {void} */
164
250
  draw() {}
165
251
 
252
+ /** @returns {[number, number]} */
166
253
  getPosition() {
167
254
  return this.position;
168
255
  }
169
256
 
257
+ /**
258
+ * @param {[number, number]} newPosition
259
+ * @returns {void}
260
+ */
170
261
  setPosition(newPosition) {
171
262
  this.position = newPosition;
172
263
  }
173
264
 
174
- /*
265
+ /**
175
266
  * A blank handler for MouseMove / Zoom events. Should be overriden
176
267
  * by individual tracks to provide
177
268
  *
178
- * @param {obj} evt:
179
- *
180
- * @returns nothing
269
+ * @param {{}} evt
270
+ * @returns {void}
181
271
  */
182
272
  defaultMouseMoveHandler(evt) {}
183
273
 
274
+ /** @returns {void} */
184
275
  remove() {
185
276
  // Clear all pubSub subscriptions
186
277
  this.pubSubs.forEach((subscription) =>
@@ -189,19 +280,36 @@ class Track {
189
280
  this.pubSubs = [];
190
281
  }
191
282
 
192
- rerender() {}
283
+ /**
284
+ * @param {Options} options
285
+ * @returns {void}
286
+ */
287
+ rerender(options) {}
193
288
 
194
- /*
289
+ /**
195
290
  * This function is for seeing whether this track should respond
196
291
  * to events at this mouse position. The difference to `isWithin()` is that it
197
292
  * can be overwritten if a track is inactive for example.
293
+ *
294
+ * @param {number} x - X position to be tested.
295
+ * @param {number} y - Y position to be tested.
296
+ * @returns {boolean}
198
297
  */
199
298
  respondsToPosition(x, y) {
200
299
  return this.isWithin(x, y);
201
300
  }
202
301
 
302
+ /**
303
+ * @param {number} trackY
304
+ * @param {number} kMultiplier
305
+ * @returns {void}
306
+ */
203
307
  zoomedY(trackY, kMultiplier) {}
204
308
 
309
+ /**
310
+ * @param {number} dY
311
+ * @returns {void}
312
+ */
205
313
  movedY(dY) {}
206
314
  }
207
315
 
@@ -91,6 +91,7 @@ const SCROLL_TIMEOUT = 100;
91
91
  /** @typedef {import('./types').Scale} Scale */
92
92
  /** @typedef {import('./types').TrackConfig} TrackConfig */
93
93
  /** @typedef {import('./types').TrackObject} TrackObject */
94
+ /** @typedef {import('./types').TilesetInfo} TilesetInfo */
94
95
 
95
96
  /** @typedef {TrackRenderer["setCenter"]} SetCentersFunction */
96
97
  /** @typedef {(x: Scale, y: Scale) => [Scale, Scale]} ProjectorFunction */
@@ -104,8 +105,6 @@ const SCROLL_TIMEOUT = 100;
104
105
  * @property {number} left
105
106
  */
106
107
 
107
- /** @typedef {Record<string, unknown>} TilesetInfo */
108
-
109
108
  /**
110
109
  * @typedef MetaPluginTrackContext
111
110
  * @property {(trackId: string) => TrackObject | undefined} getTrackObject
@@ -133,7 +132,7 @@ const SCROLL_TIMEOUT = 100;
133
132
  * @property {() => void} onMouseMoveZoom
134
133
  * @property {string} chromInfoPath
135
134
  * @property {() => boolean} isShowGlobalMousePosition
136
- * @property {() => (string | typeof THEME_DARK)} getTheme
135
+ * @property {() => import('./types').Theme} getTheme
137
136
  * @property {unknown=} AVAILABLE_FOR_PLUGINS
138
137
  * @property {(HTMLDivElement | null)=} baseEl
139
138
  * @property {TrackConfig=} definition
@@ -197,7 +196,7 @@ const SCROLL_TIMEOUT = 100;
197
196
  * @property {import('pub-sub-es').PubSub} pubSub
198
197
  * @property {(func: SetCentersFunction) => void} setCentersFunction
199
198
  * @property {HTMLElement} svgElement
200
- * @property {string | typeof THEME_DARK} theme
199
+ * @property {import('./types').Theme} theme
201
200
  * @property {number} topHeight
202
201
  * @property {number} topHeightNoGallery
203
202
  * @property {{ backgroundColor?: string }} viewOptions
@@ -1856,17 +1855,15 @@ class TrackRenderer extends React.Component {
1856
1855
  context.projectionYDomain = track.projectionYDomain;
1857
1856
  }
1858
1857
 
1859
- const options = track.options;
1860
-
1861
1858
  switch (track.type) {
1862
1859
  case 'left-axis':
1863
- return new LeftAxisTrack(context, options);
1860
+ return new LeftAxisTrack(context, track.options);
1864
1861
 
1865
1862
  case 'top-axis':
1866
- return new TopAxisTrack(context, options);
1863
+ return new TopAxisTrack(context, track.options);
1867
1864
 
1868
1865
  case 'heatmap':
1869
- return new HeatmapTiledPixiTrack(context, options);
1866
+ return new HeatmapTiledPixiTrack(context, track.options);
1870
1867
 
1871
1868
  case 'multivec':
1872
1869
  case 'vector-heatmap':
@@ -1874,46 +1871,46 @@ class TrackRenderer extends React.Component {
1874
1871
  case 'horizontal-vector-heatmap': // legacy, included for backwards compatiblity
1875
1872
  case 'vertical-multivec': // legacy, included for backwards compatiblity
1876
1873
  case 'vertical-vector-heatmap': // legacy, included for backwards compatiblity
1877
- return new HorizontalMultivecTrack(context, options);
1874
+ return new HorizontalMultivecTrack(context, track.options);
1878
1875
 
1879
1876
  case '1d-heatmap':
1880
1877
  case 'horizontal-1d-heatmap': // legacy, included for backwards compatiblity
1881
1878
  case 'vertical-1d-heatmap': // legacy, included for backwards compatiblity
1882
- return new Horizontal1dHeatmapTrack(context, options);
1879
+ return new Horizontal1dHeatmapTrack(context, track.options);
1883
1880
 
1884
1881
  case 'line':
1885
1882
  case 'horizontal-line': // legacy, included for backwards compatiblity
1886
1883
  case 'vertical-line': // legacy, included for backwards compatiblity
1887
- return new HorizontalLine1DPixiTrack(context, options);
1884
+ return new HorizontalLine1DPixiTrack(context, track.options);
1888
1885
 
1889
1886
  case 'point':
1890
1887
  case 'horizontal-point': // legacy, included for backwards compatiblity
1891
1888
  case 'vertical-point': // legacy, included for backwards compatiblity
1892
- return new HorizontalPoint1DPixiTrack(context, options);
1889
+ return new HorizontalPoint1DPixiTrack(context, track.options);
1893
1890
 
1894
1891
  case 'bar':
1895
1892
  case 'horizontal-bar': // legacy, included for backwards compatiblity
1896
1893
  case 'vertical-bar': // legacy, included for backwards compatiblity
1897
- return new BarTrack(context, options);
1894
+ return new BarTrack(context, track.options);
1898
1895
 
1899
1896
  case 'divergent-bar':
1900
1897
  case 'horizontal-divergent-bar': // legacy, included for backwards compatiblity
1901
1898
  case 'vertical-divergent-bar': // legacy, included for backwards compatiblity
1902
- return new DivergentBarTrack(context, options);
1899
+ return new DivergentBarTrack(context, track.options);
1903
1900
 
1904
1901
  case 'horizontal-1d-tiles':
1905
- return new IdHorizontal1DTiledPixiTrack(context, options);
1902
+ return new IdHorizontal1DTiledPixiTrack(context, track.options);
1906
1903
 
1907
1904
  case 'vertical-1d-tiles':
1908
- return new IdVertical1DTiledPixiTrack(context, options);
1905
+ return new IdVertical1DTiledPixiTrack(context, track.options);
1909
1906
 
1910
1907
  case '2d-tiles':
1911
- return new Id2DTiledPixiTrack(context, options);
1908
+ return new Id2DTiledPixiTrack(context, track.options);
1912
1909
 
1913
1910
  case 'stacked-interval':
1914
1911
  case 'top-stacked-interval': // legacy, included for backwards compatiblity
1915
1912
  case 'left-stacked-interval': // legacy, included for backwards compatiblity
1916
- return new CNVIntervalTrack(context, options);
1913
+ return new CNVIntervalTrack(context, track.options);
1917
1914
 
1918
1915
  case 'viewport-projection-center':
1919
1916
  // TODO: Fix this so that these functions are defined somewhere else
@@ -1925,9 +1922,9 @@ class TrackRenderer extends React.Component {
1925
1922
  context.registerViewportChanged = track.registerViewportChanged;
1926
1923
  context.removeViewportChanged = track.removeViewportChanged;
1927
1924
  context.setDomainsCallback = track.setDomainsCallback;
1928
- return new ViewportTracker2D(context, options);
1925
+ return new ViewportTracker2D(context, track.options);
1929
1926
  }
1930
- return new Track(context);
1927
+ return new Track(context, {});
1931
1928
 
1932
1929
  case 'viewport-projection-horizontal':
1933
1930
  // TODO: Fix this so that these functions are defined somewhere else
@@ -1939,9 +1936,9 @@ class TrackRenderer extends React.Component {
1939
1936
  context.registerViewportChanged = track.registerViewportChanged;
1940
1937
  context.removeViewportChanged = track.removeViewportChanged;
1941
1938
  context.setDomainsCallback = track.setDomainsCallback;
1942
- return new ViewportTrackerHorizontal(context, options);
1939
+ return new ViewportTrackerHorizontal(context, track.options);
1943
1940
  }
1944
- return new Track(context);
1941
+ return new Track(context, {});
1945
1942
 
1946
1943
  case 'viewport-projection-vertical':
1947
1944
  // TODO: Fix this so that these functions are defined somewhere else
@@ -1953,37 +1950,37 @@ class TrackRenderer extends React.Component {
1953
1950
  context.registerViewportChanged = track.registerViewportChanged;
1954
1951
  context.removeViewportChanged = track.removeViewportChanged;
1955
1952
  context.setDomainsCallback = track.setDomainsCallback;
1956
- return new ViewportTrackerVertical(context, options);
1953
+ return new ViewportTrackerVertical(context, track.options);
1957
1954
  }
1958
- return new Track(context);
1955
+ return new Track(context, {});
1959
1956
 
1960
1957
  case 'gene-annotations':
1961
1958
  case 'horizontal-gene-annotations': // legacy, included for backwards compatiblity
1962
1959
  case 'vertical-gene-annotations': // legacy, included for backwards compatiblity
1963
- return new HorizontalGeneAnnotationsTrack(context, options);
1960
+ return new HorizontalGeneAnnotationsTrack(context, track.options);
1964
1961
 
1965
1962
  case '2d-rectangle-domains':
1966
1963
  case 'arrowhead-domains':
1967
- return new ArrowheadDomainsTrack(context, options);
1964
+ return new ArrowheadDomainsTrack(context, track.options);
1968
1965
 
1969
1966
  case 'horizontal-1d-annotations':
1970
- return new Annotations1dTrack(context, options);
1967
+ return new Annotations1dTrack(context, track.options);
1971
1968
 
1972
1969
  case 'vertical-1d-annotations':
1973
1970
  // Fix this: LeftTrackModifier is doing a whole bunch of things not
1974
1971
  // needed by this track but the current setup is not consistent.
1975
- return new Annotations1dTrack(context, options, true);
1972
+ return new Annotations1dTrack(context, track.options, true);
1976
1973
 
1977
1974
  case '2d-annotations':
1978
- return new Annotations2dTrack(context, options);
1975
+ return new Annotations2dTrack(context, track.options);
1979
1976
 
1980
1977
  case 'linear-2d-rectangle-domains':
1981
1978
  case 'horizontal-2d-rectangle-domains': // legacy, included for backwards compatiblity
1982
1979
  case 'vertical-2d-rectangle-domains': // legacy, included for backwards compatiblity
1983
- return new Horizontal2DDomainsTrack(context, options);
1980
+ return new Horizontal2DDomainsTrack(context, track.options);
1984
1981
 
1985
1982
  case 'square-markers':
1986
- return new SquareMarkersTrack(context, options);
1983
+ return new SquareMarkersTrack(context, track.options);
1987
1984
 
1988
1985
  case 'combined':
1989
1986
  // @ts-expect-error - FIXME: Our typing should be able to narrow track config
@@ -1993,80 +1990,84 @@ class TrackRenderer extends React.Component {
1993
1990
  return new CombinedTrack(context);
1994
1991
 
1995
1992
  case '2d-chromosome-labels':
1996
- return new Chromosome2DLabels(context, options);
1993
+ return new Chromosome2DLabels(context, track.options);
1997
1994
 
1998
1995
  case 'horizontal-chromosome-grid':
1999
1996
  context.orientation = '1d-horizontal';
2000
- return new ChromosomeGrid(context, options);
1997
+ return new ChromosomeGrid(context, track.options);
2001
1998
 
2002
1999
  case 'vertical-chromosome-grid':
2003
2000
  context.orientation = '1d-vertical';
2004
- return new ChromosomeGrid(context, options);
2001
+ return new ChromosomeGrid(context, track.options);
2005
2002
 
2006
2003
  case '2d-chromosome-grid':
2007
- return new ChromosomeGrid(context, options);
2004
+ return new ChromosomeGrid(context, track.options);
2008
2005
 
2009
2006
  case 'chromosome-labels':
2010
2007
  case 'horizontal-chromosome-labels': // legacy, included for backwards compatiblity
2011
2008
  case 'vertical-chromosome-labels': // legacy, included for backwards compatiblity
2012
2009
  // chromInfoPath is passed in for backwards compatibility
2013
2010
  // it can be used to provide custom chromosome sizes
2014
- return new HorizontalChromosomeLabels(context, options);
2011
+ return new HorizontalChromosomeLabels(context, track.options);
2015
2012
 
2016
2013
  case 'linear-heatmap':
2017
2014
  case 'horizontal-heatmap': // legacy, included for backwards compatiblity
2018
2015
  case 'vertical-heatmap': // legacy, included for backwards compatiblity
2019
- return new HorizontalHeatmapTrack(context, options);
2016
+ return new HorizontalHeatmapTrack(context, track.options);
2020
2017
 
2021
2018
  case '2d-chromosome-annotations':
2022
- return new Chromosome2DAnnotations(context, options);
2019
+ return new Chromosome2DAnnotations(context, track.options);
2023
2020
 
2024
2021
  case '1d-value-interval':
2025
2022
  case 'horizontal-1d-value-interval': // legacy, included for backwards compatiblity
2026
2023
  case 'vertical-1d-value-interval': // legacy, included for backwards compatiblity
2027
- return new ValueIntervalTrack(context, options);
2024
+ return new ValueIntervalTrack(context, track.options);
2028
2025
 
2029
2026
  case 'osm':
2030
2027
  case 'osm-tiles':
2031
- return new OSMTilesTrack(context, options);
2028
+ return new OSMTilesTrack(context, track.options);
2032
2029
 
2033
2030
  case 'osm-2d-tile-ids':
2034
- return new OSMTileIdsTrack(context, options);
2031
+ return new OSMTileIdsTrack(context, track.options);
2035
2032
 
2036
2033
  case 'mapbox':
2037
2034
  case 'mapbox-tiles':
2038
- return new MapboxTilesTrack(context, options);
2035
+ return new MapboxTilesTrack(context, track.options);
2039
2036
 
2040
2037
  case 'raster-tiles':
2041
- return new RasterTilesTrack(context, options);
2038
+ return new RasterTilesTrack(context, track.options);
2042
2039
 
2043
2040
  case 'bedlike':
2044
2041
  case 'vertical-bedlike': // legacy, included for backwards compatiblity
2045
- return new BedLikeTrack(context, options);
2042
+ return new BedLikeTrack(context, track.options);
2046
2043
 
2047
2044
  case 'overlay-track':
2048
- return new OverlayTrack(context, options);
2045
+ return new OverlayTrack(context, track.options);
2049
2046
 
2050
2047
  case 'overlay-chromosome-grid-track':
2051
2048
  context.isOverlay = true;
2052
- return new ChromosomeGrid(context, options);
2049
+ return new ChromosomeGrid(context, track.options);
2053
2050
 
2054
2051
  case 'horizontal-rule':
2055
- return new HorizontalRule(context, options);
2052
+ return new HorizontalRule(context, track.options);
2056
2053
 
2057
2054
  case 'vertical-rule':
2058
- return new VerticalRule(context, options);
2055
+ return new VerticalRule(context, track.options);
2059
2056
 
2060
2057
  case 'cross-rule':
2061
2058
  // This needs to be harmonized.
2062
2059
  context.x = track.x;
2063
2060
  context.y = track.y;
2064
- return new CrossRule(context, options);
2061
+ return new CrossRule(context, track.options);
2065
2062
 
2066
2063
  case 'simple-svg':
2067
- return new SVGTrack(context, options);
2068
- case 'empty':
2064
+ return new SVGTrack(context, track.options);
2065
+ case 'empty': {
2066
+ /** @type {import('./PixiTrack').PixiTrackOptions} */
2067
+ // @ts-expect-error - We need a way to relate the track type and track.options.
2068
+ const options = track.options;
2069
2069
  return new PixiTrack(context, options);
2070
+ }
2070
2071
 
2071
2072
  default: {
2072
2073
  // Check if a plugin track is available
@@ -2091,7 +2092,7 @@ class TrackRenderer extends React.Component {
2091
2092
  return new pluginTrack.track( // eslint-disable-line new-cap
2092
2093
  this.availableForPlugins,
2093
2094
  context,
2094
- options,
2095
+ track.options,
2095
2096
  );
2096
2097
  } catch (e) {
2097
2098
  console.error(
@@ -1,3 +1,4 @@
1
+ /* eslint-disable react/jsx-props-no-spreading */
1
2
  import React from 'react';
2
3
 
3
4
  import { toVoid } from '../utils';
@@ -1,12 +1,15 @@
1
+ /* eslint-disable react/jsx-props-no-spreading */
1
2
  import React from 'react';
2
3
 
3
4
  import { toVoid } from '../utils';
4
5
 
6
+ /** @type {import('pub-sub-es').PubSub & { __fake__: true }} */
5
7
  const fake = {
6
8
  __fake__: true,
7
9
  publish: toVoid,
8
- subscribe: toVoid,
10
+ subscribe: () => ({ event: 'fake', handler: toVoid }),
9
11
  unsubscribe: toVoid,
12
+ clear: toVoid,
10
13
  };
11
14
 
12
15
  const { Provider, Consumer } = React.createContext(fake);
@@ -1,3 +1,4 @@
1
+ /* eslint-disable react/jsx-props-no-spreading */
1
2
  import React from 'react';
2
3
 
3
4
  import { toVoid } from '../utils';
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import PropTypes from 'prop-types';
2
3
  import { select } from 'd3-selection';
3
4
  import classes from '../styles/ViewHeader.module.scss';
4
5
 
@@ -397,3 +398,8 @@ export function SearchIcon({ theStyle, onClick }) {
397
398
  </svg>
398
399
  );
399
400
  }
401
+
402
+ SearchIcon.propTypes = {
403
+ theStyle: PropTypes.string,
404
+ onClick: PropTypes.func,
405
+ };
@@ -52,7 +52,7 @@ fetchTilesPool.run(function(params, done) {
52
52
  }, [workerPath]);
53
53
  */
54
54
 
55
- const sessionId = slugid.nice();
55
+ const sessionId = import.meta.env.DEV ? 'dev' : slugid.nice();
56
56
  export let requestsInFlight = 0; // eslint-disable-line import/no-mutable-exports
57
57
  export let authHeader = null; // eslint-disable-line import/no-mutable-exports
58
58