igv 2.10.2 → 2.10.3

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
@@ -12,19 +12,19 @@ Below are examples and a quickstart guide. See the [Wiki](https://github.com/ig
12
12
 
13
13
  # Examples
14
14
 
15
- ***[Alignments](https://igv.org/web/release/2.10.2/examples/cram-vcf.html)***
15
+ ***[Alignments](https://igv.org/web/release/2.10.3/examples/cram-vcf.html)***
16
16
 
17
- ***[Interactions](https://igv.org/web/release/2.10.2/examples/interact.html)***
17
+ ***[Interactions](https://igv.org/web/release/2.10.3/examples/interact.html)***
18
18
 
19
- ***[Copy number](https://igv.org/web/release/2.10.2/examples/copyNumber.html)***
19
+ ***[Copy number](https://igv.org/web/release/2.10.3/examples/copyNumber.html)***
20
20
 
21
- ***[Multiple regions](https://igv.org/web/release/2.10.2/examples/multi-locus.html)***
21
+ ***[Multiple regions](https://igv.org/web/release/2.10.3/examples/multi-locus.html)***
22
22
 
23
- ***[Mutation Annotation Format (MAF)](https://igv.org/web/release/2.10.2/examples/maf-tcga.html)***
23
+ ***[Mutation Annotation Format (MAF)](https://igv.org/web/release/2.10.3/examples/maf-tcga.html)***
24
24
 
25
- ***[Variant color options](https://igv.org/web/release/2.10.2/examples/variant-colors.html)***
25
+ ***[Variant color options](https://igv.org/web/release/2.10.3/examples/variant-colors.html)***
26
26
 
27
- ***[More](https://igv.org/web/release/2.10.2/examples/)***
27
+ ***[More](https://igv.org/web/release/2.10.3/examples/)***
28
28
 
29
29
 
30
30
  # Quickstart
@@ -33,18 +33,18 @@ Below are examples and a quickstart guide. See the [Wiki](https://github.com/ig
33
33
  igv.js consists of a single javascript file with no external dependencies.
34
34
 
35
35
  Pre-built files for ES5 (igv.min.js) and ES6 (igv.esm.min.js)
36
- can be downloaded from [https://cdn.jsdelivr.net/npm/igv@2.10.2/dist/](https://cdn.jsdelivr.net/npm/igv@2.10.2/dist/).
36
+ can be downloaded from [https://cdn.jsdelivr.net/npm/igv@2.10.3/dist/](https://cdn.jsdelivr.net/npm/igv@2.10.3/dist/).
37
37
 
38
38
  To import igv as an ES6 module
39
39
 
40
40
  ```javascript
41
- import igv from "https://cdn.jsdelivr.net/npm/igv@2.10.2/dist/igv.es6.min.js"
41
+ import igv from "https://cdn.jsdelivr.net/npm/igv@2.10.3/dist/igv.es6.min.js"
42
42
  ```
43
43
 
44
44
  Or as a script include (defines the "igv" global)
45
45
 
46
46
  ```html
47
- <script src="https://cdn.jsdelivr.net/npm/igv@2.10.2/dist/igv.min.js"></script>
47
+ <script src="https://cdn.jsdelivr.net/npm/igv@2.10.3/dist/igv.min.js"></script>
48
48
  ```
49
49
 
50
50
  Alternatively you can install with npm
package/dist/igv.esm.js CHANGED
@@ -8758,11 +8758,11 @@ async function resolveURL(url) {
8758
8758
  * @param urlOrFile
8759
8759
  */
8760
8760
 
8761
- function getFilename$1 (urlOrFile) {
8761
+ function getFilename$1(urlOrFile) {
8762
8762
 
8763
- if (urlOrFile instanceof File) {
8763
+ if (isFile(urlOrFile)) {
8764
8764
  return urlOrFile.name;
8765
- } else if (isString$3(urlOrFile)){
8765
+ } else if (isString$3(urlOrFile)) {
8766
8766
 
8767
8767
  let index = urlOrFile.lastIndexOf("/");
8768
8768
  let filename = index < 0 ? urlOrFile : urlOrFile.substr(index + 1);
@@ -8778,12 +8778,19 @@ function getFilename$1 (urlOrFile) {
8778
8778
  }
8779
8779
  }
8780
8780
 
8781
- function isFilePath (path) {
8782
- return (path instanceof File);
8781
+ /**
8782
+ * Test if object is a File or File-like object by testing for the "name" property. This is not a robust test,
8783
+ * but the purpose is to distinguish the object from url strings
8784
+ *
8785
+ * @param object
8786
+ */
8787
+ function isFile(object) {
8788
+ return object.hasOwnProperty("name")
8783
8789
  }
8784
8790
 
8791
+ const isFilePath = isFile; // deprecated
8785
8792
 
8786
- function download (filename, data) {
8793
+ function download(filename, data) {
8787
8794
 
8788
8795
  const element = document.createElement('a');
8789
8796
  element.setAttribute('href', data);
@@ -16789,7 +16796,7 @@ const igvxhr = {
16789
16796
  if (!options.responseType) {
16790
16797
  options.responseType = "arraybuffer";
16791
16798
  }
16792
- if (url instanceof File) {
16799
+ if (isFile(url)) {
16793
16800
  return loadFileSlice(url, options);
16794
16801
  } else {
16795
16802
  return load(url, options);
@@ -16828,7 +16835,7 @@ async function load(url, options) {
16828
16835
  // Resolve functions, promises, and functions that return promises
16829
16836
  url = await (typeof url === 'function' ? url() : url);
16830
16837
 
16831
- if (url instanceof File) {
16838
+ if (isFile(url)) {
16832
16839
  return loadFileSlice(url, options);
16833
16840
  } else if (typeof url.startsWith === 'function') { // Test for string
16834
16841
  if (url.startsWith("data:")) {
@@ -18117,7 +18124,8 @@ const MenuUtils = {
18117
18124
  "alignment" === track.type ||
18118
18125
  "annotation" === track.type ||
18119
18126
  "variant" === track.type ||
18120
- "wig" === track.type);
18127
+ "wig" === track.type) ||
18128
+ 'interact' === track.type
18121
18129
  },
18122
18130
 
18123
18131
  createMenuItem(label, action) {
@@ -18611,7 +18619,7 @@ class AlertDialog {
18611
18619
 
18612
18620
  let alertDialog;
18613
18621
 
18614
- const Alert$1 = {
18622
+ const Alert = {
18615
18623
 
18616
18624
  init(root) {
18617
18625
  if (!alertDialog) {
@@ -19230,7 +19238,7 @@ class DataRangeDialog {
19230
19238
  const min = parseFloat(this.$minimum_input.val());
19231
19239
  const max = parseFloat(this.$maximum_input.val());
19232
19240
  if (isNaN(min) || isNaN(max)) {
19233
- Alert$1.presentAlert(new Error('Must input numeric values'), undefined);
19241
+ Alert.presentAlert(new Error('Must input numeric values'), undefined);
19234
19242
  } else {
19235
19243
  trackView.setDataRange(min, max);
19236
19244
  }
@@ -20301,7 +20309,7 @@ class SequenceTrack {
20301
20309
  const start = viewport.referenceFrame.start;
20302
20310
  const end = start + bpWindow;
20303
20311
  const sequence = await this.browser.genome.sequence.getSequence(chr, start, end);
20304
- Alert$1.presentAlert(sequence);
20312
+ Alert.presentAlert(sequence);
20305
20313
  }
20306
20314
  },
20307
20315
  {
@@ -22475,7 +22483,7 @@ const Cytoband = function (start, end, name, typestain) {
22475
22483
  }
22476
22484
  };
22477
22485
 
22478
- const _version = "2.10.2";
22486
+ const _version = "2.10.3";
22479
22487
  function version() {
22480
22488
  return _version;
22481
22489
  }
@@ -22608,7 +22616,7 @@ const GenomeUtils = {
22608
22616
  const knownGenomes = GenomeUtils.KNOWN_GENOMES;
22609
22617
  const reference = knownGenomes[genomeID];
22610
22618
  if (!reference) {
22611
- Alert$1.presentAlert(new Error(`Unknown genome id: ${genomeID}`), undefined);
22619
+ Alert.presentAlert(new Error(`Unknown genome id: ${genomeID}`), undefined);
22612
22620
  }
22613
22621
  return reference;
22614
22622
  } else {
@@ -22960,7 +22968,7 @@ class TrackViewport extends Viewport {
22960
22968
 
22961
22969
  initializationHelper() {
22962
22970
 
22963
- this.$spinner = $('<div>', { class: 'igv-loading-spinner-container' });
22971
+ this.$spinner = $('<div>', {class: 'igv-loading-spinner-container'});
22964
22972
  this.$viewport.append(this.$spinner);
22965
22973
  this.$spinner.append($('<div>'));
22966
22974
 
@@ -23074,8 +23082,8 @@ class TrackViewport extends Viewport {
23074
23082
  const chrLength = this.browser.genome.getChromosome(chr).bpLength;
23075
23083
  const pixelWidth = this.$content.width();// * 3;
23076
23084
  const bpWidth = pixelWidth * referenceFrame.bpPerPixel;
23077
- const bpStart = Math.floor(Math.max(0, referenceFrame.start - bpWidth ));
23078
- const bpEnd = Math.ceil(Math.min(chrLength, referenceFrame.start + bpWidth + bpWidth)); // Add one screen width to end
23085
+ const bpStart = Math.floor(Math.max(0, referenceFrame.start - bpWidth));
23086
+ const bpEnd = Math.ceil(Math.min(chrLength, referenceFrame.start + bpWidth + bpWidth)); // Add one screen width to end
23079
23087
 
23080
23088
  if (this.loading && this.loading.start === bpStart && this.loading.end === bpEnd) {
23081
23089
  return undefined;
@@ -23537,8 +23545,8 @@ class TrackViewport extends Viewport {
23537
23545
  menuItems.push({label: $('<HR>')});
23538
23546
  }
23539
23547
 
23540
- menuItems.push({ label: 'Save Image (PNG)', click: () => this.saveImage() });
23541
- menuItems.push({ label: 'Save Image (SVG)', click: () => this.saveSVG() });
23548
+ menuItems.push({label: 'Save Image (PNG)', click: () => this.saveImage()});
23549
+ menuItems.push({label: 'Save Image (SVG)', click: () => this.saveSVG()});
23542
23550
 
23543
23551
  this.browser.menuPopup.presentTrackContextMenu(event, menuItems);
23544
23552
  }
@@ -23555,7 +23563,7 @@ class TrackViewport extends Viewport {
23555
23563
  }
23556
23564
 
23557
23565
  removeViewportMouseDownHandler(viewport) {
23558
- viewport.removeEventListener('mousedown', this.boundMouseDownHandler);
23566
+ viewport.removeEventListener('mousedown', this.boundMouseDownHandler);
23559
23567
  }
23560
23568
 
23561
23569
  addViewportTouchStartHandler(viewport) {
@@ -23636,9 +23644,9 @@ class TrackViewport extends Viewport {
23636
23644
  if (1 === this.browser.referenceFrameList.length) {
23637
23645
  string = chr;
23638
23646
  } else {
23639
- const loci = this.browser.referenceFrameList.map(({ locusSearchString }) => locusSearchString);
23647
+ const loci = this.browser.referenceFrameList.map(({locusSearchString}) => locusSearchString);
23640
23648
  const index = this.browser.referenceFrameList.indexOf(this.referenceFrame);
23641
- loci[ index ] = chr;
23649
+ loci[index] = chr;
23642
23650
  string = loci.join(' ');
23643
23651
  }
23644
23652
 
@@ -23694,7 +23702,7 @@ class TrackViewport extends Viewport {
23694
23702
 
23695
23703
  event.stopPropagation();
23696
23704
 
23697
- const { track } = this.trackView;
23705
+ const {track} = this.trackView;
23698
23706
 
23699
23707
  let str;
23700
23708
  if (typeof track.description === 'function') {
@@ -23702,8 +23710,8 @@ class TrackViewport extends Viewport {
23702
23710
  } else if (track.description) {
23703
23711
  str = `<div>${track.description}</div>`;
23704
23712
  } else {
23705
- if(track.url) {
23706
- if (track.url instanceof File) {
23713
+ if (track.url) {
23714
+ if (isFile(track.url)) {
23707
23715
  str = `<div><b>Filename: </b>${track.url.name}`;
23708
23716
  } else {
23709
23717
  str = `<div><b>URL: </b>${track.url}`;
@@ -27802,7 +27810,7 @@ class TrackBase {
27802
27810
 
27803
27811
  if (config.name || config.label) {
27804
27812
  this.name = config.name || config.label;
27805
- } else if (config.url instanceof File) {
27813
+ } else if (isFile(config.url)) {
27806
27814
  this.name = config.url.name;
27807
27815
  } else if (isString$3(config.url) && !config.url.startsWith("data:")) {
27808
27816
  this.name = getFilename$1(config.url);
@@ -27865,7 +27873,7 @@ class TrackBase {
27865
27873
  // function properties are transient as they cannot be saved in json
27866
27874
  const state = {};
27867
27875
  for (let key of Object.keys(this.config)) {
27868
- if (!key.startsWith("_") && typeof this.config[key] !== "function") {
27876
+ if (!key.startsWith("_") && typeof this.config[key] !== "function") {
27869
27877
  state[key] = this.config[key];
27870
27878
  }
27871
27879
  }
@@ -27893,7 +27901,7 @@ class TrackBase {
27893
27901
  if (typeof state[key] === 'function') {
27894
27902
  throw Error(`Property '${key}' of track '${this.name} is a function. Functions cannot be saved in sessions.`);
27895
27903
  }
27896
- if (state[key] instanceof File) {
27904
+ if (isFile(state[key])) {
27897
27905
  const str = `Track ${this.name} is a local file. Sessions cannot be saved with local file references.`;
27898
27906
  throw Error(str);
27899
27907
  }
@@ -34017,6 +34025,8 @@ function renderFeature(feature, bpStart, xScale, pixelHeight, ctx, options) {
34017
34025
  py = this.margin;
34018
34026
  }
34019
34027
 
34028
+ const pixelWidth = options.pixelWidth;
34029
+
34020
34030
  const cy = py + h / 2;
34021
34031
  const h2 = h / 2;
34022
34032
  const py2 = cy - h2 / 2;
@@ -34028,14 +34038,17 @@ function renderFeature(feature, bpStart, xScale, pixelHeight, ctx, options) {
34028
34038
 
34029
34039
  if (exonCount === 0) {
34030
34040
  // single-exon transcript
34031
- ctx.fillRect(coord.px, py, coord.pw, h);
34041
+ const xLeft = Math.max(0, coord.px);
34042
+ const xRight = Math.min(pixelWidth, coord.px1);
34043
+ const width = Math.max(coord.pw, xRight - xLeft);
34044
+ ctx.fillRect(xLeft, py, width, h);
34032
34045
 
34033
34046
  // Arrows
34034
34047
  // Do not draw if strand is not +/-
34035
34048
  if (direction !== 0) {
34036
34049
  ctx.fillStyle = "white";
34037
34050
  ctx.strokeStyle = "white";
34038
- for (let x = coord.px + step / 2; x < coord.px1; x += step) {
34051
+ for (let x = xLeft + step / 2; x < xRight; x += step) {
34039
34052
  // draw arrowheads along central line indicating transcribed orientation
34040
34053
  IGVGraphics.strokeLine(ctx, x - direction * 2, cy - 2, x, cy);
34041
34054
  IGVGraphics.strokeLine(ctx, x - direction * 2, cy + 2, x, cy);
@@ -34047,7 +34060,6 @@ function renderFeature(feature, bpStart, xScale, pixelHeight, ctx, options) {
34047
34060
  // multi-exon transcript
34048
34061
  IGVGraphics.strokeLine(ctx, coord.px + 1, cy, coord.px1 - 1, cy); // center line for introns
34049
34062
 
34050
- const pixelWidth = options.pixelWidth;
34051
34063
 
34052
34064
  const xLeft = Math.max(0, coord.px) + step / 2;
34053
34065
  const xRight = Math.min(pixelWidth, coord.px1);
@@ -35765,7 +35777,7 @@ class MergedTrack extends TrackBase {
35765
35777
 
35766
35778
  set height(h) {
35767
35779
  this._height = h;
35768
- if(this.tracks) {
35780
+ if (this.tracks) {
35769
35781
  for (let t of this.tracks) {
35770
35782
  t.height = h;
35771
35783
  t.config.height = h;
@@ -35851,8 +35863,8 @@ class MergedTrack extends TrackBase {
35851
35863
  const popupData = [];
35852
35864
  for (let i = 0; i < this.tracks.length; i++) {
35853
35865
  if (i > 0) popupData.push('<hr/>');
35854
- popupData.push(`<div style=background-color:#f7f8fa;border-bottom-style:dashed;border-bottom-width:1px;margin-bottom:5px;margin-top:5px;font-size:medium><b>${this.tracks[i].name}</b></div>`);
35855
- const trackPopupData = this.tracks[i].popupData(clickState);
35866
+ popupData.push(`<div style=background-color:rgb(245,245,245);border-bottom-style:dashed;border-bottom-width:1px;padding-bottom:5px;padding-top:10px;font-weight:bold;font-size:larger >${this.tracks[i].name}</div>`);
35867
+ const trackPopupData = this.tracks[i].popupData(clickState, featuresArray[i]);
35856
35868
  popupData.push(...trackPopupData);
35857
35869
 
35858
35870
  }
@@ -38547,7 +38559,7 @@ class CramReader {
38547
38559
  if (message && message.indexOf("MD5") >= 0) {
38548
38560
  message = "Sequence mismatch. Is this the correct genome for the loaded CRAM?";
38549
38561
  }
38550
- Alert$1.presentAlert(new Error(message));
38562
+ Alert.presentAlert(new Error(message));
38551
38563
  throw error
38552
38564
  }
38553
38565
  }
@@ -40507,7 +40519,7 @@ class AlignmentTrack {
40507
40519
  this.highlightedAlignmentReadNamed = clickedAlignment.readName;
40508
40520
  this.browser.presentMultiLocusPanel(clickedAlignment, referenceFrame);
40509
40521
  } else {
40510
- Alert$1.presentAlert(`Reference does not contain chromosome: ${clickedAlignment.mate.chr}`);
40522
+ Alert.presentAlert(`Reference does not contain chromosome: ${clickedAlignment.mate.chr}`);
40511
40523
  }
40512
40524
  }
40513
40525
  },
@@ -40523,9 +40535,9 @@ class AlignmentTrack {
40523
40535
 
40524
40536
  const seqstring = alignment.seq; //.map(b => String.fromCharCode(b)).join("");
40525
40537
  if (!seqstring || "*" === seqstring) {
40526
- Alert$1.presentAlert("Read sequence: *");
40538
+ Alert.presentAlert("Read sequence: *");
40527
40539
  } else {
40528
- Alert$1.presentAlert(seqstring);
40540
+ Alert.presentAlert(seqstring);
40529
40541
  }
40530
40542
  }
40531
40543
  });
@@ -41544,7 +41556,7 @@ class VariantTrack extends TrackBase {
41544
41556
 
41545
41557
  this.header = await this.getHeader(); // cricital, don't remove'
41546
41558
  if (undefined === this.visibilityWindow && this.config.indexed !== false) {
41547
- const fn = this.config.url instanceof File ? this.config.url.name : this.config.url;
41559
+ const fn = FileUtils.isFile(this.config.url) ? this.config.url.name : this.config.url;
41548
41560
  if (isString(fn) && fn.toLowerCase().includes("gnomad")) {
41549
41561
  this.visibilityWindow = 1000; // these are known to be very dense
41550
41562
  } else if (this.callSets) {
@@ -43666,28 +43678,21 @@ class SpliceJunctionTrack extends TrackBase {
43666
43678
 
43667
43679
  if (featureList) {
43668
43680
 
43669
- const rowFeatureCount = [];
43670
- for (let feature of featureList) {
43671
43681
 
43672
- junctionRenderingContext.referenceFrame = options.viewport.referenceFrame;
43673
- junctionRenderingContext.referenceFrameStart = junctionRenderingContext.referenceFrame.start;
43674
- junctionRenderingContext.referenceFrameEnd = junctionRenderingContext.referenceFrameStart + junctionRenderingContext.referenceFrame.toBP($(options.viewport.contentDiv).width());
43682
+ junctionRenderingContext.referenceFrame = options.viewport.referenceFrame;
43683
+ junctionRenderingContext.referenceFrameStart = junctionRenderingContext.referenceFrame.start;
43684
+ junctionRenderingContext.referenceFrameEnd = junctionRenderingContext.referenceFrameStart + junctionRenderingContext.referenceFrame.toBP($(options.viewport.contentDiv).width());
43675
43685
 
43676
- // For a given viewport, records where features that are < 2px in width have been rendered already.
43677
- // This prevents wasteful rendering of multiple such features onto the same pixels.
43678
- junctionRenderingContext.featureZoomOutTracker = {};
43686
+ // For a given viewport, records where features that are < 2px in width have been rendered already.
43687
+ // This prevents wasteful rendering of multiple such features onto the same pixels.
43688
+ junctionRenderingContext.featureZoomOutTracker = {};
43679
43689
 
43680
-
43681
- for (let feature of featureList) {
43682
- if (feature.end < bpStart) continue;
43683
- if (feature.start > bpEnd) break;
43684
-
43685
- const row = this.displayMode === 'COLLAPSED' ? 0 : feature.row;
43686
- const featureDensity = pixelWidth / rowFeatureCount[row];
43687
- options.drawLabel = options.labelAllFeatures || featureDensity > 10;
43688
- this.renderJunction(feature, bpStart, bpPerPixel, pixelHeight, ctx, options);
43689
- }
43690
+ for (let feature of featureList) {
43691
+ if (feature.end < bpStart) continue;
43692
+ if (feature.start > bpEnd) break;
43693
+ this.renderJunction(feature, bpStart, bpPerPixel, pixelHeight, ctx);
43690
43694
  }
43695
+
43691
43696
  } else {
43692
43697
  console.log("No feature list");
43693
43698
  }
@@ -46226,7 +46231,7 @@ class Browser {
46226
46231
  this.root = div$1({class: 'igv-container'});
46227
46232
  parentDiv.appendChild(this.root);
46228
46233
 
46229
- Alert$1.init(this.root);
46234
+ Alert.init(this.root);
46230
46235
 
46231
46236
  this.columnContainer = div$1({class: 'igv-column-container'});
46232
46237
  this.root.appendChild(this.columnContainer);
@@ -46885,7 +46890,7 @@ class Browser {
46885
46890
  const newTrack = await this.createTrack(config);
46886
46891
 
46887
46892
  if (undefined === newTrack) {
46888
- Alert$1.presentAlert(new Error(`Unknown file type: ${config.url || config}`), undefined);
46893
+ Alert.presentAlert(new Error(`Unknown file type: ${config.url || config}`), undefined);
46889
46894
  return newTrack;
46890
46895
  }
46891
46896
 
@@ -46939,7 +46944,7 @@ class Browser {
46939
46944
  msg = httpMessages[msg];
46940
46945
  }
46941
46946
  msg += (": " + config.url);
46942
- Alert$1.presentAlert(new Error(msg), undefined);
46947
+ Alert.presentAlert(new Error(msg), undefined);
46943
46948
  } finally {
46944
46949
  // TODO: If loadTrack() is called individually - not via loadTrackList() - call this.resize()
46945
46950
  if (false === doResize) ; else {
@@ -47455,7 +47460,7 @@ class Browser {
47455
47460
  async doSearch(string, init) {
47456
47461
  const success = await this.search(string, init);
47457
47462
  if (!success) {
47458
- Alert$1.presentAlert(new Error(`Unrecognized locus: <b> ${string} </b>`));
47463
+ Alert.presentAlert(new Error(`Unrecognized locus: <b> ${string} </b>`));
47459
47464
  }
47460
47465
  return success;
47461
47466
  }
@@ -47509,7 +47514,7 @@ class Browser {
47509
47514
 
47510
47515
  async loadSampleInformation(url) {
47511
47516
  var name = url;
47512
- if (url instanceof File) {
47517
+ if (isFile(url)) {
47513
47518
  name = url.name;
47514
47519
  }
47515
47520
  var ext = name.substr(name.lastIndexOf('.') + 1);