igv 2.12.2 → 2.12.5

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
@@ -16468,8 +16468,12 @@ const IGVColor = {
16468
16468
 
16469
16469
  let dragData$1; // Its assumed we are only dragging one element at a time.
16470
16470
 
16471
+ let bbox = undefined;
16471
16472
 
16472
- function makeDraggable$1(target, handle) {
16473
+ function makeDraggable$1(target, handle, constraint) {
16474
+ if (constraint) {
16475
+ bbox = Object.assign({}, constraint);
16476
+ }
16473
16477
  handle.addEventListener('mousedown', dragStart$1.bind(target));
16474
16478
  }
16475
16479
 
@@ -16512,8 +16516,13 @@ function drag$1(event) {
16512
16516
  event.preventDefault();
16513
16517
  const dx = event.screenX - dragData$1.screenX;
16514
16518
  const dy = event.screenY - dragData$1.screenY;
16515
- this.style.left = `${dragData$1.left + dx}px`;
16516
- this.style.top = `${dragData$1.top + dy}px`;
16519
+
16520
+ // const left = bbox ? Math.max(bbox.minX, dragData.left + dx) : dragData.left + dx
16521
+ const left = dragData$1.left + dx;
16522
+ const top = bbox ? Math.max(bbox.minY, dragData$1.top + dy) : dragData$1.top + dy;
16523
+
16524
+ this.style.left = `${ left }px`;
16525
+ this.style.top = `${ top }px`;
16517
16526
  }
16518
16527
 
16519
16528
  function dragEnd$1(event) {
@@ -16801,9 +16810,9 @@ const igvxhr = {
16801
16810
  options.responseType = "arraybuffer";
16802
16811
  }
16803
16812
  if (isFile(url)) {
16804
- return loadFileSlice(url, options);
16813
+ return loadFileSlice(url, options)
16805
16814
  } else {
16806
- return load(url, options);
16815
+ return load(url, options)
16807
16816
  }
16808
16817
  },
16809
16818
 
@@ -16815,18 +16824,18 @@ const igvxhr = {
16815
16824
  }
16816
16825
  const result = await this.loadString(url, options);
16817
16826
  if (result) {
16818
- return JSON.parse(result);
16827
+ return JSON.parse(result)
16819
16828
  } else {
16820
- return result;
16829
+ return result
16821
16830
  }
16822
16831
  },
16823
16832
 
16824
16833
  loadString: async function (path, options) {
16825
16834
  options = options || {};
16826
16835
  if (path instanceof File) {
16827
- return loadStringFromFile(path, options);
16836
+ return loadStringFromFile(path, options)
16828
16837
  } else {
16829
- return loadStringFromUrl(path, options);
16838
+ return loadStringFromUrl(path, options)
16830
16839
  }
16831
16840
  }
16832
16841
  };
@@ -16840,15 +16849,15 @@ async function load(url, options) {
16840
16849
  url = await (typeof url === 'function' ? url() : url);
16841
16850
 
16842
16851
  if (isFile(url)) {
16843
- return loadFileSlice(url, options);
16852
+ return loadFileSlice(url, options)
16844
16853
  } else if (typeof url.startsWith === 'function') { // Test for string
16845
16854
  if (url.startsWith("data:")) {
16846
16855
  const buffer = decodeDataURI$1(url).buffer;
16847
- if(options.range) {
16856
+ if (options.range) {
16848
16857
  const rangeEnd = options.range.size ? options.range.start + options.range.size : buffer.byteLength;
16849
- return buffer.slice(options.range.start, rangeEnd);
16858
+ return buffer.slice(options.range.start, rangeEnd)
16850
16859
  } else {
16851
- return buffer;
16860
+ return buffer
16852
16861
  }
16853
16862
  } else {
16854
16863
  if (url.startsWith("https://drive.google.com")) {
@@ -16859,11 +16868,11 @@ async function load(url, options) {
16859
16868
  return loadURL(url, options)
16860
16869
  })
16861
16870
  } else {
16862
- return loadURL(url, options);
16871
+ return loadURL(url, options)
16863
16872
  }
16864
16873
  }
16865
16874
  } else {
16866
- throw Error(`url must be either a 'File', 'string', 'function', or 'Promise'. Actual type: ${urlType}`);
16875
+ throw Error(`url must be either a 'File', 'string', 'function', or 'Promise'. Actual type: ${urlType}`)
16867
16876
  }
16868
16877
  }
16869
16878
 
