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,3 +1,4 @@
1
+ /* eslint-disable react/jsx-props-no-spreading */
1
2
  import React from 'react';
2
3
  import { findDOMNode } from 'react-dom';
3
4
  import scrollIntoView from 'dom-scroll-into-view';
@@ -11,6 +11,7 @@ class CustomTrackDialog extends React.PureComponent {
11
11
  const childrenWithProp = [];
12
12
  this.props.children.forEach((Child, i) => {
13
13
  const key = `customTrackDialog_${i}`;
14
+ // eslint-disable-next-line react/jsx-props-no-spreading
14
15
  childrenWithProp.push(<Child key={key} {...this.props.bodyProps[i]} />);
15
16
  });
16
17
 
@@ -33,6 +34,9 @@ CustomTrackDialog.defaultProps = {};
33
34
 
34
35
  CustomTrackDialog.propTypes = {
35
36
  onCancel: PropTypes.func.isRequired,
37
+ title: PropTypes.string,
38
+ bodyProps: PropTypes.array,
39
+ children: PropTypes.array,
36
40
  };
37
41
 
38
42
  export default CustomTrackDialog;
@@ -856,6 +856,7 @@ GenomePositionSearchBox.propTypes = {
856
856
  autocompleteServer: PropTypes.string,
857
857
  chromInfoId: PropTypes.string,
858
858
  chromInfoServer: PropTypes.string,
859
+ chromInfoPath: PropTypes.string,
859
860
  hideAvailableAssemblies: PropTypes.bool,
860
861
  isFocused: PropTypes.bool,
861
862
  pubSub: PropTypes.object,
@@ -1,3 +1,4 @@
1
+ /* eslint-disable react/jsx-props-no-spreading */
1
2
  import PropTypes from 'prop-types';
2
3
  import React from 'react';
3
4
  import { arrayMove } from 'react-sortable-hoc';
@@ -1,3 +1,4 @@
1
+ // @ts-check
1
2
  import { formatPrefix, precisionPrefix } from 'd3-format';
2
3
  import slugid from 'slugid';
3
4
 
@@ -7,14 +8,18 @@ import { colorToHex } from './utils';
7
8
 
8
9
  // Configs
9
10
  import { GLOBALS } from './configs';
11
+ import {
12
+ isResolutionsTilesetInfo,
13
+ isLegacyTilesetInfo,
14
+ } from './utils/type-guards';
10
15
 
11
16
  /**
12
17
  * Format a resolution relative to the highest possible resolution.
13
18
  *
14
19
  * The highest possible resolution determines the granularity of the
15
20
  * formatting (e.g. 20K vs 20000)
16
- * @param {int} resolution The resolution to format (e.g. 30000)
17
- * @param {int} maxResolutionSize The maximum possible resolution (e.g. 1000)
21
+ * @param {number} resolution The resolution to format (e.g. 30000)
22
+ * @param {number} maxResolutionSize The maximum possible resolution (e.g. 1000)
18
23
  *
19
24
  * @returns {string} A formatted resolution string (e.g. "30K")
20
25
  */
@@ -30,11 +35,10 @@ function formatResolutionText(resolution, maxResolutionSize) {
30
35
  * Get a text description of a resolution based on a zoom level
31
36
  * and a list of resolutions
32
37
  *
33
- * @param {list} resolutions: A list of resolutions (e.g. [1000,2000,3000])
34
- * @param {int} zoomLevel: The current zoom level (e.g. 4)
38
+ * @param {Array<number>} resolutions: A list of resolutions (e.g. [1000,2000,3000])
39
+ * @param {number} zoomLevel: The current zoom level (e.g. 4)
35
40
  *
36
- * @returns {string} A formatted string representation of the zoom level
37
- * (e.g. "30K")
41
+ * @returns {string} A formatted string representation of the zoom level (e.g. "30K")
38
42
  */
39
43
  function getResolutionBasedResolutionText(resolutions, zoomLevel) {
40
44
  const sortedResolutions = resolutions.map((x) => +x).sort((a, b) => b - a);
@@ -46,18 +50,14 @@ function getResolutionBasedResolutionText(resolutions, zoomLevel) {
46
50
 
47
51
  /**
48
52
  * Get a text description of the resolution based on the zoom level
49
- * max width of the dataset, the bins per dimension and the maximum
50
- * zoom.
53
+ * max width of the dataset, the bins per dimension and the maximum zoom.
51
54
  *
52
- * @param {int} zoomLevel The current zoomLevel (e.g. 0)
53
- * @param {int} max_width The max width
54
- * (e.g. 2 ** maxZoom * highestResolution * binsPerDimension)
55
- * @param {int} bins_per_dimension The number of bins per tile dimension
56
- * (e.g. 256)
57
- * @param {int} maxZoom The maximum zoom level for this tileset
55
+ * @param {number} zoomLevel - The current zoomLevel (e.g. 0)
56
+ * @param {number} maxWidth - The max width (e.g. 2 ** maxZoom * highestResolution * binsPerDimension)
57
+ * @param {number} binsPerDimension - The number of bins per tile dimension (e.g. 256)
58
+ * @param {number} maxZoom - The maximum zoom level for this tileset
58
59
  *
59
- * @returns {string} A formatted string representation of the zoom level
60
- * (e.g. "30K")
60
+ * @returns {string} A formatted string representation of the zoom level (e.g. "30K")
61
61
  */
62
62
  function getWidthBasedResolutionText(
63
63
  zoomLevel,
@@ -84,14 +84,35 @@ function getWidthBasedResolutionText(
84
84
  return '';
85
85
  }
86
86
 
87
+ /**
88
+ * @typedef PixiTrackOptions
89
+ * @property {string} labelPosition - If the label is to be drawn, where should it be drawn?
90
+ * @property {string} labelText - What should be drawn in the label.
91
+ * If either labelPosition or labelText are false, no label will be drawn.
92
+ * @property {number=} trackBorderWidth
93
+ * @property {string=} trackBorderColor
94
+ * @property {string=} backgroundColor
95
+ * @property {string=} labelColor
96
+ * @property {string=} lineStrokeColor
97
+ * @property {string=} barFillColor
98
+ * @property {string=} name
99
+ * @property {number=} labelTextOpacity
100
+ * @property {string=} labelBackgroundColor
101
+ * @property {number=} labelLeftMargin
102
+ * @property {number=} labelRightMargin
103
+ * @property {number=} labelTopMargin
104
+ * @property {number=} labelBottomMargin
105
+ * @property {number=} labelBackgroundOpacity
106
+ * @property {boolean=} labelShowAssembly
107
+ * @property {boolean=} labelShowResolution
108
+ * @property {string=} dataTransform
109
+ */
110
+
111
+ /** @extends {Track<PixiTrackOptions>} */
87
112
  class PixiTrack extends Track {
88
113
  /**
89
- * @param scene: A PIXI.js scene to draw everything to.
90
- * @param options: A set of options that describe how this track is rendered.
91
- this.pMain.position.x = this.position[0];
92
- * - labelPosition: If the label is to be drawn, where should it be drawn?
93
- * - labelText: What should be drawn in the label. If either labelPosition
94
- * or labelText are false, no label will be drawn.
114
+ * @param {import('./Track').ExtendedTrackContext<{ scene: import('pixi.js').Container}>} context - Includes the PIXI.js scene to draw to.
115
+ * @param {PixiTrackOptions} options - The options for this track.
95
116
  */
96
117
  constructor(context, options) {
97
118
  super(context, options);
@@ -99,27 +120,39 @@ class PixiTrack extends Track {
99
120
 
100
121
  // the PIXI drawing areas
101
122
  // pMain will have transforms applied to it as users scroll to and fro
123
+ /** @type {import('pixi.js').Container} */
102
124
  this.scene = scene;
103
125
 
104
126
  // this option is used to temporarily prevent drawing so that
105
127
  // updates can be batched (e.g. zoomed and options changed)
128
+ /** @type {boolean} */
106
129
  this.delayDrawing = false;
107
130
 
131
+ /** @type {import('pixi.js').Graphics} */
108
132
  this.pBase = new GLOBALS.PIXI.Graphics();
109
-
133
+ /** @type {import('pixi.js').Graphics} */
110
134
  this.pMasked = new GLOBALS.PIXI.Graphics();
135
+ /** @type {import('pixi.js').Graphics} */
111
136
  this.pMask = new GLOBALS.PIXI.Graphics();
137
+ /** @type {import('pixi.js').Graphics} */
112
138
  this.pMain = new GLOBALS.PIXI.Graphics();
113
139
 
114
140
  // for drawing the track label (often its name)
141
+ /** @type {import('pixi.js').Graphics} */
115
142
  this.pBorder = new GLOBALS.PIXI.Graphics();
143
+ /** @type {import('pixi.js').Graphics} */
116
144
  this.pBackground = new GLOBALS.PIXI.Graphics();
145
+ /** @type {import('pixi.js').Graphics} */
117
146
  this.pForeground = new GLOBALS.PIXI.Graphics();
147
+ /** @type {import('pixi.js').Graphics} */
118
148
  this.pLabel = new GLOBALS.PIXI.Graphics();
149
+ /** @type {import('pixi.js').Graphics} */
119
150
  this.pMobile = new GLOBALS.PIXI.Graphics();
151
+ /** @type {import('pixi.js').Graphics} */
120
152
  this.pAxis = new GLOBALS.PIXI.Graphics();
121
153
 
122
154
  // for drawing information on mouseover events
155
+ /** @type {import('pixi.js').Graphics} */
123
156
  this.pMouseOver = new GLOBALS.PIXI.Graphics();
124
157
 
125
158
  this.scene.addChild(this.pBase);
@@ -138,20 +171,28 @@ class PixiTrack extends Track {
138
171
 
139
172
  this.pMasked.mask = this.pMask;
140
173
 
174
+ /** @type {string} */
141
175
  this.prevOptions = '';
142
176
 
143
177
  // pMobile will be a graphics object that is moved around
144
178
  // tracks that wish to use it will replace this.pMain with it
145
179
 
180
+ /** @type {PixiTrackOptions} */
146
181
  this.options = Object.assign(this.options, options);
147
182
 
183
+ /** @type {string} */
148
184
  const labelTextText = this.getName();
149
-
185
+ /** @type {string} */
150
186
  this.labelTextFontFamily = 'Arial';
187
+ /** @type {number} */
151
188
  this.labelTextFontSize = 12;
152
- // Used to avoid label/colormap clashes
189
+ /**
190
+ * Used to avoid label/colormap clashes
191
+ * @type {number}
192
+ */
153
193
  this.labelXOffset = 0;
154
194
 
195
+ /** @type {import('pixi.js').Text} */
155
196
  this.labelText = new GLOBALS.PIXI.Text(labelTextText, {
156
197
  fontSize: `${this.labelTextFontSize}px`,
157
198
  fontFamily: this.labelTextFontFamily,
@@ -159,6 +200,7 @@ class PixiTrack extends Track {
159
200
  });
160
201
  this.pLabel.addChild(this.labelText);
161
202
 
203
+ /** @type {import('pixi.js').Text} */
162
204
  this.errorText = new GLOBALS.PIXI.Text('', {
163
205
  fontSize: '12px',
164
206
  fontFamily: 'Arial',
@@ -167,12 +209,19 @@ class PixiTrack extends Track {
167
209
  this.errorText.anchor.x = 0.5;
168
210
  this.errorText.anchor.y = 0.5;
169
211
  this.pLabel.addChild(this.errorText);
212
+ /** @type {string} */
213
+ this.errorTextText = '';
214
+ /** @type {boolean} */
215
+ this.flipText = false;
216
+ /** @type {import('./types').TilesetInfo | undefined} */
217
+ this.tilesetInfo = undefined;
170
218
  }
171
219
 
172
220
  setLabelText() {
173
221
  // will be drawn in draw() anyway
174
222
  }
175
223
 
224
+ /** @param {[number, number]} newPosition */
176
225
  setPosition(newPosition) {
177
226
  this.position = newPosition;
178
227
 
@@ -183,6 +232,7 @@ class PixiTrack extends Track {
183
232
  this.setForeground();
184
233
  }
185
234
 
235
+ /** @param {[number, number]} newDimensions */
186
236
  setDimensions(newDimensions) {
187
237
  super.setDimensions(newDimensions);
188
238
 
@@ -193,6 +243,10 @@ class PixiTrack extends Track {
193
243
  this.setForeground();
194
244
  }
195
245
 
246
+ /**
247
+ * @param {[number, number]} position
248
+ * @param {[number, number]} dimensions
249
+ */
196
250
  setMask(position, dimensions) {
197
251
  this.pMask.clear();
198
252
  this.pMask.beginFill();
@@ -320,6 +374,8 @@ class PixiTrack extends Track {
320
374
 
321
375
  graphics.clear();
322
376
 
377
+ // TODO(Trevor): I don't think this can ever be true. Options are always defined,
378
+ // and options.labelPosition can't be defined if this.options is undefined.
323
379
  if (
324
380
  !this.options ||
325
381
  !this.options.labelPosition ||
@@ -330,11 +386,11 @@ class PixiTrack extends Track {
330
386
  return;
331
387
  }
332
388
 
389
+ const { labelBackgroundColor = 'white', labelBackgroundOpacity = 0.5 } =
390
+ this.options;
333
391
  graphics.beginFill(
334
- colorToHex(this.options.labelBackgroundColor || 'white'),
335
- +this.options.labelBackgroundOpacity >= 0
336
- ? +this.options.labelBackgroundOpacity
337
- : 0.5,
392
+ colorToHex(labelBackgroundColor),
393
+ +labelBackgroundOpacity,
338
394
  );
339
395
 
340
396
  const fontColor = colorToHex(this.getLabelColor());
@@ -356,8 +412,7 @@ class PixiTrack extends Track {
356
412
 
357
413
  if (
358
414
  this.options.labelShowResolution &&
359
- this.tilesetInfo &&
360
- this.tilesetInfo.max_width &&
415
+ isLegacyTilesetInfo(this.tilesetInfo) &&
361
416
  this.tilesetInfo.bins_per_dimension
362
417
  ) {
363
418
  const formattedResolution = getWidthBasedResolutionText(
@@ -370,8 +425,7 @@ class PixiTrack extends Track {
370
425
  labelTextText += `\n[Current data resolution: ${formattedResolution}]`;
371
426
  } else if (
372
427
  this.options.labelShowResolution &&
373
- this.tilesetInfo &&
374
- this.tilesetInfo.resolutions
428
+ isResolutionsTilesetInfo(this.tilesetInfo)
375
429
  ) {
376
430
  const formattedResolution = getResolutionBasedResolutionText(
377
431
  this.tilesetInfo.resolutions,
@@ -418,10 +472,12 @@ class PixiTrack extends Track {
418
472
  this.labelText.scale.x = -1;
419
473
  }
420
474
 
421
- const labelLeftMargin = +this.options.labelLeftMargin || 0;
422
- const labelRightMargin = +this.options.labelRightMargin || 0;
423
- const labelTopMargin = +this.options.labelTopMargin || 0;
424
- const labelBottomMargin = +this.options.labelBottomMargin || 0;
475
+ const {
476
+ labelLeftMargin = 0,
477
+ labelRightMargin = 0,
478
+ labelTopMargin = 0,
479
+ labelBottomMargin = 0,
480
+ } = this.options;
425
481
 
426
482
  if (this.options.labelPosition === 'topLeft') {
427
483
  this.labelText.x = this.position[0] + labelLeftMargin + this.labelXOffset;
@@ -575,6 +631,7 @@ class PixiTrack extends Track {
575
631
  }
576
632
  }
577
633
 
634
+ /** @param {PixiTrackOptions} options */
578
635
  rerender(options) {
579
636
  this.options = options;
580
637
 
@@ -598,8 +655,8 @@ class PixiTrack extends Track {
598
655
  /**
599
656
  * Export an SVG representation of this track
600
657
  *
601
- * @returns {Array} The two returned DOM nodes are both SVG
602
- * elements [base,track]. Base is a parent which contains track as a
658
+ * @returns {[HTMLElement, HTMLElement]} The two returned DOM nodes are both SVG
659
+ * elements [base, track]. Base is a parent which contains track as a
603
660
  * child. Track is clipped with a clipping rectangle contained in base.
604
661
  *
605
662
  */
@@ -693,15 +750,15 @@ class PixiTrack extends Track {
693
750
  this.options.labelPosition === 'topRight'
694
751
  ) {
695
752
  const dy = ddy + (i + 1) * (this.labelTextFontSize + 2);
696
- text.setAttribute('dy', dy);
753
+ text.setAttribute('dy', String(dy));
697
754
  } else if (
698
755
  this.options.labelPosition === 'bottomLeft' ||
699
756
  this.options.labelPosition === 'bottomRight'
700
757
  ) {
701
- text.setAttribute('dy', ddy + i * (this.labelTextFontSize + 2));
758
+ text.setAttribute('dy', String(ddy + i * (this.labelTextFontSize + 2)));
702
759
  }
703
760
 
704
- text.setAttribute('fill', this.options.labelColor);
761
+ text.setAttribute('fill', this.options.labelColor ?? '');
705
762
 
706
763
  if (this.labelText.anchor.x === 0.5) {
707
764
  text.setAttribute('text-anchor', 'middle');
@@ -721,6 +778,13 @@ class PixiTrack extends Track {
721
778
  // contents
722
779
  return [gBase, gTrack];
723
780
  }
781
+
782
+ /**
783
+ * @returns {number}
784
+ */
785
+ calculateZoomLevel() {
786
+ throw new Error('Must be implemented by subclass');
787
+ }
724
788
  }
725
789
 
726
790
  export default PixiTrack;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable react/jsx-props-no-spreading */
1
2
  import React from 'react';
2
3
  import { SortableContainer } from 'react-sortable-hoc';
3
4
 
@@ -2388,6 +2388,8 @@ TiledPlot.propTypes = {
2388
2388
  canvasElement: PropTypes.object,
2389
2389
  chooseTrackHandler: PropTypes.func,
2390
2390
  chromInfoPath: PropTypes.string,
2391
+ customDialog: PropTypes.array,
2392
+ closeCustomDialog: PropTypes.func,
2391
2393
  disableTrackMenu: PropTypes.bool,
2392
2394
  dragging: PropTypes.bool,
2393
2395
  draggingHappening: PropTypes.bool,