igv 3.0.1 → 3.0.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.
package/dist/igv.js CHANGED
@@ -19021,13 +19021,13 @@
19021
19021
  if (Array.isArray(trackViewOrTrackViewList)) {
19022
19022
  dataRange = { min: Number.MAX_SAFE_INTEGER, max:-Number.MAX_SAFE_INTEGER };
19023
19023
  for (const trackView of trackViewOrTrackViewList) {
19024
- if (trackView.dataRange) {
19025
- dataRange.min = Math.min(trackView.dataRange.min, dataRange.min);
19026
- dataRange.max = Math.max(trackView.dataRange.max, dataRange.max);
19024
+ if (trackView.track.dataRange) {
19025
+ dataRange.min = Math.min(trackView.track.dataRange.min, dataRange.min);
19026
+ dataRange.max = Math.max(trackView.track.dataRange.max, dataRange.max);
19027
19027
  }
19028
19028
  }
19029
19029
  } else {
19030
- dataRange = trackViewOrTrackViewList.dataRange;
19030
+ dataRange = trackViewOrTrackViewList.track.dataRange;
19031
19031
  }
19032
19032
 
19033
19033
  if (dataRange) {
@@ -19069,7 +19069,7 @@
19069
19069
  } else {
19070
19070
  const list = Array.isArray(trackViewOfTrackViewList) ? trackViewOfTrackViewList : [ trackViewOfTrackViewList ];
19071
19071
  for (const trackView of list) {
19072
- trackView.dataRange = { min, max };
19072
+ trackView.track.setDataRange({ min, max });
19073
19073
  }
19074
19074
 
19075
19075
  }
@@ -26702,6 +26702,14 @@
26702
26702
  return menuItems
26703
26703
  }
26704
26704
 
26705
+ setDataRange({ min, max }) {
26706
+
26707
+ this.dataRange = { min, max };
26708
+ this.autoscale = false;
26709
+ this.autoscaleGroup = undefined;
26710
+ this.trackView.repaintViews();
26711
+ }
26712
+
26705
26713
  /**
26706
26714
  * Return the first feature in this track whose start position is > position
26707
26715
  * @param chr
@@ -27069,7 +27077,7 @@
27069
27077
  this.filter = tokens[6];
27070
27078
  this.info = {};
27071
27079
  const infoStr = tokens[7];
27072
- if (infoStr) {
27080
+ if (infoStr && infoStr !== '.') {
27073
27081
  for (let elem of infoStr.split(';')) {
27074
27082
  var element = elem.split('=');
27075
27083
  this.info[element[0]] = element[1];
@@ -27228,9 +27236,10 @@
27228
27236
  }
27229
27237
  }
27230
27238
 
27231
- if (this.info) {
27239
+ const infoKeys = Object.keys(this.info);
27240
+ if (this.info && infoKeys.length > 0) {
27232
27241
  fields.push({html: '<hr style="border-top: dotted 1px;border-color: #c9c3ba" />'});
27233
- for (let key of Object.keys(this.info)) {
27242
+ for (let key of infoKeys) {
27234
27243
  fields.push({name: key, value: arrayToString(decodeURIComponent(this.info[key]))});
27235
27244
  }
27236
27245
  }
@@ -27297,7 +27306,7 @@
27297
27306
  }
27298
27307
 
27299
27308
  getAttributeValue(key) {
27300
- return this.mate.getAttributeValue(key)
27309
+ return this.mate.getAttributeValue(key)
27301
27310
  }
27302
27311
 
27303
27312
  getInfo(tag) {
@@ -27320,7 +27329,7 @@
27320
27329
  popupData.push({name: 'Pos', value: `${numberFormatter$1(this.pos)}`});
27321
27330
  popupData.push({html: '<hr style="border-top: dotted 1px;border-color: #c9c3ba" />'});
27322
27331
  popupData.push("SV");
27323
- popupData.push(... this.mate.popupData(genomicLocation, genomeId));
27332
+ popupData.push(...this.mate.popupData(genomicLocation, genomeId));
27324
27333
 
27325
27334
  return popupData
27326
27335
  }
@@ -31216,7 +31225,7 @@
31216
31225
 
31217
31226
  function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
31218
31227
 
31219
- if ("biginteract" === format || (autoSql && ('chromatinInteract' === autoSql.table) || 'interact' === autoSql.table)) {
31228
+ if ("biginteract" === format || (autoSql && ('chromatinInteract' === autoSql.table || 'interact' === autoSql.table))) {
31220
31229
  return decodeInteract
31221
31230
  } else {
31222
31231
  const standardFieldCount = definedFieldCount - 3;
@@ -34422,7 +34431,7 @@
34422
34431
  }
34423
34432
 
34424
34433
 
34425
- if (!this.config.isMergedTrack) {
34434
+ if (!this.isMergedTrack) {
34426
34435
  IGVGraphics.fillRect(context, 0, options.pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
34427
34436
  }
34428
34437
 
@@ -41611,39 +41620,36 @@
41611
41620
  * THE SOFTWARE.
41612
41621
  */
