igv 2.15.7 → 2.15.9

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/README.md CHANGED
@@ -18,19 +18,19 @@ Below are examples and a quickstart guide. See the [Wiki](https://github.com/ig
18
18
 
19
19
  # Examples
20
20
 
21
- ***[Alignments](https://igv.org/web/release/2.15.7/examples/cram-vcf.html)***
21
+ ***[Alignments](https://igv.org/web/release/2.15.9/examples/cram-vcf.html)***
22
22
 
23
- ***[Interactions](https://igv.org/web/release/2.15.7/examples/interact.html)***
23
+ ***[Interactions](https://igv.org/web/release/2.15.9/examples/interact.html)***
24
24
 
25
- ***[Copy number](https://igv.org/web/release/2.15.7/examples/copyNumber.html)***
25
+ ***[Copy number](https://igv.org/web/release/2.15.9/examples/copyNumber.html)***
26
26
 
27
- ***[Multiple regions](https://igv.org/web/release/2.15.7/examples/multi-locus.html)***
27
+ ***[Multiple regions](https://igv.org/web/release/2.15.9/examples/multi-locus.html)***
28
28
 
29
- ***[Mutation Annotation Format (MAF)](https://igv.org/web/release/2.15.7/examples/maf-tcga.html)***
29
+ ***[Mutation Annotation Format (MAF)](https://igv.org/web/release/2.15.9/examples/maf-tcga.html)***
30
30
 
31
- ***[Variant color options](https://igv.org/web/release/2.15.7/examples/variant-colors.html)***
31
+ ***[Variant color options](https://igv.org/web/release/2.15.9/examples/variant-colors.html)***
32
32
 
33
- ***[More](https://igv.org/web/release/2.15.7/examples/)***
33
+ ***[More](https://igv.org/web/release/2.15.9/examples/)***
34
34
 
35
35
 
36
36
  # Quickstart
@@ -39,18 +39,18 @@ Below are examples and a quickstart guide. See the [Wiki](https://github.com/ig
39
39
  igv.js consists of a single javascript file with no external dependencies.
40
40
 
41
41
  Pre-built files for script include, AMD, or CJS module systems (igv.min.js) and an ES6 module (igv.esm.min.js)
42
- can be downloaded from [https://cdn.jsdelivr.net/npm/igv@2.15.7/dist/](https://cdn.jsdelivr.net/npm/igv@2.15.7/dist/).
42
+ can be downloaded from [https://cdn.jsdelivr.net/npm/igv@2.15.9/dist/](https://cdn.jsdelivr.net/npm/igv@2.15.9/dist/).
43
43
 
44
44
  To import igv as an ES6 module
45
45
 
46
46
  ```javascript
47
- import igv from "https://cdn.jsdelivr.net/npm/igv@2.15.7/dist/igv.esm.min.js"
47
+ import igv from "https://cdn.jsdelivr.net/npm/igv@2.15.9/dist/igv.esm.min.js"
48
48
  ```
49
49
 
50
50
  Or as a script include (defines the "igv" global)
51
51
 
52
52
  ```html
53
- <script src="https://cdn.jsdelivr.net/npm/igv@2.15.7/dist/igv.min.js"></script>
53
+ <script src="https://cdn.jsdelivr.net/npm/igv@2.15.9/dist/igv.min.js"></script>
54
54
  ```
55
55
 
56
56
  Alternatively you can install with npm
package/dist/igv.esm.js CHANGED
@@ -9675,6 +9675,7 @@ const MenuUtils = {
9675
9675
  menuItems.push(unsetColorMenuItem({trackView, label: "Unset track color"}));
9676
9676
  if(trackView.track.config.type === 'wig' || trackView.track.config.type === 'annotation') {
9677
9677
  menuItems.push(colorPickerMenuItem({trackView, label: "Set alt color", option: "altColor"}));
9678
+ menuItems.push(unsetAltColorMenuItem({trackView, label: "Unset alt color"}));
9678
9679
  }
9679
9680
  }
9680
9681
 
@@ -9876,6 +9877,20 @@ function unsetColorMenuItem({trackView, label}) {
9876
9877
  }
9877
9878
  }
9878
9879
 
9880
+ function unsetAltColorMenuItem({trackView, label}) {
9881
+
9882
+ const $e = $$1('<div>');
9883
+ $e.text(label);
9884
+
9885
+ return {
9886
+ object: $e,
9887
+ click: () => {
9888
+ trackView.track.altColor = undefined;
9889
+ trackView.repaintViews();
9890
+ }
9891
+ }
9892
+ }
9893
+
9879
9894
  function trackRenameMenuItem(trackView) {
9880
9895
 
9881
9896
  const click = e => {
@@ -18659,7 +18674,6 @@ class IGVXhr {
18659
18674
 
18660
18675
  const self = this;
18661
18676
 
18662
- //console.log(`${Date.now()} ${url}`)
18663
18677
  url = mapUrl$1(url);
18664
18678
 
18665
18679
  options = options || {};
@@ -18709,7 +18723,10 @@ class IGVXhr {
18709
18723
  }
18710
18724
 
18711
18725
  if (range) {
18712
- var rangeEnd = range.size ? range.start + range.size - 1 : "";
18726
+ let rangeEnd = "";
18727
+ if (range.size) {
18728
+ rangeEnd = range.start + range.size - 1;
18729
+ }
18713
18730
  xhr.setRequestHeader("Range", "bytes=" + range.start + "-" + rangeEnd);
18714
18731
  // xhr.setRequestHeader("Cache-Control", "no-cache"); <= This can cause CORS issues, disabled for now
18715
18732
  }
@@ -18735,20 +18752,34 @@ class IGVXhr {
18735
18752
  }
18736
18753
 
18737
18754
  xhr.onload = async function (event) {
18738
- // when the url points to a local file, the status is 0 but that is not an error
18755
+
18756
+ // when the url points to a local file, the status is 0
18739
18757
  if (xhr.status === 0 || (xhr.status >= 200 && xhr.status <= 300)) {
18740
- if (range && xhr.status !== 206 && range.start !== 0) {
18741
- // For small files a range starting at 0 can return the whole file => 200
18742
- // Provide just the slice we asked for, throw out the rest quietly
18743
- // If file is large warn user
18744
- if (xhr.response.length > 100000 && !self.RANGE_WARNING_GIVEN) {
18745
- alert(`Warning: Range header ignored for URL: ${url}. This can have severe performance impacts.`);
18758
+ if ("HEAD" === options.method) {
18759
+ // Support fetching specific headers. Attempting to fetch all headers can be problematic with CORS
18760
+ const headers = options.requestedHeaders || ['content-length'];
18761
+ const headerMap = {};
18762
+ for (let h of headers) {
18763
+ headerMap[h] = xhr.getResponseHeader(h);
18746
18764
  }
18747
- resolve(xhr.response.slice(range.start, range.start + range.size));
18748
-
18765
+ resolve(headerMap);
18749
18766
  } else {
18750
- resolve(xhr.response);
18767
+ // Assume "GET" or "POST"
18768
+ if (range && xhr.status !== 206 && range.start !== 0) {
18769
+
18770
+ // For small files a range starting at 0 can return the whole file => 200
18771
+ // Provide just the slice we asked for, throw out the rest quietly
18772
+ // If file is large warn user
18773
+ if (xhr.response.length > 100000 && !self.RANGE_WARNING_GIVEN) {
18774
+ alert(`Warning: Range header ignored for URL: ${url}. This can have severe performance impacts.`);
18775
+ }
18776
+ resolve(xhr.response.slice(range.start, range.start + range.size));
18777
+ } else {
18778
+ resolve(xhr.response);
18779
+ }
18751
18780
  }
18781
+ } else if (xhr.status === 416) {
18782
+ handleError(Error(`416 Unsatisfiable Range`));
18752
18783
  } else if ((typeof gapi !== "undefined") &&
18753
18784
  ((xhr.status === 404 || xhr.status === 401 || xhr.status === 403) &&
18754
18785
  isGoogleURL(url)) &&
@@ -18758,9 +18789,6 @@ class IGVXhr {
18758
18789
  } else {
18759
18790
  if (xhr.status === 403) {
18760
18791
  handleError("Access forbidden: " + url);
18761
- } else if (xhr.status === 416) {
18762
- // Tried to read off the end of the file. This shouldn't happen, but if it does return an
18763
- handleError("Unsatisfiable range");
18764
18792
  } else {
18765
18793
  handleError(xhr.status);
18766
18794
  }
@@ -18892,6 +18920,24 @@ class IGVXhr {
18892
18920
  }
18893
18921
  }
18894
18922
  }
18923
+
18924
+ /**
18925
+ * This method should only be called when it is known the server supports HEAD requests. It is used to recover
18926
+ * from 416 errors from out-of-spec WRT range request servers. Notably Globus.
18927
+ * * *
18928
+ * @param url
18929
+ * @param options
18930
+ * @returns {Promise<unknown>}
18931
+ */
18932
+ async getContentLength(url, options) {
18933
+ options = options || {};
18934
+ options.method = 'HEAD';
18935
+ options.requestedHeaders = ['content-length'];
18936
+ const headerMap = await this._loadURL(url, options);
18937
+ const contentLengthString = headerMap['content-length'];
18938
+ return contentLengthString ? Number.parseInt(contentLengthString) : 0
18939
+ }
18940
+
18895
18941
  }
18896
18942
 
18897
18943
  function isGoogleStorageSigned(url) {
@@ -21101,6 +21147,10 @@ async function inferFileFormatFromHeader(config) {
21101
21147
 
21102
21148
  }
21103
21149
 
21150
+ function registerFileFormats(name, fields) {
21151
+ FileFormats[name] = {fields: fields};
21152
+ }
21153
+
21104
21154
  var TrackUtils = /*#__PURE__*/Object.freeze({
21105
21155
  __proto__: null,
21106
21156
  knownFileExtensions: knownFileExtensions,
@@ -21108,7 +21158,8 @@ var TrackUtils = /*#__PURE__*/Object.freeze({
21108
21158
  inferFileFormat: inferFileFormat,
21109
21159
  inferFileFormatFromHeader: inferFileFormatFromHeader,
21110
21160
  inferTrackType: inferTrackType,
21111
- inferIndexPath: inferIndexPath
21161
+ inferIndexPath: inferIndexPath,
21162
+ registerFileFormats: registerFileFormats
21112
21163
  });
21113
21164
 
21114
21165
  const pairs =
@@ -23938,7 +23989,7 @@ const Cytoband = function (start, end, name, typestain) {
23938
23989
  }
23939
23990
  };
23940
23991
 
23941
- const _version = "2.15.7";
23992
+ const _version = "2.15.9";
23942
23993
  function version() {
23943
23994
  return _version
23944
23995
  }
@@ -27077,10 +27128,10 @@ class TrackBase {
27077
27128
 
27078
27129
  static defaults = {
27079
27130
  height: 50,
27080
- color: 'rgb(0, 0, 150)',
27081
- altColor: 'rgb(0, 0, 150)',
27082
27131
  autoHeight: false,
27083
- visibilityWindow: undefined,
27132
+ visibilityWindow: undefined, // Identifies property that should be copied from config
27133
+ color: undefined, // Identifies property that should be copied from config
27134
+ altColor: undefined, // Identifies property that should be copied from config
27084
27135
  supportHiDPI: true
27085
27136
  }
27086
27137
 
@@ -31950,6 +32001,7 @@ class TextFeatureSource {
31950
32001
  this.queryable = true;
31951
32002
  } else if ("htsget" === config.sourceType) {
31952
32003
  this.reader = new HtsgetVariantReader(config, genome);
32004
+ this.queryable = true;
31953
32005
  } else if (config.sourceType === 'ucscservice') {
31954
32006
  this.reader = new UCSCServiceReader(config.source);
31955
32007
  this.queryable = true;
@@ -32165,7 +32217,7 @@ class BufferedReader {
32165
32217
  */
32166
32218
  async dataViewForRange(requestedRange, asUint8, retries = 0) {
32167
32219
  try {
32168
- console.log(`buffered reader ${requestedRange}`);
32220
+
32169
32221
  const hasData = (this.data && (this.range.start <= requestedRange.start) &&
32170
32222
  ((this.range.start + this.range.size) >= (requestedRange.start + requestedRange.size)));
32171
32223
 
@@ -40410,6 +40462,9 @@ function renderFusionJuncSpan(feature, bpStart, xScale, pixelHeight, ctx) {
40410
40462
  }
40411
40463
  }
40412
40464
 
40465
+ const DEFAULT_COLOR$2 = 'rgb(0, 0, 150)';
40466
+
40467
+
40413
40468
  class FeatureTrack extends TrackBase {
40414
40469
 
40415
40470
  static defaults = {
@@ -40841,8 +40896,11 @@ class FeatureTrack extends TrackBase {
40841
40896
  color = this.colorTable.getColor(value);
40842
40897
  } else if (feature.color) {
40843
40898
  color = feature.color; // Explicit color for feature
40844
- } else {
40845
- color = this.color; // Track default
40899
+ }
40900
+
40901
+ // If no explicit setting use the default
40902
+ if (!color) {
40903
+ color = DEFAULT_COLOR$2; // Track default
40846
40904
  }
40847
40905
 
40848
40906
  if (feature.alpha && feature.alpha !== 1) {
@@ -41427,8 +41485,6 @@ class BAMTrack extends TrackBase {
41427
41485
  showAllBases: false,
41428
41486
  showInsertions: true,
41429
41487
  showMismatches: true,
41430
- color: DEFAULT_ALIGNMENT_COLOR,
41431
- coverageColor: DEFAULT_COVERAGE_COLOR,
41432
41488
  height: 300,
41433
41489
  coverageTrackHeight: 50
41434
41490
  }
@@ -41448,6 +41504,10 @@ class BAMTrack extends TrackBase {
41448
41504
 
41449
41505
  this.alignmentTrack.setTop(this.coverageTrack, this.showCoverage);
41450
41506
 
41507
+ if(!this.showAlignments) {
41508
+ this._height = this.coverageTrackHeight;
41509
+ }
41510
+
41451
41511
  // The sort object can be an array in the case of multi-locus view, however if multiple sort positions
41452
41512
  // are present for a given reference frame the last one will take precedence
41453
41513
  if (config.sort) {
@@ -41924,15 +41984,6 @@ class BAMTrack extends TrackBase {
41924
41984
  }
41925
41985
  const chords = makePairedAlignmentChords(inView);
41926
41986
  sendChords(chords, this, refFrame, 0.02);
41927
-
41928
- // const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.02)
41929
- // const trackColor = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.02)
41930
- //
41931
- // // name the chord set to include track name and locus
41932
- // const encodedName = this.name.replaceAll(' ', '%20')
41933
- // const chordSetName = "all" === refFrame.chr ? encodedName :
41934
- // `${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end}`
41935
- // this.browser.circularView.addChords(chords, {name: chordSetName, color: chordSetColor, trackColor: trackColor})
41936
41987
  }
41937
41988
 
41938
41989
  addSplitChordsForViewport(viewport) {
@@ -41949,15 +42000,6 @@ class BAMTrack extends TrackBase {
41949
42000
 
41950
42001
  const chords = makeSupplementalAlignmentChords(inView);
41951
42002
  sendChords(chords, this, refFrame, 0.02);
41952
-
41953
- // const chordSetColor = IGVColor.addAlpha("all" === refFrame.chr ? this.color : getChrColor(refFrame.chr), 0.02)
41954
- // const trackColor = IGVColor.addAlpha(this.color || 'rgb(0,0,255)', 0.02)
41955
- //
41956
- // // name the chord set to include track name and locus
41957
- // const encodedName = this.name.replaceAll(' ', '%20')
41958
- // const chordSetName = "all" === refFrame.chr ? encodedName :
41959
- // `${encodedName} (${refFrame.chr}:${refFrame.start}-${refFrame.end}`
41960
- // this.browser.circularView.addChords(chords, {name: chordSetName, color: chordSetColor, trackColor: trackColor})
41961
42003
  }
41962
42004
  }
41963
42005
 
@@ -42014,7 +42056,7 @@ class CoverageTrack {
42014
42056
  let color;
42015
42057
  if (this.parent.coverageColor) {
42016
42058
  color = this.parent.coverageColor;
42017
- } else if (this.parent.color !== undefined && typeof this.parent.color !== "function") {
42059
+ } else if (this.parent.color && typeof this.parent.color !== "function") {
42018
42060
  color = IGVColor.darkenLighten(this.parent.color, -35);
42019
42061
  } else {
42020
42062
  color = DEFAULT_COVERAGE_COLOR;
@@ -42855,8 +42897,9 @@ class AlignmentTrack {
42855
42897
  case "tag":
42856
42898
  if (this.parent.color) {
42857
42899
  return (typeof this.parent.color === "function") ? this.parent.color(alignment) : this.parent.color
42900
+ } else {
42901
+ return DEFAULT_CONNECTOR_COLOR
42858
42902
  }
42859
- return DEFAULT_CONNECTOR_COLOR
42860
42903
  default:
42861
42904
  return this.getAlignmentColor(alignment)
42862
42905
 
@@ -42868,6 +42911,8 @@ class AlignmentTrack {
42868
42911
  let color = DEFAULT_ALIGNMENT_COLOR; // The default color if nothing else applies
42869
42912
  if (this.parent.color) {
42870
42913
  color = (typeof this.parent.color === "function") ? this.parent.color(alignment) : this.parent.color;
42914
+ } else {
42915
+ color = DEFAULT_ALIGNMENT_COLOR;
42871
42916
  }
42872
42917
  const option = this.colorBy;
42873
42918
  switch (option) {
@@ -43985,7 +44030,7 @@ class TrackView {
43985
44030
  const {width} = viewport.$viewport.get(0).getBoundingClientRect();
43986
44031
  delta.deltaX += width;
43987
44032
  }
43988
-
44033
+
43989
44034
  if (true === this.browser.showSampleNames) {
43990
44035
  this.sampleNameViewport.renderSVGContext(context, delta);
43991
44036
  }
@@ -44679,12 +44724,12 @@ function renderSVGAxis(context, track, axisCanvas, deltaX, deltaY) {
44679
44724
  * THE SOFTWARE.
44680
44725
  */
44681
44726
 
44727
+ const DEFAULT_COLOR$1 = 'rgb(150, 150, 150)';
44728
+
44682
44729
  class WigTrack extends TrackBase {
44683
44730
 
44684
44731
  static defaults = {
44685
44732
  height: 50,
44686
- color: 'rgb(150, 150, 150)',
44687
- altColor: 'rgb(150, 150, 150)',
44688
44733
  flipAxis: false,
44689
44734
  logScale: false,
44690
44735
  windowFunction: 'mean',
@@ -44817,7 +44862,7 @@ class WigTrack extends TrackBase {
44817
44862
  const pixelWidth = options.pixelWidth;
44818
44863
  options.pixelHeight;
44819
44864
  const bpEnd = bpStart + pixelWidth * bpPerPixel + 1;
44820
- const posColor = this.color || WigTrack.defaults.color;
44865
+ const posColor = this.color || DEFAULT_COLOR$1;
44821
44866
 
44822
44867
  let baselineColor;
44823
44868
  if (typeof posColor === "string" && posColor.startsWith("rgb(")) {
@@ -44961,7 +45006,7 @@ class WigTrack extends TrackBase {
44961
45006
  */
44962
45007
 
44963
45008
  getColorForFeature(f) {
44964
- let c = (f.value < 0 && this.altColor) ? this.altColor : this.color || WigTrack.defaults.color;
45009
+ let c = (f.value < 0 && this.altColor) ? this.altColor : this.color || DEFAULT_COLOR$1;
44965
45010
  return (typeof c === "function") ? c(f.value) : c
44966
45011
  }
44967
45012
 
@@ -46689,7 +46734,7 @@ function extractInfoColumn(data, str) {
46689
46734
 
46690
46735
  const isString = isString$2;
46691
46736
 
46692
-
46737
+ const DEFAULT_COLOR = "rgb(0,0,150)";
46693
46738
  const DEFAULT_VISIBILITY_WINDOW = 1000000;
46694
46739
  const TOP_MARGIN = 10;
46695
46740
  const STANDARD_FIELDS = new Map([["REF", "referenceBases"], ["ALT", "alternateBases"], ["QUAL", "quality"], ["FILTER", "filter"]]);
@@ -46739,6 +46784,7 @@ class VariantTrack extends TrackBase {
46739
46784
  this.colorTables = new Map();
46740
46785
  this.colorTables.set(config.colorBy, new ColorTable(config.colorTable));
46741
46786
  }
46787
+ this._color = config.color;
46742
46788
  this._strokecolor = config.strokecolor;
46743
46789
  this._context_hook = config.context_hook;
46744
46790
 
@@ -46771,7 +46817,7 @@ class VariantTrack extends TrackBase {
46771
46817
  }
46772
46818
 
46773
46819
  get color() {
46774
- return this._color
46820
+ return this._color || DEFAULT_COLOR
46775
46821
  }
46776
46822
 
46777
46823
  set color(c) {
@@ -59233,6 +59279,23 @@ class ROIManager {
59233
59279
  return regionElement
59234
59280
  }
59235
59281
 
59282
+ renderSVGContext(context, {deltaX, deltaY}) {
59283
+
59284
+ for (const regionElement of document.querySelectorAll('.igv-roi-region')) {
59285
+
59286
+ // body
59287
+ const { x, y, width, height } = regionElement.getBoundingClientRect();
59288
+ context.fillStyle = regionElement.style.backgroundColor;
59289
+ context.fillRect(x+deltaX, y+deltaY, width, height);
59290
+
59291
+ // header
59292
+ const header = regionElement.querySelector('div');
59293
+ const { x:xx, y:yy, width:ww, height:hh } = header.getBoundingClientRect();
59294
+ context.fillStyle = header.style.backgroundColor;
59295
+ context.fillRect(xx+deltaX, yy+deltaY, ww, hh);
59296
+ }
59297
+ }
59298
+
59236
59299
  async getUserDefinedROISet() {
59237
59300
  return this.roiSets.find(roiSet => true === roiSet.isUserDefined)
59238
59301
  }
@@ -60055,9 +60118,13 @@ class Browser {
60055
60118
  const context = new ctx(config);
60056
60119
 
60057
60120
  // tracks -> SVG
60121
+ const delta = {deltaX: 0, deltaY: -y};
60058
60122
  for (let trackView of this.trackViews) {
60059
- trackView.renderSVGContext(context, {deltaX: 0, deltaY: -y});
60123
+ trackView.renderSVGContext(context, delta);
60060
60124
  }
60125
+
60126
+ this.roiManager.renderSVGContext(context, delta);
60127
+
60061
60128
  // reset height to trim away unneeded svg canvas real estate. Yes, a bit of a hack.
60062
60129
  context.setHeight(height);
60063
60130
 
@@ -62112,7 +62179,8 @@ var index = {
62112
62179
  setOauthToken,
62113
62180
  oauth,
62114
62181
  version,
62115
- setApiKey
62182
+ setApiKey,
62183
+ registerFileFormats
62116
62184
  };
62117
62185
 
62118
62186
  export { index as default };