igv 2.12.0 → 2.12.1

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.12.0/examples/cram-vcf.html)***
15
+ ***[Alignments](https://igv.org/web/release/2.12.1/examples/cram-vcf.html)***
16
16
 
17
- ***[Interactions](https://igv.org/web/release/2.12.0/examples/interact.html)***
17
+ ***[Interactions](https://igv.org/web/release/2.12.1/examples/interact.html)***
18
18
 
19
- ***[Copy number](https://igv.org/web/release/2.12.0/examples/copyNumber.html)***
19
+ ***[Copy number](https://igv.org/web/release/2.12.1/examples/copyNumber.html)***
20
20
 
21
- ***[Multiple regions](https://igv.org/web/release/2.12.0/examples/multi-locus.html)***
21
+ ***[Multiple regions](https://igv.org/web/release/2.12.1/examples/multi-locus.html)***
22
22
 
23
- ***[Mutation Annotation Format (MAF)](https://igv.org/web/release/2.12.0/examples/maf-tcga.html)***
23
+ ***[Mutation Annotation Format (MAF)](https://igv.org/web/release/2.12.1/examples/maf-tcga.html)***
24
24
 
25
- ***[Variant color options](https://igv.org/web/release/2.12.0/examples/variant-colors.html)***
25
+ ***[Variant color options](https://igv.org/web/release/2.12.1/examples/variant-colors.html)***
26
26
 
27
- ***[More](https://igv.org/web/release/2.12.0/examples/)***
27
+ ***[More](https://igv.org/web/release/2.12.1/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.12.0/dist/](https://cdn.jsdelivr.net/npm/igv@2.12.0/dist/).
36
+ can be downloaded from [https://cdn.jsdelivr.net/npm/igv@2.12.1/dist/](https://cdn.jsdelivr.net/npm/igv@2.12.1/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.12.0/dist/igv.esm.min.js"
41
+ import igv from "https://cdn.jsdelivr.net/npm/igv@2.12.1/dist/igv.esm.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.12.0/dist/igv.min.js"></script>
47
+ <script src="https://cdn.jsdelivr.net/npm/igv@2.12.1/dist/igv.min.js"></script>
48
48
  ```
49
49
 
50
50
  Alternatively you can install with npm
package/dist/igv.esm.js CHANGED
@@ -19712,6 +19712,8 @@ const knownFileExtensions = new Set([
19712
19712
  "bb",
19713
19713
  "bigbed",
19714
19714
  "biginteract",
19715
+ "biggenepred",
19716
+ "bignarrowpeak",
19715
19717
  "bw",
19716
19718
  "bigwig",
19717
19719
  "bam",
@@ -19863,6 +19865,8 @@ function inferTrackType(config) {
19863
19865
  case "bed":
19864
19866
  case "bigbed":
19865
19867
  case "bb":
19868
+ case "biggenepred":
19869
+ case "bignarrowpeak":
19866
19870
  return "bedtype"
19867
19871
  default:
19868
19872
  return "annotation"
@@ -22792,7 +22796,7 @@ const Cytoband = function (start, end, name, typestain) {
22792
22796
  }
22793
22797
  };
22794
22798
 
22795
- const _version = "2.12.0";
22799
+ const _version = "2.12.1";
22796
22800
  function version() {
22797
22801
  return _version
22798
22802
  }
@@ -22940,7 +22944,7 @@ class Genome {
22940
22944
  constructor(config, sequence, ideograms, aliases) {
22941
22945
 
22942
22946
  this.config = config;
22943
- this.id = config.id;
22947
+ this.id = config.id || generateGenomeID(config);
22944
22948
  this.sequence = sequence;
22945
22949
  this.chromosomeNames = sequence.chromosomeNames;
22946
22950
  this.chromosomes = sequence.chromosomes; // An object (functions as a dictionary)
@@ -23262,6 +23266,18 @@ function constructWG(genome, config) {
23262
23266
 
23263
23267
  }
23264
23268
 
23269
+ function generateGenomeID(config) {
23270
+ if (config.id !== undefined) {
23271
+ return config.id
23272
+ } else if (config.fastaURL && isString$3(config.fastaURL)) {
23273
+ return config.fastaURL
23274
+ } else if (config.fastaURL && config.fastaURL.name) {
23275
+ return config.fastaURL.name
23276
+ } else {
23277
+ return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
23278
+ }
23279
+ }
23280
+
23265
23281
  /**
23266
23282
  * Created by dat on 9/16/16.
23267
23283
  */
@@ -23847,7 +23863,7 @@ class TrackViewport extends Viewport {
23847
23863
 
23848
23864
  viewport.addEventListener('click', (event) => {
23849
23865
 
23850
- if (this.enableClick) {
23866
+ if (this.enableClick && this.canvas) {
23851
23867
  if (3 === event.which || event.ctrlKey) {
23852
23868
  return
23853
23869
  }
@@ -29004,6 +29020,10 @@ class BamSource {
29004
29020
  * THE SOFTWARE.
29005
29021
  */
29006
29022
 
29023
+ const fixColor = (colorString) => {
29024
+ return (colorString.indexOf(",") > 0 && !colorString.startsWith("rgb")) ?
29025
+ `rgb(${colorString})` : colorString
29026
+ };
29007
29027
 
29008
29028
  /**
29009
29029
  * A collection of properties and methods shared by all (or most) track types.
@@ -29048,8 +29068,8 @@ class TrackBase {
29048
29068
 
29049
29069
  this.order = config.order;
29050
29070
 
29051
- this.color = config.color;
29052
- this.altColor = config.altColor;
29071
+ if(config.color) this.color = fixColor(config.color);
29072
+ if(config.altColor) this.altColor = fixColor(config.altColor);
29053
29073
  if ("civic-ws" === config.sourceType) { // Ugly proxy for specialized track type
29054
29074
  this.defaultColor = "rgb(155,20,20)";
29055
29075
  } else {
@@ -30944,7 +30964,7 @@ class ChordSetManager {
30944
30964
  return this.tracks.find(t => name === t.name)
30945
30965
  }
30946
30966
 
30947
- getChordset(name) {
30967
+ getChordSet(name) {
30948
30968
  return this.chordSets.find(cs => name === cs.name)
30949
30969
  }
30950
30970
 
@@ -31062,9 +31082,8 @@ class CircularView {
31062
31082
  buttonContainer.appendChild(this.showControlsButton);
31063
31083
  this.showControlsButton.innerText = 'none' === this.controlPanel.style.display ? 'Show Controls' : 'Hide Controls';
31064
31084
  this.showControlsButton.addEventListener('click', (event) => {
31065
- const trackPanelRows = this.controlPanel.querySelectorAll('div');
31066
- if (trackPanelRows.length > 0) {
31067
-
31085
+ const panelRows = this.controlPanel.querySelectorAll('div');
31086
+ if (panelRows.length > 0) {
31068
31087
  if ('none' === this.controlPanel.style.display) {
31069
31088
  this.controlPanel.style.display = 'flex';
31070
31089
  event.target.innerText = 'Hide Controls';
@@ -31148,10 +31167,10 @@ class CircularView {
31148
31167
  hideShowButton.innerText = true === chordSet.visible ? 'Hide' : 'Show';
31149
31168
  hideShowButton.addEventListener('click', event => {
31150
31169
  if (true === chordSet.visible) {
31151
- this.hideTrack(chordSet.name);
31170
+ this.hideChordSet(chordSet.name);
31152
31171
  event.target.innerText = "Show";
31153
31172
  } else {
31154
- this.showTrack(chordSet.name);
31173
+ this.showChordSet(chordSet.name);
31155
31174
  event.target.innerText = "Hide";
31156
31175
  }
31157
31176
  });
@@ -31175,7 +31194,7 @@ class CircularView {
31175
31194
  color: chordSet.color,
31176
31195
  onChange: ({rgbaString}) => {
31177
31196
  colorPickerButton.style.backgroundColor = setAlpha(rgbaString, 1);
31178
- this.setTrackColor(chordSet.name, rgbaString);
31197
+ this.setColor(chordSet.name, rgbaString);
31179
31198
  alphaSlider.value = alphaToValue(getAlpha(chordSet.color));
31180
31199
  }
31181
31200
  };
@@ -31193,7 +31212,7 @@ class CircularView {
31193
31212
  alphaSlider.value = alphaToValue(getAlpha(chordSet.color));
31194
31213
  alphaSlider.oninput = () => {
31195
31214
  const v = valueToAlpha(alphaSlider.value);
31196
- this.setTrackColor(chordSet.name, setAlpha(chordSet.color, v));
31215
+ this.setColor(chordSet.name, setAlpha(chordSet.color, v));
31197
31216
  picker.setColor(chordSet.color);
31198
31217
  };
31199
31218
  row.appendChild(alphaSlider);
@@ -31213,11 +31232,13 @@ class CircularView {
31213
31232
  */
31214
31233
  setAssembly(igvGenome) {
31215
31234
 
31216
- if (this.genomeId === igvGenome.id) {
31235
+ const id = this.genomeId || guid();
31236
+
31237
+ if (this.genomeId === id) {
31217
31238
  return
31218
31239
  }
31219
31240
  this.chordManager.clearChords();
31220
- this.genomeId = igvGenome.id;
31241
+ this.genomeId = id;
31221
31242
  this.chrNames = new Set(igvGenome.chromosomes.map(chr => shortChrName$1(chr.name)));
31222
31243
 
31223
31244
  const regions = [];
@@ -31238,7 +31259,7 @@ class CircularView {
31238
31259
  this.assembly = {
31239
31260
  name: igvGenome.name,
31240
31261
  sequence: {
31241
- trackId: igvGenome.id,
31262
+ trackId: id,
31242
31263
  type: 'ReferenceSequenceTrack',
31243
31264
  adapter: {
31244
31265
  type: 'FromConfigSequenceAdapter',
@@ -31279,7 +31300,7 @@ class CircularView {
31279
31300
 
31280
31301
  addChords(newChords, options = {}) {
31281
31302
 
31282
- const tmp = options.track || options.name || "*";
31303
+ const tmp = options.name || options.track || "*";
31283
31304
  const trackName = tmp.split(' ')[0].replaceAll("%20", " ");
31284
31305
  const chordSetName = tmp.replaceAll("%20", " ");
31285
31306
 
@@ -31332,21 +31353,6 @@ class CircularView {
31332
31353
  this.viewState.pluginManager.rootModel.session.clearSelection();
31333
31354
  }
31334
31355
 
31335
- getFeature(featureId) {
31336
-
31337
- // TODO -- broken
31338
- // const display = this.viewState.pluginManager.rootModel.session.view.tracks[0].displays[0]
31339
- // const feature = display.data.features.get(featureId)
31340
- // return feature;
31341
-
31342
- const features = [...this.viewState.config.tracks[0].adapter.features.value];
31343
- for (let f of features) {
31344
- if (featureId === f.uniqueId) {
31345
- return f
31346
- }
31347
- }
31348
- }
31349
-
31350
31356
  /**
31351
31357
  * Deprecated, use "visible" property
31352
31358
  */
@@ -31369,23 +31375,23 @@ class CircularView {
31369
31375
  this.parent.style.display = isVisible ? 'block' : 'none';
31370
31376
  }
31371
31377
 
31372
- hideTrack(trackName) {
31373
- let track = this.getTrack(trackName);
31374
- if (track) {
31375
- track.visible = false;
31378
+ hideChordSet(trackName) {
31379
+ let cs = this.getChordSet(trackName);
31380
+ if (cs) {
31381
+ cs.visible = false;
31376
31382
  this.render();
31377
31383
  } else {
31378
31384
  console.warn(`No track with name: ${name}`);
31379
31385
  }
31380
31386
  }
31381
31387
 
31382
- showTrack(trackName) {
31383
- let track = this.getTrack(trackName);
31384
- if (track) {
31385
- track.visible = true;
31388
+ showChordSet(name) {
31389
+ let cs = this.getChordSet(name);
31390
+ if (cs) {
31391
+ cs.visible = true;
31386
31392
  this.render();
31387
31393
  } else {
31388
- console.warn(`No track with name: ${trackName}`);
31394
+ console.warn(`No track with name: ${name}`);
31389
31395
  }
31390
31396
  }
31391
31397
 
@@ -31411,12 +31417,12 @@ class CircularView {
31411
31417
  this.render();
31412
31418
  }
31413
31419
 
31414
- getTrack(name) {
31415
- return this.groupByTrack ? this.chordManager.getTrack(name) : this.chordManager.getChordset(name)
31420
+ getChordSet(name) {
31421
+ return this.groupByTrack ? this.chordManager.getTrack(name) : this.chordManager.getChordSet(name)
31416
31422
  }
31417
31423
 
31418
- setTrackColor(name, color) {
31419
- const t = this.getTrack(name);
31424
+ setColor(name, color) {
31425
+ const t = this.getChordSet(name);
31420
31426
  if (t) {
31421
31427
  t.color = color;
31422
31428
  const trackID = t.id;
@@ -31443,8 +31449,6 @@ class CircularView {
31443
31449
  // Remove all children from possible previous renders. React might do this for us when we render, but just in case.
31444
31450
  ReactDOM.unmountComponentAtNode(this.container);
31445
31451
 
31446
-
31447
-
31448
31452
  const visibleChordSets =
31449
31453
  (this.groupByTrack ? this.chordManager.tracks : this.chordManager.chordSets).filter(t => t.visible);
31450
31454
 
@@ -31523,7 +31527,7 @@ function guid() {
31523
31527
 
31524
31528
  function embedCSS$1() {
31525
31529
 
31526
- const css = '.igv-circview-container {\n z-index: 2048;\n position: absolute;\n width: fit-content;\n height: fit-content;\n box-sizing: content-box;\n color: dimgray;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n background-color: white;\n border-color: dimgray;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n}\n\n.igv-circview-toolbar {\n position: relative;\n width: 100%;\n height: 32px;\n background-color: lightgrey;\n border-bottom-style: solid;\n border-bottom-color: dimgray;\n border-bottom-width: thin;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n\n.igv-circview-toolbar-button-container {\n height: 100%;\n width: fit-content;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-circview-toolbar-button-container > div {\n margin: 4px;\n}\n\n.igv-circview-track-panel {\n z-index: 1024;\n position: absolute;\n top: 33px;\n left: 0;\n width: 100%;\n height: fit-content;\n border-bottom-style: solid;\n border-bottom-color: dimgray;\n border-bottom-width: thin;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n}\n.igv-circview-track-panel > div {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-circview-track-panel > div > div {\n margin: 4px;\n}\n\n.igv-circview-swatch-button {\n cursor: pointer;\n padding: 5px;\n width: 8px;\n height: 8px;\n border: 1px solid #8d8b8b;\n border-radius: 16px;\n}\n\n.igv-circview-button {\n cursor: pointer;\n padding: 5px;\n color: #444;\n vertical-align: middle;\n text-align: center;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n border: 1px solid #8d8b8b;\n border-radius: 4px;\n background: #efefef;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.2);\n}\n\n.igv-circview-button:hover {\n background: #efefef;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.6);\n}\n\n.igv-circview-button:active {\n color: #007bff;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.6);\n}\n\n/*# sourceMappingURL=circular-view.css.map */\n';
31530
+ const css = '.igv-circview-container {\n z-index: 2048;\n width: fit-content;\n height: fit-content;\n box-sizing: content-box;\n color: dimgray;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n background-color: white;\n border-color: dimgray;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n}\n\n.igv-circview-toolbar {\n position: relative;\n width: 100%;\n height: 32px;\n background-color: lightgrey;\n border-bottom-style: solid;\n border-bottom-color: dimgray;\n border-bottom-width: thin;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n\n.igv-circview-toolbar-button-container {\n height: 100%;\n width: fit-content;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-circview-toolbar-button-container > div {\n margin: 4px;\n}\n\n.igv-circview-track-panel {\n z-index: 1024;\n position: absolute;\n top: 33px;\n left: 0;\n width: 100%;\n height: fit-content;\n border-bottom-style: solid;\n border-bottom-color: dimgray;\n border-bottom-width: thin;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n}\n.igv-circview-track-panel > div {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-circview-track-panel > div > div {\n margin: 4px;\n}\n\n.igv-circview-swatch-button {\n cursor: pointer;\n padding: 5px;\n width: 8px;\n height: 8px;\n border: 1px solid #8d8b8b;\n border-radius: 16px;\n}\n\n.igv-circview-button {\n cursor: pointer;\n padding: 5px;\n color: #444;\n vertical-align: middle;\n text-align: center;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n border: 1px solid #8d8b8b;\n border-radius: 4px;\n background: #efefef;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.2);\n}\n\n.igv-circview-button:hover {\n background: #efefef;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.6);\n}\n\n.igv-circview-button:active {\n color: #007bff;\n box-shadow: 0 0 5px -1px rgba(0, 0, 0, 0.6);\n}\n\n/*# sourceMappingURL=circular-view.css.map */\n';
31527
31531
 
31528
31532
  const style = document.createElement('style');
31529
31533
  style.setAttribute('type', 'text/css');
@@ -33181,10 +33185,13 @@ class AlignmentTrack {
33181
33185
  case "pairOrientation":
33182
33186
 
33183
33187
  if (this.pairOrientation && alignment.pairOrientation) {
33184
- var oTypes = orientationTypes[this.pairOrientation];
33188
+ const oTypes = orientationTypes[this.pairOrientation];
33185
33189
  if (oTypes) {
33186
- var pairColor = this.pairColors[oTypes[alignment.pairOrientation]];
33187
- if (pairColor) color = pairColor;
33190
+ const pairColor = this.pairColors[oTypes[alignment.pairOrientation]];
33191
+ if (pairColor) {
33192
+ color = pairColor;
33193
+ break
33194
+ }
33188
33195
  }
33189
33196
  }
33190
33197
  if ("pairOrientation" === option) {
@@ -35793,7 +35800,7 @@ function decodeBed(tokens, header) {
35793
35800
  const eEnd = eStart + parseInt(exonSizes[i]);
35794
35801
  exons.push({start: eStart, end: eEnd});
35795
35802
  }
35796
- findUTRs(exons, feature.cdStart, feature.cdEnd);
35803
+ findUTRs$1(exons, feature.cdStart, feature.cdEnd);
35797
35804
  feature.exons = exons;
35798
35805
  }
35799
35806
 
@@ -35901,7 +35908,7 @@ function decodeGenePred(tokens, header) {
35901
35908
  const end = parseInt(exonEnds[i]);
35902
35909
  exons.push({start: start, end: end});
35903
35910
  }
35904
- findUTRs(exons, cdStart, cdEnd);
35911
+ findUTRs$1(exons, cdStart, cdEnd);
35905
35912
 
35906
35913
  feature.exons = exons;
35907
35914
 
@@ -35944,7 +35951,7 @@ function decodeGenePredExt(tokens, header) {
35944
35951
  const end = parseInt(exonEnds[i]);
35945
35952
  exons.push({start: start, end: end});
35946
35953
  }
35947
- findUTRs(exons, cdStart, cdEnd);
35954
+ findUTRs$1(exons, cdStart, cdEnd);
35948
35955
 
35949
35956
  feature.exons = exons;
35950
35957
 
@@ -35985,14 +35992,14 @@ function decodeReflat(tokens, header) {
35985
35992
  const end = parseInt(exonEnds[i]);
35986
35993
  exons.push({start: start, end: end});
35987
35994
  }
35988
- findUTRs(exons, cdStart, cdEnd);
35995
+ findUTRs$1(exons, cdStart, cdEnd);
35989
35996
 
35990
35997
  feature.exons = exons;
35991
35998
 
35992
35999
  return feature
35993
36000
  }
35994
36001
 
35995
- function findUTRs(exons, cdStart, cdEnd) {
36002
+ function findUTRs$1(exons, cdStart, cdEnd) {
35996
36003
 
35997
36004
  for (let exon of exons) {
35998
36005
  const end = exon.end;
@@ -39508,7 +39515,7 @@ class TextFeatureSource {
39508
39515
  this.sourceType = (config.sourceType === undefined ? "file" : config.sourceType);
39509
39516
  this.maxWGCount = config.maxWGCount || DEFAULT_MAX_WG_COUNT;
39510
39517
 
39511
- const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "biginteract", "tdf"]);
39518
+ const queryableFormats = new Set(["bigwig", "bw", "bigbed", "bb", "biginteract", "biggenepred", "bignarrowpeak", "tdf"]);
39512
39519
 
39513
39520
  if (config.features && Array.isArray(config.features)) {
39514
39521
  // Explicit array of features
@@ -39928,11 +39935,9 @@ class BufferedReader {
39928
39935
  }
39929
39936
  }
39930
39937
 
39931
- //table chromatinInteract
39932
-
39933
39938
  function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
39934
39939
 
39935
- if (autoSql && 'chromatinInteract' === autoSql.table || "biginteract" === format) {
39940
+ if ("biginteract" === format || (autoSql && ('chromatinInteract' === autoSql.table) || 'interact' === autoSql.table)) {
39936
39941
  return decodeInteract
39937
39942
  } else {
39938
39943
  const standardFieldCount = definedFieldCount - 3;
@@ -39969,6 +39974,7 @@ function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
39969
39974
  const eEnd = eStart + parseInt(exonSizes[i]);
39970
39975
  exons.push({start: eStart, end: eEnd});
39971
39976
  }
39977
+ findUTRs(exons, feature.cdStart, feature.cdEnd);
39972
39978
  feature.exons = exons;
39973
39979
  }
39974
39980
 
@@ -39986,6 +39992,28 @@ function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
39986
39992
  }
39987
39993
  }
39988
39994
 
39995
+ //table chromatinInteract
39996
+ // "Chromatin interaction between two regions"
39997
+ // (
39998
+ // string chrom; "Chromosome (or contig, scaffold, etc.). For interchromosomal, use 2 records"
39999
+ // uint chromStart; "Start position of lower region. For interchromosomal, set to chromStart of this region"
40000
+ // uint chromEnd; "End position of upper region. For interchromosomal, set to chromEnd of this region"
40001
+ // string name; "Name of item, for display"
40002
+ // uint score; "Score from 0-1000"
40003
+ // double value; "Strength of interaction or other data value. Typically basis for score"
40004
+ // string exp; "Experiment name (metadata for filtering). Use . if not applicable"
40005
+ // string color; "Item color. Specified as r,g,b or hexadecimal #RRGGBB or html color name, as in //www.w3.org/TR/css3-color/#html4."
40006
+ // string region1Chrom; "Chromosome of lower region. For non-directional interchromosomal, chrom of this region."
40007
+ // uint region1Start; "Start position of lower/this region"
40008
+ // uint region1End; "End position in chromosome of lower/this region"
40009
+ // string region1Name; "Identifier of lower/this region"
40010
+ // string region1Strand; "Orientation of lower/this region: + or -. Use . if not applicable"
40011
+ // string region2Chrom; "Chromosome of upper region. For non-directional interchromosomal, chrom of other region"
40012
+ // uint region2Start; "Start position in chromosome of upper/this region"
40013
+ // uint region2End; "End position in chromosome of upper/this region"
40014
+ // string region2Name; "Identifier of upper/this region"
40015
+ // string region2Strand; "Orientation of upper/this region: + or -. Use . if not applicable"
40016
+ // )
39989
40017
  function decodeInteract(feature, tokens) {
39990
40018
 
39991
40019
  feature.chr1 = tokens[5];
@@ -40005,6 +40033,24 @@ function getDecoder(definedFieldCount, fieldCount, autoSql, format) {
40005
40033
  }
40006
40034
  }
40007
40035
 
40036
+ function findUTRs(exons, cdStart, cdEnd) {
40037
+
40038
+ for (let exon of exons) {
40039
+ const end = exon.end;
40040
+ const start = exon.start;
40041
+ if (end < cdStart || start > cdEnd) {
40042
+ exon.utr = true;
40043
+ } else {
40044
+ if (cdStart >= start && cdStart <= end) {
40045
+ exon.cdStart = cdStart;
40046
+ }
40047
+ if (cdEnd >= start && cdEnd <= end) {
40048
+ exon.cdEnd = cdEnd;
40049
+ }
40050
+ }
40051
+ }
40052
+ }
40053
+
40008
40054
  function scoreShade(score, color) {
40009
40055
  const alpha = Math.min(1, 0.11 + 0.89 * (score / 779));
40010
40056
  return alpha.toString()
@@ -41544,11 +41590,12 @@ function zoomLevelForScale(chr, bpPerPixel, genome) {
41544
41590
  * THE SOFTWARE.
41545
41591
  */
41546
41592
 
41593
+ const bbFormats = new Set(['bigwig', 'bw', 'bigbed', 'bb', 'biginteract', 'biggenepred', 'bignarrowpeak']);
41547
41594
 
41548
41595
  function FeatureSource(config, genome) {
41549
41596
 
41550
41597
  const format = config.format ? config.format.toLowerCase() : undefined;
41551
- if ('bigwig' === format || 'bigbed' === format || 'bb' === format || "biginteract" === format) {
41598
+ if (bbFormats.has(format)) {
41552
41599
  return new BWSource(config, genome)
41553
41600
  } else if ("tdf" === format) {
41554
41601
  return new TDFSource(config, genome)
@@ -41796,10 +41843,9 @@ function renderFeatureLabel(ctx, feature, featureX, featureX1, featureY, referen
41796
41843
  const textBox = ctx.measureText(name);
41797
41844
  const xleft = centerX - textBox.width / 2;
41798
41845
  const xright = centerX + textBox.width / 2;
41799
- if (options.labelAllFeatures || xleft > options.rowLastX[feature.row] || gtexSelection) {
41800
- options.rowLastX[feature.row] = xright;
41846
+ if (options.labelAllFeatures || xleft > options.rowLastLabelX[feature.row] || gtexSelection) {
41847
+ options.rowLastLabelX[feature.row] = xright;
41801
41848
  IGVGraphics.fillText(ctx, name, centerX, labelY, geneFontStyle, transform);
41802
-
41803
41849
  }
41804
41850
  } finally {
41805
41851
  ctx.restore();
@@ -42156,24 +42202,27 @@ class FeatureTrack extends TrackBase {
42156
42202
 
42157
42203
  const rowFeatureCount = [];
42158
42204
  options.rowLastX = [];
42205
+ options.rowLastLabelX = [];
42159
42206
  for (let feature of featureList) {
42160
- const row = feature.row || 0;
42161
- if (rowFeatureCount[row] === undefined) {
42162
- rowFeatureCount[row] = 1;
42163
- } else {
42164
- rowFeatureCount[row]++;
42207
+ if(feature.start > bpStart && feature.end < bpEnd) {
42208
+ const row = this.displayMode === "COLLAPSED" ? 0 : feature.row || 0;
42209
+ if (rowFeatureCount[row] === undefined) {
42210
+ rowFeatureCount[row] = 1;
42211
+ } else {
42212
+ rowFeatureCount[row]++;
42213
+ }
42214
+ options.rowLastX[row] = -Number.MAX_SAFE_INTEGER;
42215
+ options.rowLastLabelX[row] = -Number.MAX_SAFE_INTEGER;
42165
42216
  }
42166
- options.rowLastX[row] = -Number.MAX_SAFE_INTEGER;
42167
42217
  }
42218
+ const pixelsPerFeature = pixelWidth / Math.max(...rowFeatureCount);
42168
42219
 
42169
42220
  let lastPxEnd = [];
42170
42221
  for (let feature of featureList) {
42171
42222
  if (feature.end < bpStart) continue
42172
42223
  if (feature.start > bpEnd) break
42173
-
42174
42224
  const row = this.displayMode === 'COLLAPSED' ? 0 : feature.row;
42175
- const featureDensity = pixelWidth / rowFeatureCount[row];
42176
- options.drawLabel = options.labelAllFeatures || featureDensity > 10;
42225
+ options.drawLabel = options.labelAllFeatures || pixelsPerFeature > 10;
42177
42226
  const pxEnd = Math.ceil((feature.end - bpStart) / bpPerPixel);
42178
42227
  const last = lastPxEnd[row];
42179
42228
  if (!last || pxEnd > last) {
@@ -42187,7 +42236,6 @@ class FeatureTrack extends TrackBase {
42187
42236
  ctx.globalAlpha = 1.0;
42188
42237
  }
42189
42238
  lastPxEnd[row] = pxEnd;
42190
-
42191
42239
  }
42192
42240
  }
42193
42241
 
@@ -51005,6 +51053,7 @@ class Browser {
51005
51053
  }
51006
51054
 
51007
51055
  createCircularView(container, show) {
51056
+ show = show === true; // convert undefined to boolean
51008
51057
  this.circularView = createCircularView(container, this);
51009
51058
  this.circularViewControl = new CircularViewControl(this.$toggle_button_container.get(0), this);
51010
51059
  this.circularView.setAssembly({
@@ -51013,7 +51062,7 @@ class Browser {
51013
51062
  chromosomes: makeCircViewChromosomes(this.genome)
51014
51063
  });
51015
51064
  this.circularViewVisible = show;
51016
-
51065
+ return this.circularView
51017
51066
  }
51018
51067
 
51019
51068
  get circularViewVisible() {