@@ -16882,7 +16891,7 @@ async function loadURL(url, options) {
16882
16891
  return new Promise(function (resolve, reject) {
16883
16892
 
16884
16893
  // Various Google tansformations
16885
- if (isGoogleURL(url)) {
16894
+ if (isGoogleURL(url) && !isGoogleStorageSigned(url)) {
16886
16895
  if (isGoogleStorageURL(url)) {
16887
16896
  url = translateGoogleCloudURL(url);
16888
16897
  }
@@ -16906,7 +16915,7 @@ async function loadURL(url, options) {
16906
16915
  const isChrome = navigator.userAgent.indexOf('Chrome') > -1;
16907
16916
  navigator.vendor.indexOf("Apple") === 0 && /\sSafari\//.test(navigator.userAgent);
16908
16917
 
16909
- if (range && isChrome && !isAmazonV4Signed(url)) {
16918
+ if (range && isChrome && !isAmazonV4Signed(url) && !isGoogleStorageSigned(url)) {
16910
16919
  // Hack to prevent caching for byte-ranges. Attempt to fix net:err-cache errors in Chrome
16911
16920
  url += url.includes("?") ? "&" : "?";
16912
16921
  url += "someRandomSeed=" + Math.random().toString(36);
@@ -17011,7 +17020,7 @@ async function loadURL(url, options) {
17011
17020
  if (reject) {
17012
17021
  reject(error);
17013
17022
  } else {
17014
- throw error;
17023
+ throw error
17015
17024
  }
17016
17025
  }
17017
17026
 
@@ -17043,60 +17052,38 @@ async function loadFileSlice(localfile, options) {
17043
17052
  localfile.slice(options.range.start, options.range.start + options.range.size) :
17044
17053
  localfile;
17045
17054
 
17055
+ const arrayBuffer = await blob.arrayBuffer();
17056
+
17046
17057
  if ("arraybuffer" === options.responseType) {
17047
- return blobToArrayBuffer(blob);
17058
+ return arrayBuffer
17048
17059
  } else {
17049
- // binary string format, shouldn't be used anymore
17050
- return new Promise(function (resolve, reject) {
17051
- const fileReader = new FileReader();
17052
- fileReader.onload = function (e) {
17053
- resolve(fileReader.result);
17054
- };
17055
- fileReader.onerror = function (e) {
17056
- console.error("reject uploading local file " + localfile.name);
17057
- reject(null, fileReader);
17058
- };
17059
- fileReader.readAsBinaryString(blob);
17060
- console.warn("Deprecated method used: readAsBinaryString");
17061
- })
17060
+ return arrayBufferToString(arrayBuffer)
17062
17061
  }
17063
17062
  }
17064
17063
 
17065
17064
  async function loadStringFromFile(localfile, options) {
17066
17065
 
17067
17066
  const blob = options.range ? localfile.slice(options.range.start, options.range.start + options.range.size) : localfile;
17068
- const arrayBuffer = await blobToArrayBuffer(blob);
17069
- return arrayBufferToString(arrayBuffer);
17067
+ const arrayBuffer = await blob.arrayBuffer();
17068
+ return arrayBufferToString(arrayBuffer)
17070
17069
  }
17071
17070
 
17072
- async function blobToArrayBuffer(blob) {
17073
- if (typeof blob.arrayBuffer === 'function') {
17074
- return blob.arrayBuffer();
17075
- }
17076
- return new Promise(function (resolve, reject) {
17077
- const fileReader = new FileReader();
17078
- fileReader.onload = function (e) {
17079
- resolve(fileReader.result);
17080
- };
17081
- fileReader.onerror = function (e) {
17082
- console.error("reject uploading local file " + localfile.name);
17083
- reject(null, fileReader);
17084
- };
17085
- fileReader.readAsArrayBuffer(blob);
17086
- })
17087
- }
17088
17071
 
17089
17072
  async function loadStringFromUrl(url, options) {
17090
17073
 
17091
17074
  options = options || {};
17092
17075
  options.responseType = "arraybuffer";
17093
17076
  const data = await igvxhr.load(url, options);
17094
- return arrayBufferToString(data);
17077
+ return arrayBufferToString(data)
17095
17078
  }
17096
17079
 
17097
17080
 
17098
17081
  function isAmazonV4Signed(url) {
17099
- return url.indexOf("X-Amz-Signature") > -1;
17082
+ return url.indexOf("X-Amz-Signature") > -1
17083
+ }
17084
+
17085
+ function isGoogleStorageSigned(url) {
17086
+ return url.indexOf("X-Goog-Signature") > -1
17100
17087
  }
17101
17088
 
17102
17089
  function getOauthToken(url) {
@@ -17107,11 +17094,11 @@ function getOauthToken(url) {
17107
17094
  parseUri(url).host;
17108
17095
  let token = oauth.getToken(host);
17109
17096
  if (token) {
17110
- return token;
17097
+ return token
17111
17098
  } else if (host === undefined) {
17112
17099
  const googleToken = getCurrentGoogleAccessToken();
17113
17100
  if (googleToken && googleToken.expires_at > Date.now()) {
17114
- return googleToken.access_token;
17101
+ return googleToken.access_token
17115
17102
  }
17116
17103
  }
17117
17104
  }
@@ -17127,7 +17114,7 @@ async function fetchGoogleAccessToken(url) {
17127
17114
  if (isInitialized()) {
17128
17115
  const scope = getScopeForURL(url);
17129
17116
  const googleToken = await getAccessToken(scope);
17130
- return googleToken ? googleToken.access_token : undefined;
17117
+ return googleToken ? googleToken.access_token : undefined
17131
17118
  } else {
17132
17119
  throw Error(
17133
17120
  `Authorization is required, but Google oAuth has not been initalized. Contact your site administrator for assistance.`)
@@ -17141,9 +17128,9 @@ async function fetchGoogleAccessToken(url) {
17141
17128
  function getCurrentGoogleAccessToken() {
17142
17129
  if (isInitialized()) {
17143
17130
  const googleToken = getCurrentAccessToken();
17144
- return googleToken ? googleToken.access_token : undefined;
17131
+ return googleToken ? googleToken.access_token : undefined
17145
17132
  } else {
17146
- return undefined;
17133
+ return undefined
17147
17134
  }
17148
17135
  }
17149
17136
 
@@ -17152,7 +17139,7 @@ function addOauthHeaders(headers, acToken) {
17152
17139
  headers["Cache-Control"] = "no-cache";
17153
17140
  headers["Authorization"] = "Bearer " + acToken;
17154
17141
  }
17155
- return headers;
17142
+ return headers
17156
17143
  }
17157
17144
 
17158
17145
 
@@ -17165,12 +17152,12 @@ function addApiKey(url) {
17165
17152
  const paramSeparator = url.includes("?") ? "&" : "?";
17166
17153
  url = url + paramSeparator + "key=" + apiKey;
17167
17154
  }
17168
- return url;
17155
+ return url
17169
17156
  }
17170
17157
 
17171
17158
  function addTeamDrive(url) {
17172
17159
  if (url.includes("supportsTeamDrive")) {
17173
- return url;
17160
+ return url
17174
17161
  } else {
17175
17162
  const paramSeparator = url.includes("?") ? "&" : "?";
17176
17163
  url = url + paramSeparator + "supportsTeamDrive=true";
@@ -17184,17 +17171,17 @@ function addTeamDrive(url) {
17184
17171
  function mapUrl(url) {
17185
17172
 
17186
17173
  if (url.includes("//www.dropbox.com")) {
17187
- return url.replace("//www.dropbox.com", "//dl.dropboxusercontent.com");
17174
+ return url.replace("//www.dropbox.com", "//dl.dropboxusercontent.com")
17188
17175
  } else if (url.includes("//drive.google.com")) {
17189
- return driveDownloadURL(url);
17176
+ return driveDownloadURL(url)
17190
17177
  } else if (url.includes("//www.broadinstitute.org/igvdata")) {
17191
- return url.replace("//www.broadinstitute.org/igvdata", "//data.broadinstitute.org/igvdata");
17178
+ return url.replace("//www.broadinstitute.org/igvdata", "//data.broadinstitute.org/igvdata")
17192
17179
  } else if (url.includes("//igvdata.broadinstitute.org")) {
17193
17180
  return url.replace("//igvdata.broadinstitute.org", "https://dn7ywbm9isq8j.cloudfront.net")
17194
17181
  } else if (url.startsWith("ftp://ftp.ncbi.nlm.nih.gov/geo")) {
17195
17182
  return url.replace("ftp://", "https://")
17196
17183
  } else {
17197
- return url;
17184
+ return url
17198
17185
  }
17199
17186
  }
17200
17187
 
@@ -17209,9 +17196,9 @@ function arrayBufferToString(arraybuffer) {
17209
17196
  }
17210
17197
 
17211
17198
  if ('TextDecoder' in getGlobalObject()) {
17212
- return new TextDecoder().decode(plain);
17199
+ return new TextDecoder().decode(plain)
17213
17200
  } else {
17214
- return decodeUTF8(plain);
17201
+ return decodeUTF8(plain)
17215
17202
  }
17216
17203
  }
17217
17204
 
@@ -17263,12 +17250,12 @@ function decodeUTF8(octets) {
17263
17250
 
17264
17251
  function getGlobalObject() {
17265
17252
  if (typeof self !== 'undefined') {
17266
- return self;
17253
+ return self
17267
17254
  }
17268
17255
  if (typeof global !== 'undefined') {
17269
- return global;
17256
+ return global
17270
17257
  } else {
17271
- return window;
17258
+ return window
17272
17259
  }
17273
17260
  }
17274
17261
 
@@ -20251,6 +20238,12 @@ for (let i = 0; i < t1.length; i++) {
20251
20238
  complement[t1[i].toLowerCase()] = t2[i].toLowerCase();
20252
20239
  }
20253
20240
 
20241
+ const DEFAULT_HEIGHT = 25;
20242
+ const TRANSLATED_HEIGHT = 115;
20243
+ const SEQUENCE_HEIGHT = 15;
20244
+ const FRAME_HEIGHT = 25;
20245
+ const FRAME_BORDER = 5;
20246
+
20254
20247
  class SequenceTrack {
20255
20248
 
20256
20249
  constructor(config, browser) {
@@ -20262,13 +20255,13 @@ class SequenceTrack {
20262
20255
  this.name = "Sequence";
20263
20256
  this.id = "sequence";
20264
20257
  this.sequenceType = config.sequenceType || "dna"; // dna | rna | prot
20265
- this.height = 25;
20266
20258
  this.disableButtons = false;
20267
20259
  this.order = config.order || defaultSequenceTrackOrder;
20268
20260
  this.ignoreTrackMenu = false;
20269
20261
 
20270
- this.reversed = false;
20271
- this.frameTranslate = false;
20262
+ this.reversed = config.reversed === true;
20263
+ this.frameTranslate = config.frameTranslate === true;
20264
+ this.height = this.frameTranslate ? TRANSLATED_HEIGHT : DEFAULT_HEIGHT;
20272
20265
 
20273
20266
  }
20274
20267
 
@@ -20287,14 +20280,14 @@ class SequenceTrack {
20287
20280
  this.frameTranslate = !this.frameTranslate;
20288
20281
  if (this.frameTranslate) {
20289
20282
  for (let vp of this.trackView.viewports) {
20290
- vp.setContentHeight(115);
20283
+ vp.setContentHeight(TRANSLATED_HEIGHT);
20291
20284
  }
20292
- this.trackView.setTrackHeight(115);
20285
+ this.trackView.setTrackHeight(TRANSLATED_HEIGHT);
20293
20286
  } else {
20294
20287
  for (let vp of this.trackView.viewports) {
20295
- vp.setContentHeight(25);
20288
+ vp.setContentHeight(DEFAULT_HEIGHT);
20296
20289
  }
20297
- this.trackView.setTrackHeight(25);
20290
+ this.trackView.setTrackHeight(DEFAULT_HEIGHT);
20298
20291
  }
20299
20292
  this.trackView.repaintViews();
20300
20293
 
@@ -20377,7 +20370,8 @@ class SequenceTrack {
20377
20370
  }
20378
20371
 
20379
20372
  async getFeatures(chr, start, end, bpPerPixel) {
20380
-
20373
+ start = Math.floor(start);
20374
+ end = Math.floor(end);
20381
20375
  if (bpPerPixel && bpPerPixel > 1) {
20382
20376
  return null
20383
20377
  } else {
@@ -20395,89 +20389,79 @@ class SequenceTrack {
20395
20389
 
20396
20390
  if (options.features) {
20397
20391
 
20398
- const sequence = options.features.sequence;
20399
- const sequenceBpStart = options.features.bpStart;
20400
- const bpEnd = 1 + options.bpStart + (options.pixelWidth * options.bpPerPixel);
20401
-
20402
- let height = 15;
20403
- for (let bp = sequenceBpStart; bp <= bpEnd; bp++) {
20392
+ let sequence = options.features.sequence;
20404
20393
 
20405
- let seqOffsetBp = Math.floor(bp - sequenceBpStart);
20394
+ if (this.reversed) {
20395
+ sequence = sequence.split('').map(function (cv) {
20396
+ return complement[cv]
20397
+ }).join('');
20398
+ }
20406
20399
 
20407
- if (seqOffsetBp < sequence.length) {
20408
- let letter = sequence[seqOffsetBp];
20400
+ const sequenceBpStart = options.features.bpStart; // genomic position at start of sequence
20401
+ const bpEnd = 1 + options.bpStart + (options.pixelWidth * options.bpPerPixel);
20409
20402
 
20410
- if (this.reversed) {
20411
- letter = complement[letter] || "";
20412
- }
20403
+ for (let bp = Math.floor(options.bpStart); bp <= bpEnd; bp++) {
20413
20404
 
20414
- let offsetBP = bp - options.bpStart;
20415
- let aPixel = offsetBP / options.bpPerPixel;
20416
- let bPixel = (offsetBP + 1) / options.bpPerPixel;
20417
- let color = this.fillColor(letter);
20405
+ const seqIdx = Math.floor(bp - sequenceBpStart);
20418
20406
 
20419
- // IGVGraphics.fillRect(ctx, aPixel, 5, bPixel - aPixel, height - 5, { fillStyle: randomRGBConstantAlpha(150, 255, 0.75) });
20407
+ if (seqIdx >= 0 && seqIdx < sequence.length) {
20408
+ const baseLetter = sequence[seqIdx];
20409
+ const offsetBP = bp - options.bpStart;
20410
+ const aPixel = offsetBP / options.bpPerPixel;
20411
+ const pixelWidth = 1 / options.bpPerPixel;
20412
+ const color = this.fillColor(baseLetter);
20420
20413
 
20421
20414
  if (options.bpPerPixel > 1 / 10) {
20422
- IGVGraphics.fillRect(ctx, aPixel, 5, bPixel - aPixel, height - 5, {fillStyle: color});
20415
+ IGVGraphics.fillRect(ctx, aPixel, 5, pixelWidth, SEQUENCE_HEIGHT - 5, {fillStyle: color});
20423
20416
  } else {
20424
- let xPixel = 0.5 * (aPixel + bPixel - ctx.measureText(letter).width);
20425
- IGVGraphics.strokeText(ctx, letter, xPixel, height, {strokeStyle: color});
20417
+ let textPixel = aPixel + 0.5 * (pixelWidth - ctx.measureText(baseLetter).width);
20418
+ IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, {strokeStyle: color});
20426
20419
  }
20427
20420
  }
20428
20421
  }
20429
20422
 
20430
20423
  if (this.frameTranslate) {
20431
20424
 
20432
- let transSeq;
20433
- if (this.reversed) {
20434
- transSeq = sequence.split('').map(function (cv) {
20435
- return complement[cv]
20436
- });
20437
- transSeq = transSeq.join('');
20438
- } else {
20439
- transSeq = sequence;
20440
- }
20441
-
20442
- let y = height;
20443
- let translatedSequence = this.translateSequence(transSeq);
20444
- for (let arr of translatedSequence) {
20425
+ let y = SEQUENCE_HEIGHT + 2 * FRAME_BORDER;
20426
+ const translatedSequence = this.translateSequence(sequence);
20445
20427
 
20446
- let i = translatedSequence.indexOf(arr);
20447
- let fNum = i;
20448
- let h = 25;
20428
+ for (let fNum = 0; fNum < translatedSequence.length; fNum++) { // == 3, 1 for each frame
20449
20429
 
20450
- y = (i === 0) ? y + 10 : y + 30; //Little less room at first.
20430
+ const aaSequence = translatedSequence[fNum]; // AA sequence for this frame
20451
20431
 
20452
- for (let cv of arr) {
20432
+ for (let idx = 0; idx < aaSequence.length; idx++) {
20453
20433
 
20454
- let aaS;
20455
- let idx = arr.indexOf(cv);
20456
- let xSeed = (idx + fNum) + (2 * idx);
20457
20434
  let color = 0 === idx % 2 ? 'rgb(160,160,160)' : 'rgb(224,224,224)';
20435
+ const cv = aaSequence[idx];
20436
+
20437
+ const bpPos = sequenceBpStart + fNum + (idx * 3);
20438
+ const bpOffset = bpPos - options.bpStart;
20439
+ const p0 = Math.floor(bpOffset / options.bpPerPixel);
20440
+ const p1 = Math.floor((bpOffset + 3) / options.bpPerPixel);
20441
+ const pc = Math.round((p0 + p1) / 2);
20442
+
20443
+ if (p1 < 0) {
20444
+ continue // off left edge
20445
+ } else if (p0 > options.pixelWidth) {
20446
+ break // off right edge
20447
+ }
20458
20448
 
20459
- let p0 = Math.floor(xSeed / options.bpPerPixel);
20460
- let p1 = Math.floor((xSeed + 3) / options.bpPerPixel);
20461
- let pc = Math.round((p0 + p1) / 2);
20462
-
20449
+ let aaLabel = cv.aminoA;
20463
20450
  if (cv.aminoA.indexOf('STOP') > -1) {
20464
20451
  color = 'rgb(255, 0, 0)';
20465
- aaS = 'STOP'; //Color blind accessible
20466
- } else {
20467
- aaS = cv.aminoA;
20468
- }
20469
-
20470
- if (cv.aminoA === 'M') {
20452
+ aaLabel = 'STOP'; //Color blind accessible
20453
+ } else if (cv.aminoA === 'M') {
20471
20454
  color = 'rgb(0, 153, 0)';
20472
- aaS = 'START'; //Color blind accessible
20455
+ aaLabel = 'START'; //Color blind accessible
20473
20456
  }
20474
20457
 
20475
- IGVGraphics.fillRect(ctx, p0, y, p1 - p0, h, {fillStyle: color});
20458
+ IGVGraphics.fillRect(ctx, p0, y, p1 - p0, FRAME_HEIGHT, {fillStyle: color});
20476
20459
 
20477
20460
  if (options.bpPerPixel <= 1 / 10) {
20478
- IGVGraphics.strokeText(ctx, aaS, pc - (ctx.measureText(aaS).width / 2), y + 15);
20461
+ IGVGraphics.strokeText(ctx, aaLabel, pc - (ctx.measureText(aaLabel).width / 2), y + 15);
20479
20462
  }
20480
20463
  }
20464
+ y += (FRAME_HEIGHT + FRAME_BORDER);
20481
20465
  }
20482
20466
  }
20483
20467
  }
@@ -20488,6 +20472,7 @@ class SequenceTrack {
20488
20472
  }
20489
20473
 
20490
20474
  computePixelHeight(ignore) {
20475
+ this.height = this.frameTranslate ? TRANSLATED_HEIGHT : DEFAULT_HEIGHT;
20491
20476
  return this.height
20492
20477
  }
20493
20478
 
@@ -20500,8 +20485,26 @@ class SequenceTrack {
20500
20485
  } else {
20501
20486
  return 'rgb(0, 0, 150)'
20502
20487
  }
20488
+ }
20503
20489
 
20490
+ /**
20491
+ * Return the current state of the track. Used to create sessions and bookmarks.
20492
+ *
20493
+ * @returns {*|{}}
20494
+ */
20495
+ getState() {
20496
+ const config = {
20497
+ type: "sequence"
20498
+ };
20499
+ if (this.order !== defaultSequenceTrackOrder) {
20500
+ config.order = this.order;
20501
+ }
20502
+ if (this.reversed) {
20503
+ config.revealed = true;
20504
+ }
20505
+ return config
20504
20506
  }
20507
+
20505
20508
  }
20506
20509
 
20507
20510
  /*
@@ -22337,7 +22340,9 @@ class FastaSequence {
22337
22340
 
22338
22341
  async getSequence(chr, start, end) {
22339
22342
 
22340
- if (!(this.interval && this.interval.contains(chr, start, end))) {
22343
+ const hasCachedSquence = this.interval && this.interval.contains(chr, start, end);
22344
+
22345
+ if (!hasCachedSquence) {
22341
22346
 
22342
22347
  // Expand query, to minimum of 50kb
22343
22348
  let qstart = start;
@@ -22796,7 +22801,7 @@ const Cytoband = function (start, end, name, typestain) {
22796
22801
  }
22797
22802
  };
22798
22803
 
22799
- const _version = "2.12.2";
22804
+ const _version = "2.12.5";
22800
22805
  function version() {
22801
22806
  return _version
22802
22807
  }
@@ -23460,6 +23465,17 @@ class TrackViewport extends Viewport {
23460
23465
  }
23461
23466
  }
23462
23467
 
23468
+ repaintDimensions() {
23469
+ const isWGV = GenomeUtils.isWholeGenomeView(this.referenceFrame.chr);
23470
+ const pixelWidth = isWGV ? this.$viewport.width() : 3 * this.$viewport.width();
23471
+ const bpPerPixel = this.referenceFrame.bpPerPixel;
23472
+ const startBP = this.referenceFrame.start - (isWGV ? 0 : pixelWidth / 3 * bpPerPixel);
23473
+ const endBP = this.referenceFrame.end + (isWGV ? 0 : pixelWidth / 3 * bpPerPixel);
23474
+ return {
23475
+ startBP, endBP, pixelWidth
23476
+ }
23477
+ }
23478
+
23463
23479
  /**
23464
23480
  * Repaint the canvas using the cached features
23465
23481
  *
@@ -23474,11 +23490,11 @@ class TrackViewport extends Viewport {
23474
23490
  //this.tile.bpPerPixel = this.referenceFrame.bpPerPixel
23475
23491
 
23476
23492
  // const isWGV = GenomeUtils.isWholeGenomeView(this.browser.referenceFrameList[0].chr)
23477
- const isWGV = GenomeUtils.isWholeGenomeView(this.referenceFrame.chr);
23493
+ GenomeUtils.isWholeGenomeView(this.referenceFrame.chr);
23478
23494
 
23479
23495
  // Canvas dimensions. There is no left-right panning for WGV so canvas width is viewport width.
23480
23496
  // For deep tracks we paint a canvas == 3*viewportHeight centered on the current vertical scroll position
23481
- const pixelWidth = isWGV ? this.$viewport.width() : 3 * this.$viewport.width();
23497
+ const {startBP, endBP, pixelWidth} = this.repaintDimensions();
23482
23498
  const viewportHeight = this.$viewport.height();
23483
23499
  const contentHeight = this.getContentHeight();
23484
23500
  const minHeight = roiFeatures ? Math.max(contentHeight, viewportHeight) : contentHeight; // Need to fill viewport for ROIs.
@@ -23492,8 +23508,8 @@ class TrackViewport extends Viewport {
23492
23508
  const canvasTop = Math.max(0, -(this.$content.position().top) - viewportHeight);
23493
23509
 
23494
23510
  const bpPerPixel = this.referenceFrame.bpPerPixel;
23495
- const startBP = this.referenceFrame.start - (isWGV ? 0 : pixelWidth / 3 * bpPerPixel);
23496
- const endBP = this.referenceFrame.end + (isWGV ? 0 : pixelWidth / 3 * bpPerPixel);
23511
+ //const startBP = this.referenceFrame.start - (isWGV ? 0 : pixelWidth / 3 * bpPerPixel)
23512
+ //const endBP = this.referenceFrame.end + (isWGV ? 0 : pixelWidth / 3 * bpPerPixel)
23497
23513
  const pixelXOffset = Math.round((startBP - this.referenceFrame.start) / bpPerPixel);
23498
23514
 
23499
23515
  const newCanvas = $$1('<canvas class="igv-canvas">').get(0);
@@ -23756,10 +23772,9 @@ class TrackViewport extends Viewport {
23756
23772
  if (!this.featureCache) return true
23757
23773
  const referenceFrame = this.referenceFrame;
23758
23774
  const chr = this.referenceFrame.chr;
23759
- const start = referenceFrame.start;
23760
- const end = start + referenceFrame.toBP($$1(this.contentDiv).width());
23761
23775
  const bpPerPixel = referenceFrame.bpPerPixel;
23762
- return (!this.featureCache.containsRange(chr, start, end, bpPerPixel))
23776
+ const {startBP, endBP} = this.repaintDimensions();
23777
+ return (!this.featureCache.containsRange(chr, startBP, endBP, bpPerPixel))
23763
23778
  }
23764
23779
 
23765
23780
  createZoomInNotice($parent) {
@@ -29025,8 +29040,12 @@ class BamSource {
29025
29040
  */
29026
29041
 
29027
29042
  const fixColor = (colorString) => {
29028
- return (colorString.indexOf(",") > 0 && !colorString.startsWith("rgb")) ?
29029
- `rgb(${colorString})` : colorString
29043
+ if(isString$3(colorString)) {
29044
+ return (colorString.indexOf(",") > 0 && !colorString.startsWith("rgb(")) ?
29045
+ `rgb(${colorString})` : colorString
29046
+ } else {
29047
+ return colorString;
29048
+ }
29030
29049
  };
29031
29050
 
29032
29051
  /**
@@ -29180,7 +29199,7 @@ class TrackBase {
29180
29199
  }
29181
29200
 
29182
29201
  get supportsWholeGenome() {
29183
- return false
29202
+ return this.config.supportsWholeGenome === true
29184
29203
  }
29185
29204
 
29186
29205
  /**
@@ -39436,7 +39455,7 @@ function pack(featureList, maxRows) {
39436
39455
  let r = 0;
39437
39456
  const len = Math.min(rows.length, maxRows);
39438
39457
  for (r = 0; r < len; r++) {
39439
- if (feature.start > rows[r]) {
39458
+ if (feature.start >= rows[r]) {
39440
39459
  feature.row = r;
39441
39460
  rows[r] = feature.end;
39442
39461
  break
@@ -40953,7 +40972,7 @@ class BWSource {
40953
40972
  }
40954
40973
 
40955
40974
  supportsWholeGenome() {
40956
- return this.reader.type === "bigwig" || this.defaultVisibilityWindow() <= 0
40975
+ return this.reader.type === "bigwig"
40957
40976
  }
40958
40977
 
40959
40978
  async trackType() {
@@ -42188,7 +42207,15 @@ class FeatureTrack extends TrackBase {
42188
42207
  }
42189
42208
 
42190
42209
  get supportsWholeGenome() {
42191
- return (this.config.indexed === false || !this.config.indexURL) && this.config.supportsWholeGenome !== false
42210
+ if (this.config.supportsWholeGenome !== undefined) {
42211
+ return this.config.supportsWholeGenome
42212
+ } else if (this.featureSource && typeof this.featureSource.supportsWholeGenome === 'function') {
42213
+ return this.featureSource.supportsWholeGenome()
42214
+ } else {
42215
+ if (this.visibilityWindow === undefined && (this.config.indexed === false || !this.config.indexURL)) {
42216
+ return true
42217
+ }
42218
+ }
42192
42219
  }
42193
42220
 
42194
42221
  async getFeatures(chr, start, end, bpPerPixel) {
@@ -42245,7 +42272,7 @@ class FeatureTrack extends TrackBase {
42245
42272
  options.rowLastX = [];
42246
42273
  options.rowLastLabelX = [];
42247
42274
  for (let feature of featureList) {
42248
- if(feature.start > bpStart && feature.end < bpEnd) {
42275
+ if (feature.start > bpStart && feature.end < bpEnd) {
42249
42276
  const row = this.displayMode === "COLLAPSED" ? 0 : feature.row || 0;
42250
42277
  if (rowFeatureCount[row] === undefined) {
42251
42278
  rowFeatureCount[row] = 1;
@@ -44509,6 +44536,8 @@ const isString = isString$3;
44509
44536
 
44510
44537
  const DEFAULT_VISIBILITY_WINDOW = 1000000;
44511
44538
  const TOP_MARGIN = 10;
44539
+ const STANDARD_FIELDS = new Map([["REF", "referenceBases"], ["ALT", "alternateBases"], ["QUAL", "quality"], ["FILTER", "filter"]]);
44540
+
44512
44541
 
44513
44542
  class VariantTrack extends TrackBase {
44514
44543
 
@@ -44550,7 +44579,6 @@ class VariantTrack extends TrackBase {
44550
44579
  this.colorTables = new Map();
44551
44580
  this.colorTables.set(config.colorBy, new ColorTable(config.colorTable));
44552
44581
  }
44553
- this._color = config.color;
44554
44582
 
44555
44583
  this.showGenotypes = config.showGenotypes === undefined ? true : config.showGenotypes;
44556
44584
 
@@ -44659,9 +44687,9 @@ class VariantTrack extends TrackBase {
44659
44687
  IGVGraphics.fillRect(context, 0, pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
44660
44688
 
44661
44689
  const vGap = ("SQUISHED" === this.displayMode) ? this.squishedVGap : this.expandedVGap;
44662
- const rc = ("COLLAPSED" === this.displayMode) ? 1 : this.nVariantRows;
44690
+ const rowCount = ("COLLAPSED" === this.displayMode) ? 1 : this.nVariantRows;
44663
44691
  const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight;
44664
- this.variantBandHeight = TOP_MARGIN + rc * (variantHeight + vGap);
44692
+ this.variantBandHeight = TOP_MARGIN + rowCount * (variantHeight + vGap);
44665
44693
 
44666
44694
  const callSets = this.callSets;
44667
44695
  const nCalls = this.getCallsetsLength();
@@ -44761,14 +44789,21 @@ class VariantTrack extends TrackBase {
44761
44789
  let variantColor;
44762
44790
 
44763
44791
  if (this.colorBy) {
44764
- const value = v.info[this.colorBy];
44765
- variantColor = this.getVariantColorTable(this.colorBy).getColor(value);
44792
+ const colorBy = this.colorBy;
44793
+ let value;
44794
+ if (v.info.hasOwnProperty(colorBy)) {
44795
+ value = v.info[colorBy];
44796
+ } else if (STANDARD_FIELDS.has(colorBy)) {
44797
+ const key = STANDARD_FIELDS.get(colorBy);
44798
+ value = v[key];
44799
+ }
44800
+ variantColor = this.getVariantColorTable(colorBy).getColor(value);
44766
44801
  if (!variantColor) {
44767
44802
  variantColor = "gray";
44768
44803
  }
44769
44804
 
44770
44805
  } else if (this._color) {
44771
- variantColor = this.color;
44806
+ variantColor = (typeof this._color === "function") ? this._color(variant) : this._color;
44772
44807
  } else if ("NONVARIANT" === v.type) {
44773
44808
  variantColor = this.nonRefColor;
44774
44809
  } else if ("MIXED" === v.type) {
@@ -44779,9 +44814,6 @@ class VariantTrack extends TrackBase {
44779
44814
  return variantColor
44780
44815
  }
44781
44816
 
44782
- get color() {
44783
- return this._color ? ((typeof this._color === "function") ? this._color(v) : this._color) : this.defaultColor
44784
- }
44785
44817
 
44786
44818
  clickedFeatures(clickState, features) {
44787
44819
 
@@ -44794,15 +44826,17 @@ class VariantTrack extends TrackBase {
44794
44826
  if (yOffset <= this.variantBandHeight) {
44795
44827
  // Variant
44796
44828
  const variantHeight = ("SQUISHED" === this.displayMode) ? this.squishedVariantHeight : this.expandedVariantHeight;
44797
- const variantRow = (Math.floor)((yOffset - TOP_MARGIN) / (variantHeight + vGap));
44798
- featureList = featureList.filter(f => f.row === variantRow);
44829
+ const variantRow = Math.floor((yOffset - TOP_MARGIN) / (variantHeight + vGap));
44830
+ if ("COLLAPSED" !== this.displayMode) {
44831
+ featureList = featureList.filter(f => f.row === variantRow);
44832
+ }
44799
44833
  } else if (this.callSets) {
44800
44834
  const callSets = this.callSets;
44801
44835
  const sampleY = yOffset - this.variantBandHeight;
44802
44836
  const sampleRow = Math.floor(sampleY / this.sampleHeight);
44803
44837
  if (sampleRow >= 0 && sampleRow < callSets.length) {
44804
44838
  const variantRow = Math.floor((sampleY - sampleRow * this.sampleHeight) / callHeight);
44805
- const variants = featureList.filter(f => f.row === variantRow);
44839
+ const variants = "COLLAPSED" === this.displayMode ? featureList : featureList.filter(f => f.row === variantRow);
44806
44840
  const cs = callSets[sampleRow];
44807
44841
  featureList = variants.map(v => {
44808
44842
  const call = v.calls[cs.id];
@@ -45016,7 +45050,7 @@ class VariantTrack extends TrackBase {
45016
45050
  label: 'Add SVs to circular view',
45017
45051
  click: () => {
45018
45052
  for (let viewport of this.trackView.viewports) {
45019
- this.sendChordsForViewport(viewport);
45053
+ this.sendChordsForViewport(viewport);
45020
45054
  }
45021
45055
  }
45022
45056
  });