41613
41622
 
41614
-
41615
41623
  /**
41616
- * Represents 2 or more wig tracks overlaid on a common viewport.
41624
+ * Represents 2 or more tracks overlaid on a common viewport.
41617
41625
  */
41618
41626
  class MergedTrack extends TrackBase {
41619
41627
 
41620
41628
  static defaults = {
41629
+ autoscale: undefined,
41621
41630
  alpha: 0.5,
41622
41631
  height: 50
41623
41632
  }
41624
41633
 
41625
- constructor(config, browser) {
41634
+ constructor(config, browser, tracks) {
41626
41635
  super(config, browser);
41627
41636
  this.type = "merged";
41628
- this.featureType = "numeric";
41629
41637
  this.paintAxis = paintAxis;
41630
41638
  this.graphType = config.graphType;
41631
- }
41632
-
41633
- init(config) {
41634
- if (!(config.tracks || config._tracks)) {
41635
- throw Error("Error: no tracks defined for merged track" + config)
41639
+ if (tracks) {
41640
+ this.tracks = tracks; // Dynamic creation, actual track objects (not configurations)
41641
+ } else {
41642
+ this.tracks = [];
41636
41643
  }
41637
- super.init(config);
41638
41644
  }
41639
41645
 
41646
+
41640
41647
  async postInit() {
41641
41648
 
41642
- this.tracks = [];
41643
41649
  if (this.config.tracks) {
41644
- // Configured merged track
41650
+ // Track configurations, this indicates a configured merged track as opposed to dynamic merge through the UI
41651
+ // Actual track objects need to be created.
41645
41652
  for (let tconf of this.config.tracks) {
41646
- tconf.isMergedTrack = true;
41647
41653
  const t = await this.browser.createTrack(tconf);
41648
41654
  if (t) {
41649
41655
  this.tracks.push(t);
@@ -41654,24 +41660,27 @@
41654
41660
  await t.postInit();
41655
41661
  }
41656
41662
  }
41657
- // Explicit merged settings -- these will override any individual track settings
41658
- if (this.config.autoscale) {
41659
- this.autoscale = this.config.autoscale;
41660
- } else if (this.config.max !== undefined) {
41661
- this.dataRange = {
41662
- min: this.config.min || 0,
41663
- max: this.config.max
41664
- };
41665
- } else {
41666
- this.autoscale = !this.tracks.every(t => t.config.autoscale || t.config.max !== undefined);
41663
+ // Default to autoscale unless scale if range or autoscale is not otherwise defined
41664
+ const allTracksSpecified = this.config.tracks.every(config => config.autoscale !== undefined || config.max !== undefined);
41665
+ if (!allTracksSpecified) {
41666
+ this.config.autoscale = this.config.max === undefined;
41667
41667
  }
41668
- } else {
41669
- // Dynamic merged track
41670
- this.tracks = this.config._tracks;
41671
- this.autoscale = false;
41672
- delete this.config._tracks;
41673
41668
  }
41674
41669
 
41670
+ // Mark constitutive tracks as merged.
41671
+ for (let t of this.tracks) t.isMergedTrack = true;
41672
+
41673
+ // Explicit settings -- these will override any individual track settings
41674
+ if(this.config.autoscale) {
41675
+ this.autoscale = this.config.autoscale;
41676
+ } else if (this.config.max !== undefined) {
41677
+ this.setDataRange ({
41678
+ min: this.config.min || 0,
41679
+ max: this.config.max
41680
+ });
41681
+ }
41682
+
41683
+
41675
41684
  if (this.config.flipAxis !== undefined) {
41676
41685
  for (let t of this.tracks) t.flipAxis = this.config.flipAxis;
41677
41686
  }
@@ -41681,25 +41690,28 @@
41681
41690
  }
41682
41691
 
41683
41692
  this.resolutionAware = this.tracks.some(t => t.resolutionAware);
41684
-
41685
41693
  }
41686
41694
 
41687
41695
  set flipAxis(b) {
41688
41696
  this.config.flipAxis = b;
41689
- for (let t of this.tracks) t.flipAxis = b;
41697
+ for (let t of numericTracks(this.tracks)) {
41698
+ t.flipAxis = b;
41699
+ }
41690
41700
  }
41691
41701
 
41692
41702
  get flipAxis() {
41693
- return this.tracks.every(t => t.flipAxis)
41703
+ return numericTracks(this.tracks).every(t => t.flipAxis)
41694
41704
  }
41695
41705
 
41696
41706
  set logScale(b) {
41697
41707
  this.config.logScale = b;
41698
- for (let t of this.tracks) t.logScale = b;
41708
+ for (let t of numericTracks(this.tracks)) {
41709
+ t.logScale = b;
41710
+ }
41699
41711
  }
41700
41712
 
41701
41713
  get logScale() {
41702
- return this.tracks.every(t => t.logScale)
41714
+ return numericTracks(this.tracks).every(t => t.logScale)
41703
41715
  }
41704
41716
 
41705
41717
  get height() {
@@ -41717,49 +41729,76 @@
41717
41729
  }
41718
41730
  }
41719
41731
 
41720
- get dataRange() {
41721
-
41722
- if (undefined === this.tracks || 0 === this.tracks.length) {
41723
- return undefined
41732
+ set autoscale(b) {
41733
+ this._autoscale = b;
41734
+ if(b === false && this.tracks) {
41735
+ for(let t of this.tracks) t.autoscale = false;
41724
41736
  }
41737
+ }
41725
41738
 
41726
- const list = this.tracks.filter(track => undefined !== track.dataRange);
41727
- if (list.length !== this.tracks.length) {
41728
- return undefined
41729
- }
41739
+ get autoscale() {
41740
+ return this._autoscale
41741
+ }
41730
41742
 
41731
- const minSet = new Set(this.tracks.map(({dataRange}) => dataRange.min));
41732
- if (1 !== minSet.size) {
41733
- return undefined
41734
- }
41743
+ /**
41744
+ * Set the data range of all constitutive numeric tracks. This method is called from the menu item, i.e. an explicit
41745
+ * setting, so it should disable autoscale as well.
41746
+ *
41747
+ * @param min
41748
+ * @param max
41749
+ */
41735
41750
 
41736
- const maxSet = new Set(this.tracks.map(({dataRange}) => dataRange.max));
41737
- if (1 !== maxSet.size) {
41738
- return undefined
41751
+ setDataRange({min, max}) {
41752
+ this.autoscale = false;
41753
+ for (const track of numericTracks(this.tracks)) {
41754
+ track.dataRange = {min, max};
41755
+ track.autoscale = false;
41756
+ track.autoscaleGroup = false;
41739
41757
  }
41758
+ }
41740
41759
 
41741
- return { min: [ ...minSet ][ 0 ], max: [ ...maxSet ][ 0 ] }
41760
+ set dataRange({min, max}) {
41761
+ for (const track of numericTracks(this.tracks)) {
41762
+ track.dataRange = {min, max};
41763
+ }
41742
41764
  }
41743
41765
 
41744
- set dataRange({ min, max }) {
41745
- for (const track of this.tracks) {
41746
- track.dataRange = { min, max };
41766
+ /**
41767
+ * Return a DataRang {min, max} if all constitutive numeric tracks have identical range. A numeric track is defined
41768
+ * as a track with a data range. Otherwise return undefined.
41769
+ *
41770
+ * @returns {{min: any, max: any}|undefined}
41771
+ */
41772
+ get dataRange() {
41773
+ if(this.tracks) {
41774
+ const num = numericTracks(this.tracks);
41775
+ if (num.length > 0) {
41776
+ const firstRange = num[0].dataRange;
41777
+ if (num.every(t => t.dataRange && t.dataRange.min === firstRange.min && t.dataRange.max === firstRange.max)) {
41778
+ return firstRange
41779
+ }
41780
+ }
41747
41781
  }
41782
+ return undefined
41748
41783
  }
41749
41784
 
41785
+
41750
41786
  menuItemList() {
41751
41787
  const items = [];
41752
- if (this.flipAxis !== undefined) {
41753
- items.push({
41754
- label: "Flip y-axis",
41755
- click: function flipYAxisHandler() {
41756
- this.flipAxis = !this.flipAxis;
41757
- this.trackView.repaintViews();
41758
- }
41759
- });
41760
- }
41788
+ if (numericTracks(this.tracks).length > 0) {
41761
41789
 
41762
- items.push(...this.numericDataMenuItems());
41790
+ if (this.flipAxis !== undefined) {
41791
+ items.push({
41792
+ label: "Flip y-axis",
41793
+ click: function flipYAxisHandler() {
41794
+ this.flipAxis = !this.flipAxis;
41795
+ this.trackView.repaintViews();
41796
+ }
41797
+ });
41798
+ }
41799
+
41800
+ items.push(...this.numericDataMenuItems());
41801
+ }
41763
41802
 
41764
41803
  items.push('<hr/>');
41765
41804
  items.push(this.overlayTrackAlphaAdjustmentMenuItem());
@@ -41776,7 +41815,14 @@
41776
41815
 
41777
41816
  const promises = this.tracks.map((t) => t.getFeatures(chr, bpStart, bpEnd, bpPerPixel));
41778
41817
  const featureArrays = await Promise.all(promises);
41779
- return new MergedFeatureCollection(featureArrays)
41818
+
41819
+ if (featureArrays.every((arr) => arr.length === 0)){
41820
+ return new MergedFeatureCollection([], [])
41821
+ }
41822
+ else {
41823
+ const trackNames = this.tracks.map((t) => t.name);
41824
+ return new MergedFeatureCollection(featureArrays, trackNames)
41825
+ }
41780
41826
  }
41781
41827
 
41782
41828
  draw(options) {
@@ -41788,11 +41834,6 @@
41788
41834
  trackOptions.features = mergedFeatures.featureArrays[i];
41789
41835
  trackOptions.alpha = this.alpha;
41790
41836
 
41791
- if (this.dataRange) {
41792
- // Single data scale for all tracks
41793
- this.tracks[i].dataRange = this.dataRange;
41794
- }
41795
-
41796
41837
  if (this.graphType) {
41797
41838
  this.tracks[i].graphType = this.graphType;
41798
41839
  }
@@ -41886,6 +41927,7 @@
41886
41927
  let scaleChange;
41887
41928
 
41888
41929
  if (this.autoscale) {
41930
+ // Overrides any specific track scale settings
41889
41931
  scaleChange = true;
41890
41932
  let allFeatures = [];
41891
41933
  for (let visibleViewport of visibleViewports) {
@@ -41900,7 +41942,12 @@
41900
41942
  allFeatures.push({value: mergedFeatureCollection.getMin(start, end)});
41901
41943
  }
41902
41944
  }
41903
- this.dataRange = doAutoscale(allFeatures);
41945
+ const dataRange = doAutoscale(allFeatures);
41946
+ for (const track of numericTracks(this.tracks)) {
41947
+ // Do not use this.dataRange, as that has side effects
41948
+ track.dataRange = dataRange;
41949
+ }
41950
+
41904
41951
  }
41905
41952
  } else {
41906
41953
  // Individual track scaling
@@ -41980,6 +42027,7 @@
41980
42027
  if (groupAutoscale) {
41981
42028
  track.autoscaleGroup = name;
41982
42029
  }
42030
+ track.isMergedTrack = false;
41983
42031
  browser.addTrack(track.config, track);
41984
42032
  }
41985
42033
  browser.updateViews();
@@ -41993,25 +42041,30 @@
41993
42041
 
41994
42042
  class MergedFeatureCollection {
41995
42043
 
41996
- constructor(featureArrays) {
42044
+ constructor(featureArrays,trackNames) {
41997
42045
  this.featureArrays = featureArrays;
42046
+ //trackNames is needed for the popup data to populate track names
42047
+ //preserving the order of the actual tracks
42048
+ this.trackNames = trackNames;
41998
42049
  }
41999
42050
 
42000
42051
  getMax(start, end) {
42001
42052
  let max = -Number.MAX_VALUE;
42002
42053
 
42003
42054
  for (let a of this.featureArrays) {
42004
- for (let f of a) {
42005
- if (typeof f.value === 'undefined' || Number.isNaN(f.value)) {
42006
- continue
42007
- }
42008
- if (f.end < start) {
42009
- continue
42010
- }
42011
- if (f.start > end) {
42012
- break
42055
+ if (Array.isArray(a)) {
42056
+ for (let f of a) {
42057
+ if (typeof f.value === 'undefined' || Number.isNaN(f.value)) {
42058
+ continue
42059
+ }
42060
+ if (f.end < start) {
42061
+ continue
42062
+ }
42063
+ if (f.start > end) {
42064
+ break
42065
+ }
42066
+ max = Math.max(max, f.value);
42013
42067
  }
42014
- max = Math.max(max, f.value);
42015
42068
  }
42016
42069
  }
42017
42070
 
@@ -42022,15 +42075,17 @@
42022
42075
  getMin(start, end) {
42023
42076
  let min = 0;
42024
42077
  for (let a of this.featureArrays) {
42025
- for (let f of a) {
42026
- if (typeof f.value !== 'undefined' && !Number.isNaN(f.value)) {
42027
- if (f.end < start) {
42028
- continue
42029
- }
42030
- if (f.start > end) {
42031
- break
42078
+ if (Array.isArray(a)) {
42079
+ for (let f of a) {
42080
+ if (typeof f.value !== 'undefined' && !Number.isNaN(f.value)) {
42081
+ if (f.end < start) {
42082
+ continue
42083
+ }
42084
+ if (f.start > end) {
42085
+ break
42086
+ }
42087
+ min = Math.min(min, f.value);
42032
42088
  }
42033
- min = Math.min(min, f.value);
42034
42089
  }
42035
42090
  }
42036
42091
  }
@@ -42038,6 +42093,16 @@
42038
42093
  }
42039
42094
  }
42040
42095
 
42096
+ /**
42097
+ * Heuristic for finding numeric tracks.
42098
+ *
42099
+ * @param tracks
42100
+ * @returns {*}
42101
+ */
42102
+ const numericTracks = (tracks) => {
42103
+ return tracks ? tracks.filter(track => undefined !== track.dataRange || undefined !== track.autoscale || undefined !== track.autoscaleGroup) : []
42104
+ };
42105
+
42041
42106
  class OverlayTrackButton extends NavbarButton {
42042
42107
  constructor(browser, parent) {
42043
42108
 
@@ -42083,13 +42148,13 @@
42083
42148
  {
42084
42149
  name: 'Overlay',
42085
42150
  type: 'merged',
42151
+ autoscale: false,
42086
42152
  alpha: 0.5, //fudge * (1.0/tracks.length),
42087
42153
  height: Math.max(...tracks.map(({ height }) => height)),
42088
42154
  order: Math.min(...tracks.map(({ order }) => order)),
42089
- _tracks: flattenedTracks
42090
42155
  };
42091
42156
 
42092
- const mergedTrack = new MergedTrack(config, this.browser);
42157
+ const mergedTrack = new MergedTrack(config, this.browser, flattenedTracks);
42093
42158
 
42094
42159
  for (const track of tracks) {
42095
42160
  this.browser.removeTrack(track);
@@ -42309,27 +42374,6 @@
42309
42374
  }
42310
42375
  }
42311
42376
 
42312
- get dataRange() {
42313
- return this.track.dataRange ? this.track.dataRange : undefined
42314
- }
42315
-
42316
- set dataRange({ min, max }) {
42317
-
42318
- this.track.dataRange = { min, max };
42319
-
42320
- this.track.autoscale = false;
42321
- this.track.autoscaleGroup = undefined;
42322
-
42323
- const list = this.browser.trackViews.filter(({track}) => track.autoscaleGroup);
42324
- if (1 === list.length) {
42325
- list[0].track.autoscale = false;
42326
- list[0].track.autoscaleGroup = undefined;
42327
- list[0].repaintViews();
42328
- }
42329
-
42330
- this.repaintViews();
42331
-
42332
- }
42333
42377
 
42334
42378
  presentColorPicker(key) {
42335
42379
 
@@ -49778,46 +49822,41 @@
49778
49822
  },
49779
49823
 
49780
49824
  /**
49825
+ * @param ba - UInt8Array bytes to decode
49781
49826
  *
49782
- * @param ba bytes to decode as a UInt8Array
49783
- * @param genome optional igv genome object
49784
- * @returns {{ magicNumer: number, size: number, chrNames: Array, chrToIndex: ({}|*), chrAliasTable: ({}|*) }}
49827
+ * @returns {{size: *, chrNames: *[], magicNumber: *, chrToIndex: {}}}
49785
49828
  */
49786
- decodeBamHeader: function (ba, genome) {
49829
+ decodeBamHeader: function (ba) {
49787
49830
 
49788
- var magic, samHeaderLen, samHeader, chrToIndex, chrNames;
49789
49831
 
49790
- magic = readInt(ba, 0);
49832
+ const magic = readInt(ba, 0);
49791
49833
  if (magic !== BAM1_MAGIC_NUMBER) {
49792
49834
  throw new Error('BAM header errror: bad magic number. This could be caused by either a corrupt or missing file.')
49793
49835
  }
49794
49836
 
49795
- samHeaderLen = readInt(ba, 4);
49796
- samHeader = '';
49797
-
49837
+ const samHeaderLen = readInt(ba, 4);
49838
+ let samHeader = '';
49798
49839
  for (var i = 0; i < samHeaderLen; ++i) {
49799
49840
  samHeader += String.fromCharCode(ba[i + 8]);
49800
49841
  }
49801
49842
 
49802
- var nRef = readInt(ba, samHeaderLen + 8);
49803
- var p = samHeaderLen + 12;
49843
+ const nRef = readInt(ba, samHeaderLen + 8);
49844
+ let p = samHeaderLen + 12;
49804
49845
 
49805
- chrToIndex = {};
49806
- chrNames = [];
49846
+ const chrToIndex = {};
49847
+ const chrNames = [];
49807
49848
 
49808
49849
  for (i = 0; i < nRef; ++i) {
49809
- var lName = readInt(ba, p);
49810
- var name = '';
49811
- for (var j = 0; j < lName - 1; ++j) {
49850
+ const len = readInt(ba, p);
49851
+ let name = '';
49852
+ for (var j = 0; j < len - 1; ++j) {
49812
49853
  name += String.fromCharCode(ba[p + 4 + j]);
49813
49854
  }
49814
- readInt(ba, p + lName + 4);
49815
- //dlog(name + ': ' + lRef);
49816
49855
 
49817
49856
  chrToIndex[name] = i;
49818
49857
  chrNames[i] = name;
49819
49858
 
49820
- p = p + 8 + lName;
49859
+ p = p + 8 + len;
49821
49860
  }
49822
49861
 
49823
49862
  return {
@@ -50807,8 +50846,8 @@
50807
50846
  const ba = unbgzf(compressedData.buffer);
50808
50847
  this.header = BamUtils.decodeBamHeader(ba, this.genome);
50809
50848
  this.chrAliasTable = new Map();
50810
- for (let key of Object.keys(this.header.chrAliasTable)) {
50811
- this.chrAliasTable.set(key, this.header.chrAliasTable[key]);
50849
+ for (let name of this.header.chrNames) {
50850
+ this.chrAliasTable.set(name, this.genome.getChromosomeName(name));
50812
50851
  }
50813
50852
  }
50814
50853
 
@@ -50818,6 +50857,7 @@
50818
50857
 
50819
50858
  // BAM decoding
50820
50859
  const ba = unbgzf(compressedData.buffer);
50860
+ this.header = BamUtils.decodeBamHeader(ba, this.genome);
50821
50861
 
50822
50862
  const chrIdx = this.header.chrToIndex[chr];
50823
50863
  const alignmentContainer = new AlignmentContainer(chr, start, end, this.config);
@@ -57662,6 +57702,7 @@
57662
57702
 
57663
57703
 
57664
57704
  constructor(config, parent) {
57705
+ this.featureType = 'numeric';
57665
57706
  this.parent = parent;
57666
57707
  this.featureSource = parent.featureSource;
57667
57708
 
@@ -66140,12 +66181,12 @@
66140
66181
  if (this.signals.includes(signal_name)) {
66141
66182
  let tconf = {};
66142
66183
  tconf.type = "wig";
66143
- tconf.isMergedTrack = true;
66144
66184
  tconf.features = wig;
66145
66185
  tconf.name = signal_name;
66146
66186
  tconf.color = this.signal_colors.filter(x => x.singal_name === signal_name).map(x => x.color);
66147
66187
  const t = await this.browser.createTrack(tconf);
66148
66188
  if (t) {
66189
+ t.isMergedTrack = true;
66149
66190
  t.autoscale = false; // Scaling done from merged track
66150
66191
  this.tracks.push(t);
66151
66192
  } else {
@@ -66324,12 +66365,12 @@
66324
66365
  if (this.signals.includes(signal_name)) {
66325
66366
  let tconf = {};
66326
66367
  tconf.type = "wig";
66327
- tconf.isMergedTrack = true;
66328
66368
  tconf.features = wig;
66329
66369
  tconf.name = signal_name;
66330
66370
  tconf.color = this.signal_colors.filter(x => x.singal_name === signal_name).map(x => x.color);
66331
66371
  const t = await this.browser.createTrack(tconf);
66332
66372
  if (t) {
66373
+ t.isMergedTrack = true;
66333
66374
  t.autoscale = false; // Scaling done from merged track
66334
66375
  this.tracks.push(t);
66335
66376
  } else {
@@ -66722,23 +66763,26 @@
66722
66763
  this.header = await this.getHeader();
66723
66764
 
66724
66765
  // Set colorBy, if not explicitly set default to allele frequency, if available, otherwise default to none (undefined)
66725
- const infoFields = new Set(Object.keys(this.header.INFO));
66726
- if (this.config.colorBy) {
66727
- this.colorBy = this.config.colorBy;
66728
- } else if (!this.config.color && infoFields.has('AF')) {
66729
- this.colorBy = 'AF';
66730
- }
66766
+ if(this.header.INFO) {
66767
+ const infoFields = new Set(Object.keys(this.header.INFO));
66768
+ if (this.config.colorBy) {
66769
+ this.colorBy = this.config.colorBy;
66770
+ } else if (!this.config.color && infoFields.has('AF')) {
66771
+ this.colorBy = 'AF';
66772
+ }
66731
66773
 
66732
- // Configure menu items based on info available
66733
- if (infoFields.has('AF')) {
66734
- this._colorByItems.set('AF', 'Allele frequency');
66735
- }
66736
- if (infoFields.has('VT')) {
66737
- this._colorByItems.set('VT', 'Variant Type');
66738
- }
66739
- if (infoFields.has('SVTYPE')) {
66740
- this._colorByItems.set('SVTYPE', 'SV Type');
66774
+ // Configure menu items based on info available
66775
+ if (infoFields.has('AF')) {
66776
+ this._colorByItems.set('AF', 'Allele frequency');
66777
+ }
66778
+ if (infoFields.has('VT')) {
66779
+ this._colorByItems.set('VT', 'Variant Type');
66780
+ }
66781
+ if (infoFields.has('SVTYPE')) {
66782
+ this._colorByItems.set('SVTYPE', 'SV Type');
66783
+ }
66741
66784
  }
66785
+
66742
66786
  if (this.config.colorBy && !this._colorByItems.has(this.config.colorBy)) {
66743
66787
  this._colorByItems.set(this.config.colorBy, this.config.colorBy);
66744
66788
  }
@@ -69583,11 +69627,15 @@
69583
69627
  JUNCTION_MOTIF_PALETTE.getColor(motif);
69584
69628
  });
69585
69629
 
69586
- // rendering context with values that only need to be computed once per render, rather than for each splice junction
69587
- const junctionRenderingContext = {};
69588
69630
 
69589
69631
  class SpliceJunctionTrack extends TrackBase {
69590
69632
 
69633
+ static defaults = {
69634
+ margin: 10,
69635
+ colorByNumReadsThreshold: 5,
69636
+ height: 100
69637
+ }
69638
+
69591
69639
  constructor(config, browser) {
69592
69640
  super(config, browser);
69593
69641
  }
@@ -69608,16 +69656,6 @@
69608
69656
  FeatureSource(config, this.browser.genome);
69609
69657
  }
69610
69658
 
69611
- this.margin = config.margin === undefined ? 10 : config.margin;
69612
-
69613
- if (!this.height) {
69614
- this.height = 100;
69615
- }
69616
-
69617
- //set defaults
69618
- if (config.colorByNumReadsThreshold === undefined) {
69619
- config.colorByNumReadsThreshold = 5;
69620
- }
69621
69659
  }
69622
69660
 
69623
69661
  async postInit() {
@@ -69672,13 +69710,16 @@
69672
69710
  const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
69673
69711
 
69674
69712
 
69675
- if (!this.config.isMergedTrack) {
69713
+ if (!this.isMergedTrack) {
69676
69714
  IGVGraphics.fillRect(ctx, 0, options.pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
69677
69715
  }
69678
69716
 
69679
69717
  if (featureList) {
69680
69718
 
69681
69719
 
69720
+ // rendering context with values that only need to be computed once per render, rather than for each splice junction
69721
+ const junctionRenderingContext = {};
69722
+
69682
69723
  junctionRenderingContext.referenceFrame = options.viewport.referenceFrame;
69683
69724
  junctionRenderingContext.referenceFrameStart = junctionRenderingContext.referenceFrame.start;
69684
69725
  junctionRenderingContext.referenceFrameEnd = junctionRenderingContext.referenceFrameStart +
@@ -69691,7 +69732,7 @@
69691
69732
  for (let feature of featureList) {
69692
69733
  if (feature.end < bpStart) continue
69693
69734
  if (feature.start > bpEnd) break
69694
- this.renderJunction(feature, bpStart, bpPerPixel, pixelHeight, ctx);
69735
+ this.renderJunction(feature, bpStart, bpPerPixel, pixelHeight, ctx, junctionRenderingContext);
69695
69736
  }
69696
69737
 
69697
69738
  } else {
@@ -69708,7 +69749,7 @@
69708
69749
  * @param pixelHeight pixel height of the current canvas
69709
69750
  * @param ctx the canvas 2d context
69710
69751
  */
69711
- renderJunction(feature, bpStart, xScale, pixelHeight, ctx) {
69752
+ renderJunction(feature, bpStart, xScale, pixelHeight, ctx, junctionRenderingContext) {
69712
69753
  // cache whether this junction is rendered or filtered out. Use later to exclude non-rendered junctions from click detection.
69713
69754
  feature.isVisible = false;
69714
69755
 
@@ -69792,7 +69833,7 @@
69792
69833
  }
69793
69834
 
69794
69835
  const py = this.margin;
69795
- const rowHeight = this.height;
69836
+ const rowHeight = pixelHeight;
69796
69837
 
69797
69838
  const cy = py + 0.5 * rowHeight;
69798
69839
  let topY = py;
@@ -70477,7 +70518,7 @@
70477
70518
  })
70478
70519
  }
70479
70520
 
70480
- const _version = "3.0.1";
70521
+ const _version = "3.0.2";
70481
70522
  function version() {
70482
70523
  return _version
70483
70524
  }
@@ -72928,7 +72969,7 @@
72928
72969
  }
72929
72970
 
72930
72971
  /**
72931
- * Return the canonical chromosome name for the alias. If none found return the alias.
72972
+ * Return the cached canonical chromosome name for the alias. If none found return the alias.
72932
72973
  *
72933
72974
  * Note this will only work if a "search" for ths chromosome has been performed previously.
72934
72975
  *