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.esm.js CHANGED
@@ -19015,13 +19015,13 @@ class DataRangeDialog {
19015
19015
  if (Array.isArray(trackViewOrTrackViewList)) {
19016
19016
  dataRange = { min: Number.MAX_SAFE_INTEGER, max:-Number.MAX_SAFE_INTEGER };
19017
19017
  for (const trackView of trackViewOrTrackViewList) {
19018
- if (trackView.dataRange) {
19019
- dataRange.min = Math.min(trackView.dataRange.min, dataRange.min);
19020
- dataRange.max = Math.max(trackView.dataRange.max, dataRange.max);
19018
+ if (trackView.track.dataRange) {
19019
+ dataRange.min = Math.min(trackView.track.dataRange.min, dataRange.min);
19020
+ dataRange.max = Math.max(trackView.track.dataRange.max, dataRange.max);
19021
19021
  }
19022
19022
  }
19023
19023
  } else {
19024
- dataRange = trackViewOrTrackViewList.dataRange;
19024
+ dataRange = trackViewOrTrackViewList.track.dataRange;
19025
19025
  }
19026
19026
 
19027
19027
  if (dataRange) {
@@ -19063,7 +19063,7 @@ class DataRangeDialog {
19063
19063
  } else {
19064
19064
  const list = Array.isArray(trackViewOfTrackViewList) ? trackViewOfTrackViewList : [ trackViewOfTrackViewList ];
19065
19065
  for (const trackView of list) {
19066
- trackView.dataRange = { min, max };
19066
+ trackView.track.setDataRange({ min, max });
19067
19067
  }
19068
19068
 
19069
19069
  }
@@ -26696,6 +26696,14 @@ class TrackBase {
26696
26696
  return menuItems
26697
26697
  }
26698
26698
 
26699
+ setDataRange({ min, max }) {
26700
+
26701
+ this.dataRange = { min, max };
26702
+ this.autoscale = false;
26703
+ this.autoscaleGroup = undefined;
26704
+ this.trackView.repaintViews();
26705
+ }
26706
+
26699
26707
  /**
26700
26708
  * Return the first feature in this track whose start position is > position
26701
26709
  * @param chr
@@ -27063,7 +27071,7 @@ class Variant {
27063
27071
  this.filter = tokens[6];
27064
27072
  this.info = {};
27065
27073
  const infoStr = tokens[7];
27066
- if (infoStr) {
27074
+ if (infoStr && infoStr !== '.') {
27067
27075
  for (let elem of infoStr.split(';')) {
27068
27076
  var element = elem.split('=');
27069
27077
  this.info[element[0]] = element[1];
@@ -27222,9 +27230,10 @@ class Variant {
27222
27230
  }
27223
27231
  }
27224
27232
 
27225
- if (this.info) {
27233
+ const infoKeys = Object.keys(this.info);
27234
+ if (this.info && infoKeys.length > 0) {
27226
27235
  fields.push({html: '<hr style="border-top: dotted 1px;border-color: #c9c3ba" />'});
27227
- for (let key of Object.keys(this.info)) {
27236
+ for (let key of infoKeys) {
27228
27237
  fields.push({name: key, value: arrayToString(decodeURIComponent(this.info[key]))});
27229
27238
  }
27230
27239
  }
@@ -27291,7 +27300,7 @@ class SVComplement {
27291
27300
  }
27292
27301
 
27293
27302
  getAttributeValue(key) {
27294
- return this.mate.getAttributeValue(key)
27303
+ return this.mate.getAttributeValue(key)
27295
27304
  }
27296
27305
 
27297
27306
  getInfo(tag) {
@@ -27314,7 +27323,7 @@ class SVComplement {
27314
27323
  popupData.push({name: 'Pos', value: `${numberFormatter$1(this.pos)}`});
27315
27324
  popupData.push({html: '<hr style="border-top: dotted 1px;border-color: #c9c3ba" />'});
27316
27325
  popupData.push("SV");
27317
- popupData.push(... this.mate.popupData(genomicLocation, genomeId));
27326
+ popupData.push(...this.mate.popupData(genomicLocation, genomeId));
27318
27327
 
27319
27328
  return popupData
27320
27329
  }
@@ -31210,7 +31219,7 @@ function overlaps(item, chrIdx1, startBase, chrIdx2, endBase) {
31210
31219
 
31211
31220
  function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
31212
31221
 
31213
- if ("biginteract" === format || (autoSql && ('chromatinInteract' === autoSql.table) || 'interact' === autoSql.table)) {
31222
+ if ("biginteract" === format || (autoSql && ('chromatinInteract' === autoSql.table || 'interact' === autoSql.table))) {
31214
31223
  return decodeInteract
31215
31224
  } else {
31216
31225
  const standardFieldCount = definedFieldCount - 3;
@@ -34416,7 +34425,7 @@ class FeatureTrack extends TrackBase {
34416
34425
  }
34417
34426
 
34418
34427
 
34419
- if (!this.config.isMergedTrack) {
34428
+ if (!this.isMergedTrack) {
34420
34429
  IGVGraphics.fillRect(context, 0, options.pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
34421
34430
  }
34422
34431
 
@@ -41605,39 +41614,36 @@ function paintAxis(ctx, width, height, colorOrUndefined) {
41605
41614
  * THE SOFTWARE.
41606
41615
  */
41607
41616
 
41608
-
41609
41617
  /**
41610
- * Represents 2 or more wig tracks overlaid on a common viewport.
41618
+ * Represents 2 or more tracks overlaid on a common viewport.
41611
41619
  */
41612
41620
  class MergedTrack extends TrackBase {
41613
41621
 
41614
41622
  static defaults = {
41623
+ autoscale: undefined,
41615
41624
  alpha: 0.5,
41616
41625
  height: 50
41617
41626
  }
41618
41627
 
41619
- constructor(config, browser) {
41628
+ constructor(config, browser, tracks) {
41620
41629
  super(config, browser);
41621
41630
  this.type = "merged";
41622
- this.featureType = "numeric";
41623
41631
  this.paintAxis = paintAxis;
41624
41632
  this.graphType = config.graphType;
41625
- }
41626
-
41627
- init(config) {
41628
- if (!(config.tracks || config._tracks)) {
41629
- throw Error("Error: no tracks defined for merged track" + config)
41633
+ if (tracks) {
41634
+ this.tracks = tracks; // Dynamic creation, actual track objects (not configurations)
41635
+ } else {
41636
+ this.tracks = [];
41630
41637
  }
41631
- super.init(config);
41632
41638
  }
41633
41639
 
41640
+
41634
41641
  async postInit() {
41635
41642
 
41636
- this.tracks = [];
41637
41643
  if (this.config.tracks) {
41638
- // Configured merged track
41644
+ // Track configurations, this indicates a configured merged track as opposed to dynamic merge through the UI
41645
+ // Actual track objects need to be created.
41639
41646
  for (let tconf of this.config.tracks) {
41640
- tconf.isMergedTrack = true;
41641
41647
  const t = await this.browser.createTrack(tconf);
41642
41648
  if (t) {
41643
41649
  this.tracks.push(t);
@@ -41648,24 +41654,27 @@ class MergedTrack extends TrackBase {
41648
41654
  await t.postInit();
41649
41655
  }
41650
41656
  }
41651
- // Explicit merged settings -- these will override any individual track settings
41652
- if (this.config.autoscale) {
41653
- this.autoscale = this.config.autoscale;
41654
- } else if (this.config.max !== undefined) {
41655
- this.dataRange = {
41656
- min: this.config.min || 0,
41657
- max: this.config.max
41658
- };
41659
- } else {
41660
- this.autoscale = !this.tracks.every(t => t.config.autoscale || t.config.max !== undefined);
41657
+ // Default to autoscale unless scale if range or autoscale is not otherwise defined
41658
+ const allTracksSpecified = this.config.tracks.every(config => config.autoscale !== undefined || config.max !== undefined);
41659
+ if (!allTracksSpecified) {
41660
+ this.config.autoscale = this.config.max === undefined;
41661
41661
  }
41662
- } else {
41663
- // Dynamic merged track
41664
- this.tracks = this.config._tracks;
41665
- this.autoscale = false;
41666
- delete this.config._tracks;
41667
41662
  }
41668
41663
 
41664
+ // Mark constitutive tracks as merged.
41665
+ for (let t of this.tracks) t.isMergedTrack = true;
41666
+
41667
+ // Explicit settings -- these will override any individual track settings
41668
+ if(this.config.autoscale) {
41669
+ this.autoscale = this.config.autoscale;
41670
+ } else if (this.config.max !== undefined) {
41671
+ this.setDataRange ({
41672
+ min: this.config.min || 0,
41673
+ max: this.config.max
41674
+ });
41675
+ }
41676
+
41677
+
41669
41678
  if (this.config.flipAxis !== undefined) {
41670
41679
  for (let t of this.tracks) t.flipAxis = this.config.flipAxis;
41671
41680
  }
@@ -41675,25 +41684,28 @@ class MergedTrack extends TrackBase {
41675
41684
  }
41676
41685
 
41677
41686
  this.resolutionAware = this.tracks.some(t => t.resolutionAware);
41678
-
41679
41687
  }
41680
41688
 
41681
41689
  set flipAxis(b) {
41682
41690
  this.config.flipAxis = b;
41683
- for (let t of this.tracks) t.flipAxis = b;
41691
+ for (let t of numericTracks(this.tracks)) {
41692
+ t.flipAxis = b;
41693
+ }
41684
41694
  }
41685
41695
 
41686
41696
  get flipAxis() {
41687
- return this.tracks.every(t => t.flipAxis)
41697
+ return numericTracks(this.tracks).every(t => t.flipAxis)
41688
41698
  }
41689
41699
 
41690
41700
  set logScale(b) {
41691
41701
  this.config.logScale = b;
41692
- for (let t of this.tracks) t.logScale = b;
41702
+ for (let t of numericTracks(this.tracks)) {
41703
+ t.logScale = b;
41704
+ }
41693
41705
  }
41694
41706
 
41695
41707
  get logScale() {
41696
- return this.tracks.every(t => t.logScale)
41708
+ return numericTracks(this.tracks).every(t => t.logScale)
41697
41709
  }
41698
41710
 
41699
41711
  get height() {
@@ -41711,49 +41723,76 @@ class MergedTrack extends TrackBase {
41711
41723
  }
41712
41724
  }
41713
41725
 
41714
- get dataRange() {
41715
-
41716
- if (undefined === this.tracks || 0 === this.tracks.length) {
41717
- return undefined
41726
+ set autoscale(b) {
41727
+ this._autoscale = b;
41728
+ if(b === false && this.tracks) {
41729
+ for(let t of this.tracks) t.autoscale = false;
41718
41730
  }
41731
+ }
41719
41732
 
41720
- const list = this.tracks.filter(track => undefined !== track.dataRange);
41721
- if (list.length !== this.tracks.length) {
41722
- return undefined
41723
- }
41733
+ get autoscale() {
41734
+ return this._autoscale
41735
+ }
41724
41736
 
41725
- const minSet = new Set(this.tracks.map(({dataRange}) => dataRange.min));
41726
- if (1 !== minSet.size) {
41727
- return undefined
41728
- }
41737
+ /**
41738
+ * Set the data range of all constitutive numeric tracks. This method is called from the menu item, i.e. an explicit
41739
+ * setting, so it should disable autoscale as well.
41740
+ *
41741
+ * @param min
41742
+ * @param max
41743
+ */
41729
41744
 
41730
- const maxSet = new Set(this.tracks.map(({dataRange}) => dataRange.max));
41731
- if (1 !== maxSet.size) {
41732
- return undefined
41745
+ setDataRange({min, max}) {
41746
+ this.autoscale = false;
41747
+ for (const track of numericTracks(this.tracks)) {
41748
+ track.dataRange = {min, max};
41749
+ track.autoscale = false;
41750
+ track.autoscaleGroup = false;
41733
41751
  }
41752
+ }
41734
41753
 
41735
- return { min: [ ...minSet ][ 0 ], max: [ ...maxSet ][ 0 ] }
41754
+ set dataRange({min, max}) {
41755
+ for (const track of numericTracks(this.tracks)) {
41756
+ track.dataRange = {min, max};
41757
+ }
41736
41758
  }
41737
41759
 
41738
- set dataRange({ min, max }) {
41739
- for (const track of this.tracks) {
41740
- track.dataRange = { min, max };
41760
+ /**
41761
+ * Return a DataRang {min, max} if all constitutive numeric tracks have identical range. A numeric track is defined
41762
+ * as a track with a data range. Otherwise return undefined.
41763
+ *
41764
+ * @returns {{min: any, max: any}|undefined}
41765
+ */
41766
+ get dataRange() {
41767
+ if(this.tracks) {
41768
+ const num = numericTracks(this.tracks);
41769
+ if (num.length > 0) {
41770
+ const firstRange = num[0].dataRange;
41771
+ if (num.every(t => t.dataRange && t.dataRange.min === firstRange.min && t.dataRange.max === firstRange.max)) {
41772
+ return firstRange
41773
+ }
41774
+ }
41741
41775
  }
41776
+ return undefined
41742
41777
  }
41743
41778
 
41779
+
41744
41780
  menuItemList() {
41745
41781
  const items = [];
41746
- if (this.flipAxis !== undefined) {
41747
- items.push({
41748
- label: "Flip y-axis",
41749
- click: function flipYAxisHandler() {
41750
- this.flipAxis = !this.flipAxis;
41751
- this.trackView.repaintViews();
41752
- }
41753
- });
41754
- }
41782
+ if (numericTracks(this.tracks).length > 0) {
41755
41783
 
41756
- items.push(...this.numericDataMenuItems());
41784
+ if (this.flipAxis !== undefined) {
41785
+ items.push({
41786
+ label: "Flip y-axis",
41787
+ click: function flipYAxisHandler() {
41788
+ this.flipAxis = !this.flipAxis;
41789
+ this.trackView.repaintViews();
41790
+ }
41791
+ });
41792
+ }
41793
+
41794
+ items.push(...this.numericDataMenuItems());
41795
+ }
41757
41796
 
41758
41797
  items.push('<hr/>');
41759
41798
  items.push(this.overlayTrackAlphaAdjustmentMenuItem());
@@ -41770,7 +41809,14 @@ class MergedTrack extends TrackBase {
41770
41809
 
41771
41810
  const promises = this.tracks.map((t) => t.getFeatures(chr, bpStart, bpEnd, bpPerPixel));
41772
41811
  const featureArrays = await Promise.all(promises);
41773
- return new MergedFeatureCollection(featureArrays)
41812
+
41813
+ if (featureArrays.every((arr) => arr.length === 0)){
41814
+ return new MergedFeatureCollection([], [])
41815
+ }
41816
+ else {
41817
+ const trackNames = this.tracks.map((t) => t.name);
41818
+ return new MergedFeatureCollection(featureArrays, trackNames)
41819
+ }
41774
41820
  }
41775
41821
 
41776
41822
  draw(options) {
@@ -41782,11 +41828,6 @@ class MergedTrack extends TrackBase {
41782
41828
  trackOptions.features = mergedFeatures.featureArrays[i];
41783
41829
  trackOptions.alpha = this.alpha;
41784
41830
 
41785
- if (this.dataRange) {
41786
- // Single data scale for all tracks
41787
- this.tracks[i].dataRange = this.dataRange;
41788
- }
41789
-
41790
41831
  if (this.graphType) {
41791
41832
  this.tracks[i].graphType = this.graphType;
41792
41833
  }
@@ -41880,6 +41921,7 @@ class MergedTrack extends TrackBase {
41880
41921
  let scaleChange;
41881
41922
 
41882
41923
  if (this.autoscale) {
41924
+ // Overrides any specific track scale settings
41883
41925
  scaleChange = true;
41884
41926
  let allFeatures = [];
41885
41927
  for (let visibleViewport of visibleViewports) {
@@ -41894,7 +41936,12 @@ class MergedTrack extends TrackBase {
41894
41936
  allFeatures.push({value: mergedFeatureCollection.getMin(start, end)});
41895
41937
  }
41896
41938
  }
41897
- this.dataRange = doAutoscale(allFeatures);
41939
+ const dataRange = doAutoscale(allFeatures);
41940
+ for (const track of numericTracks(this.tracks)) {
41941
+ // Do not use this.dataRange, as that has side effects
41942
+ track.dataRange = dataRange;
41943
+ }
41944
+
41898
41945
  }
41899
41946
  } else {
41900
41947
  // Individual track scaling
@@ -41974,6 +42021,7 @@ class MergedTrack extends TrackBase {
41974
42021
  if (groupAutoscale) {
41975
42022
  track.autoscaleGroup = name;
41976
42023
  }
42024
+ track.isMergedTrack = false;
41977
42025
  browser.addTrack(track.config, track);
41978
42026
  }
41979
42027
  browser.updateViews();
@@ -41987,25 +42035,30 @@ class MergedTrack extends TrackBase {
41987
42035
 
41988
42036
  class MergedFeatureCollection {
41989
42037
 
41990
- constructor(featureArrays) {
42038
+ constructor(featureArrays,trackNames) {
41991
42039
  this.featureArrays = featureArrays;
42040
+ //trackNames is needed for the popup data to populate track names
42041
+ //preserving the order of the actual tracks
42042
+ this.trackNames = trackNames;
41992
42043
  }
41993
42044
 
41994
42045
  getMax(start, end) {
41995
42046
  let max = -Number.MAX_VALUE;
41996
42047
 
41997
42048
  for (let a of this.featureArrays) {
41998
- for (let f of a) {
41999
- if (typeof f.value === 'undefined' || Number.isNaN(f.value)) {
42000
- continue
42001
- }
42002
- if (f.end < start) {
42003
- continue
42004
- }
42005
- if (f.start > end) {
42006
- break
42049
+ if (Array.isArray(a)) {
42050
+ for (let f of a) {
42051
+ if (typeof f.value === 'undefined' || Number.isNaN(f.value)) {
42052
+ continue
42053
+ }
42054
+ if (f.end < start) {
42055
+ continue
42056
+ }
42057
+ if (f.start > end) {
42058
+ break
42059
+ }
42060
+ max = Math.max(max, f.value);
42007
42061
  }
42008
- max = Math.max(max, f.value);
42009
42062
  }
42010
42063
  }
42011
42064
 
@@ -42016,15 +42069,17 @@ class MergedFeatureCollection {
42016
42069
  getMin(start, end) {
42017
42070
  let min = 0;
42018
42071
  for (let a of this.featureArrays) {
42019
- for (let f of a) {
42020
- if (typeof f.value !== 'undefined' && !Number.isNaN(f.value)) {
42021
- if (f.end < start) {
42022
- continue
42023
- }
42024
- if (f.start > end) {
42025
- break
42072
+ if (Array.isArray(a)) {
42073
+ for (let f of a) {
42074
+ if (typeof f.value !== 'undefined' && !Number.isNaN(f.value)) {
42075
+ if (f.end < start) {
42076
+ continue
42077
+ }
42078
+ if (f.start > end) {
42079
+ break
42080
+ }
42081
+ min = Math.min(min, f.value);
42026
42082
  }
42027
- min = Math.min(min, f.value);
42028
42083
  }
42029
42084
  }
42030
42085
  }
@@ -42032,6 +42087,16 @@ class MergedFeatureCollection {
42032
42087
  }
42033
42088
  }
42034
42089
 
42090
+ /**
42091
+ * Heuristic for finding numeric tracks.
42092
+ *
42093
+ * @param tracks
42094
+ * @returns {*}
42095
+ */
42096
+ const numericTracks = (tracks) => {
42097
+ return tracks ? tracks.filter(track => undefined !== track.dataRange || undefined !== track.autoscale || undefined !== track.autoscaleGroup) : []
42098
+ };
42099
+
42035
42100
  class OverlayTrackButton extends NavbarButton {
42036
42101
  constructor(browser, parent) {
42037
42102
 
@@ -42077,13 +42142,13 @@ function trackOverlayClickHandler(e) {
42077
42142
  {
42078
42143
  name: 'Overlay',
42079
42144
  type: 'merged',
42145
+ autoscale: false,
42080
42146
  alpha: 0.5, //fudge * (1.0/tracks.length),
42081
42147
  height: Math.max(...tracks.map(({ height }) => height)),
42082
42148
  order: Math.min(...tracks.map(({ order }) => order)),
42083
- _tracks: flattenedTracks
42084
42149
  };
42085
42150
 
42086
- const mergedTrack = new MergedTrack(config, this.browser);
42151
+ const mergedTrack = new MergedTrack(config, this.browser, flattenedTracks);
42087
42152
 
42088
42153
  for (const track of tracks) {
42089
42154
  this.browser.removeTrack(track);
@@ -42303,27 +42368,6 @@ class TrackView {
42303
42368
  }
42304
42369
  }
42305
42370
 
42306
- get dataRange() {
42307
- return this.track.dataRange ? this.track.dataRange : undefined
42308
- }
42309
-
42310
- set dataRange({ min, max }) {
42311
-
42312
- this.track.dataRange = { min, max };
42313
-
42314
- this.track.autoscale = false;
42315
- this.track.autoscaleGroup = undefined;
42316
-
42317
- const list = this.browser.trackViews.filter(({track}) => track.autoscaleGroup);
42318
- if (1 === list.length) {
42319
- list[0].track.autoscale = false;
42320
- list[0].track.autoscaleGroup = undefined;
42321
- list[0].repaintViews();
42322
- }
42323
-
42324
- this.repaintViews();
42325
-
42326
- }
42327
42371
 
42328
42372
  presentColorPicker(key) {
42329
42373
 
@@ -49772,46 +49816,41 @@ const BamUtils = {
49772
49816
  },
49773
49817
 
49774
49818
  /**
49819
+ * @param ba - UInt8Array bytes to decode
49775
49820
  *
49776
- * @param ba bytes to decode as a UInt8Array
49777
- * @param genome optional igv genome object
49778
- * @returns {{ magicNumer: number, size: number, chrNames: Array, chrToIndex: ({}|*), chrAliasTable: ({}|*) }}
49821
+ * @returns {{size: *, chrNames: *[], magicNumber: *, chrToIndex: {}}}
49779
49822
  */
49780
- decodeBamHeader: function (ba, genome) {
49823
+ decodeBamHeader: function (ba) {
49781
49824
 
49782
- var magic, samHeaderLen, samHeader, chrToIndex, chrNames;
49783
49825
 
49784
- magic = readInt(ba, 0);
49826
+ const magic = readInt(ba, 0);
49785
49827
  if (magic !== BAM1_MAGIC_NUMBER) {
49786
49828
  throw new Error('BAM header errror: bad magic number. This could be caused by either a corrupt or missing file.')
49787
49829
  }
49788
49830
 
49789
- samHeaderLen = readInt(ba, 4);
49790
- samHeader = '';
49791
-
49831
+ const samHeaderLen = readInt(ba, 4);
49832
+ let samHeader = '';
49792
49833
  for (var i = 0; i < samHeaderLen; ++i) {
49793
49834
  samHeader += String.fromCharCode(ba[i + 8]);
49794
49835
  }
49795
49836
 
49796
- var nRef = readInt(ba, samHeaderLen + 8);
49797
- var p = samHeaderLen + 12;
49837
+ const nRef = readInt(ba, samHeaderLen + 8);
49838
+ let p = samHeaderLen + 12;
49798
49839
 
49799
- chrToIndex = {};
49800
- chrNames = [];
49840
+ const chrToIndex = {};
49841
+ const chrNames = [];
49801
49842
 
49802
49843
  for (i = 0; i < nRef; ++i) {
49803
- var lName = readInt(ba, p);
49804
- var name = '';
49805
- for (var j = 0; j < lName - 1; ++j) {
49844
+ const len = readInt(ba, p);
49845
+ let name = '';
49846
+ for (var j = 0; j < len - 1; ++j) {
49806
49847
  name += String.fromCharCode(ba[p + 4 + j]);
49807
49848
  }
49808
- readInt(ba, p + lName + 4);
49809
- //dlog(name + ': ' + lRef);
49810
49849
 
49811
49850
  chrToIndex[name] = i;
49812
49851
  chrNames[i] = name;
49813
49852
 
49814
- p = p + 8 + lName;
49853
+ p = p + 8 + len;
49815
49854
  }
49816
49855
 
49817
49856
  return {
@@ -50801,8 +50840,8 @@ class HtsgetBamReader extends HtsgetReader {
50801
50840
  const ba = unbgzf(compressedData.buffer);
50802
50841
  this.header = BamUtils.decodeBamHeader(ba, this.genome);
50803
50842
  this.chrAliasTable = new Map();
50804
- for (let key of Object.keys(this.header.chrAliasTable)) {
50805
- this.chrAliasTable.set(key, this.header.chrAliasTable[key]);
50843
+ for (let name of this.header.chrNames) {
50844
+ this.chrAliasTable.set(name, this.genome.getChromosomeName(name));
50806
50845
  }
50807
50846
  }
50808
50847
 
@@ -50812,6 +50851,7 @@ class HtsgetBamReader extends HtsgetReader {
50812
50851
 
50813
50852
  // BAM decoding
50814
50853
  const ba = unbgzf(compressedData.buffer);
50854
+ this.header = BamUtils.decodeBamHeader(ba, this.genome);
50815
50855
 
50816
50856
  const chrIdx = this.header.chrToIndex[chr];
50817
50857
  const alignmentContainer = new AlignmentContainer(chr, start, end, this.config);
@@ -57656,6 +57696,7 @@ class CoverageTrack {
57656
57696
 
57657
57697
 
57658
57698
  constructor(config, parent) {
57699
+ this.featureType = 'numeric';
57659
57700
  this.parent = parent;
57660
57701
  this.featureSource = parent.featureSource;
57661
57702
 
@@ -66134,12 +66175,12 @@ class CNVPytorTrack extends TrackBase {
66134
66175
  if (this.signals.includes(signal_name)) {
66135
66176
  let tconf = {};
66136
66177
  tconf.type = "wig";
66137
- tconf.isMergedTrack = true;
66138
66178
  tconf.features = wig;
66139
66179
  tconf.name = signal_name;
66140
66180
  tconf.color = this.signal_colors.filter(x => x.singal_name === signal_name).map(x => x.color);
66141
66181
  const t = await this.browser.createTrack(tconf);
66142
66182
  if (t) {
66183
+ t.isMergedTrack = true;
66143
66184
  t.autoscale = false; // Scaling done from merged track
66144
66185
  this.tracks.push(t);
66145
66186
  } else {
@@ -66318,12 +66359,12 @@ class CNVPytorTrack extends TrackBase {
66318
66359
  if (this.signals.includes(signal_name)) {
66319
66360
  let tconf = {};
66320
66361
  tconf.type = "wig";
66321
- tconf.isMergedTrack = true;
66322
66362
  tconf.features = wig;
66323
66363
  tconf.name = signal_name;
66324
66364
  tconf.color = this.signal_colors.filter(x => x.singal_name === signal_name).map(x => x.color);
66325
66365
  const t = await this.browser.createTrack(tconf);
66326
66366
  if (t) {
66367
+ t.isMergedTrack = true;
66327
66368
  t.autoscale = false; // Scaling done from merged track
66328
66369
  this.tracks.push(t);
66329
66370
  } else {
@@ -66716,23 +66757,26 @@ class VariantTrack extends TrackBase {
66716
66757
  this.header = await this.getHeader();
66717
66758
 
66718
66759
  // Set colorBy, if not explicitly set default to allele frequency, if available, otherwise default to none (undefined)
66719
- const infoFields = new Set(Object.keys(this.header.INFO));
66720
- if (this.config.colorBy) {
66721
- this.colorBy = this.config.colorBy;
66722
- } else if (!this.config.color && infoFields.has('AF')) {
66723
- this.colorBy = 'AF';
66724
- }
66760
+ if(this.header.INFO) {
66761
+ const infoFields = new Set(Object.keys(this.header.INFO));
66762
+ if (this.config.colorBy) {
66763
+ this.colorBy = this.config.colorBy;
66764
+ } else if (!this.config.color && infoFields.has('AF')) {
66765
+ this.colorBy = 'AF';
66766
+ }
66725
66767
 
66726
- // Configure menu items based on info available
66727
- if (infoFields.has('AF')) {
66728
- this._colorByItems.set('AF', 'Allele frequency');
66729
- }
66730
- if (infoFields.has('VT')) {
66731
- this._colorByItems.set('VT', 'Variant Type');
66732
- }
66733
- if (infoFields.has('SVTYPE')) {
66734
- this._colorByItems.set('SVTYPE', 'SV Type');
66768
+ // Configure menu items based on info available
66769
+ if (infoFields.has('AF')) {
66770
+ this._colorByItems.set('AF', 'Allele frequency');
66771
+ }
66772
+ if (infoFields.has('VT')) {
66773
+ this._colorByItems.set('VT', 'Variant Type');
66774
+ }
66775
+ if (infoFields.has('SVTYPE')) {
66776
+ this._colorByItems.set('SVTYPE', 'SV Type');
66777
+ }
66735
66778
  }
66779
+
66736
66780
  if (this.config.colorBy && !this._colorByItems.has(this.config.colorBy)) {
66737
66781
  this._colorByItems.set(this.config.colorBy, this.config.colorBy);
66738
66782
  }
@@ -69577,11 +69621,15 @@ someMotifValues.forEach(motif => {
69577
69621
  JUNCTION_MOTIF_PALETTE.getColor(motif);
69578
69622
  });
69579
69623
 
69580
- // rendering context with values that only need to be computed once per render, rather than for each splice junction
69581
- const junctionRenderingContext = {};
69582
69624
 
69583
69625
  class SpliceJunctionTrack extends TrackBase {
69584
69626
 
69627
+ static defaults = {
69628
+ margin: 10,
69629
+ colorByNumReadsThreshold: 5,
69630
+ height: 100
69631
+ }
69632
+
69585
69633
  constructor(config, browser) {
69586
69634
  super(config, browser);
69587
69635
  }
@@ -69602,16 +69650,6 @@ class SpliceJunctionTrack extends TrackBase {
69602
69650
  FeatureSource(config, this.browser.genome);
69603
69651
  }
69604
69652
 
69605
- this.margin = config.margin === undefined ? 10 : config.margin;
69606
-
69607
- if (!this.height) {
69608
- this.height = 100;
69609
- }
69610
-
69611
- //set defaults
69612
- if (config.colorByNumReadsThreshold === undefined) {
69613
- config.colorByNumReadsThreshold = 5;
69614
- }
69615
69653
  }
69616
69654
 
69617
69655
  async postInit() {
@@ -69666,13 +69704,16 @@ class SpliceJunctionTrack extends TrackBase {
69666
69704
  const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
69667
69705
 
69668
69706
 
69669
- if (!this.config.isMergedTrack) {
69707
+ if (!this.isMergedTrack) {
69670
69708
  IGVGraphics.fillRect(ctx, 0, options.pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
69671
69709
  }
69672
69710
 
69673
69711
  if (featureList) {
69674
69712
 
69675
69713
 
69714
+ // rendering context with values that only need to be computed once per render, rather than for each splice junction
69715
+ const junctionRenderingContext = {};
69716
+
69676
69717
  junctionRenderingContext.referenceFrame = options.viewport.referenceFrame;
69677
69718
  junctionRenderingContext.referenceFrameStart = junctionRenderingContext.referenceFrame.start;
69678
69719
  junctionRenderingContext.referenceFrameEnd = junctionRenderingContext.referenceFrameStart +
@@ -69685,7 +69726,7 @@ class SpliceJunctionTrack extends TrackBase {
69685
69726
  for (let feature of featureList) {
69686
69727
  if (feature.end < bpStart) continue
69687
69728
  if (feature.start > bpEnd) break
69688
- this.renderJunction(feature, bpStart, bpPerPixel, pixelHeight, ctx);
69729
+ this.renderJunction(feature, bpStart, bpPerPixel, pixelHeight, ctx, junctionRenderingContext);
69689
69730
  }
69690
69731
 
69691
69732
  } else {
@@ -69702,7 +69743,7 @@ class SpliceJunctionTrack extends TrackBase {
69702
69743
  * @param pixelHeight pixel height of the current canvas
69703
69744
  * @param ctx the canvas 2d context
69704
69745
  */
69705
- renderJunction(feature, bpStart, xScale, pixelHeight, ctx) {
69746
+ renderJunction(feature, bpStart, xScale, pixelHeight, ctx, junctionRenderingContext) {
69706
69747
  // cache whether this junction is rendered or filtered out. Use later to exclude non-rendered junctions from click detection.
69707
69748
  feature.isVisible = false;
69708
69749
 
@@ -69786,7 +69827,7 @@ class SpliceJunctionTrack extends TrackBase {
69786
69827
  }
69787
69828
 
69788
69829
  const py = this.margin;
69789
- const rowHeight = this.height;
69830
+ const rowHeight = pixelHeight;
69790
69831
 
69791
69832
  const cy = py + 0.5 * rowHeight;
69792
69833
  let topY = py;
@@ -70471,7 +70512,7 @@ function createReferenceFrameList(loci, genome, browserFlanking, minimumBases, v
70471
70512
  })
70472
70513
  }
70473
70514
 
70474
- const _version = "3.0.1";
70515
+ const _version = "3.0.2";
70475
70516
  function version() {
70476
70517
  return _version
70477
70518
  }
@@ -72922,7 +72963,7 @@ class ChromAliasBB {
72922
72963
  }
72923
72964
 
72924
72965
  /**
72925
- * Return the canonical chromosome name for the alias. If none found return the alias.
72966
+ * Return the cached canonical chromosome name for the alias. If none found return the alias.
72926
72967
  *
72927
72968
  * Note this will only work if a "search" for ths chromosome has been performed previously.
72928
72969
  *