@jbrowse/plugin-alignments 1.6.5 → 1.6.8

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.
Files changed (52) hide show
  1. package/dist/AlignmentsFeatureDetail/index.d.ts +1 -1
  2. package/dist/BamAdapter/BamSlightlyLazyFeature.d.ts +2 -10
  3. package/dist/BamAdapter/MismatchParser.d.ts +3 -5
  4. package/dist/BamAdapter/configSchema.d.ts +1 -1
  5. package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +1 -2
  6. package/dist/CramAdapter/configSchema.d.ts +1 -1
  7. package/dist/HtsgetBamAdapter/configSchema.d.ts +1 -1
  8. package/dist/LinearAlignmentsDisplay/models/configSchema.d.ts +1 -1
  9. package/dist/LinearAlignmentsDisplay/models/model.d.ts +1 -1
  10. package/dist/LinearPileupDisplay/configSchema.d.ts +1 -1
  11. package/dist/LinearSNPCoverageDisplay/components/Tooltip.d.ts +1 -1
  12. package/dist/LinearSNPCoverageDisplay/models/configSchema.d.ts +1 -1
  13. package/dist/LinearSNPCoverageDisplay/models/model.d.ts +2 -2
  14. package/dist/PileupRenderer/PileupRenderer.d.ts +20 -6
  15. package/dist/PileupRenderer/configSchema.d.ts +1 -1
  16. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +3 -11
  17. package/dist/SNPCoverageAdapter/configSchema.d.ts +1 -1
  18. package/dist/SNPCoverageRenderer/SNPCoverageRenderer.d.ts +1 -1
  19. package/dist/SNPCoverageRenderer/configSchema.d.ts +1 -1
  20. package/dist/SNPCoverageRenderer/index.d.ts +1 -1
  21. package/dist/plugin-alignments.cjs.development.js +795 -682
  22. package/dist/plugin-alignments.cjs.development.js.map +1 -1
  23. package/dist/plugin-alignments.cjs.production.min.js +1 -1
  24. package/dist/plugin-alignments.cjs.production.min.js.map +1 -1
  25. package/dist/plugin-alignments.esm.js +797 -684
  26. package/dist/plugin-alignments.esm.js.map +1 -1
  27. package/dist/util.d.ts +4 -0
  28. package/package.json +4 -4
  29. package/src/AlignmentsFeatureDetail/AlignmentsFeatureDetail.tsx +23 -14
  30. package/src/BamAdapter/BamAdapter.ts +10 -7
  31. package/src/BamAdapter/BamSlightlyLazyFeature.ts +11 -75
  32. package/src/BamAdapter/MismatchParser.test.ts +53 -297
  33. package/src/BamAdapter/MismatchParser.ts +54 -116
  34. package/src/BamAdapter/configSchema.ts +0 -4
  35. package/src/CramAdapter/CramSlightlyLazyFeature.ts +3 -10
  36. package/src/LinearAlignmentsDisplay/components/AlignmentsDisplay.tsx +38 -30
  37. package/src/LinearAlignmentsDisplay/models/model.tsx +10 -9
  38. package/src/LinearPileupDisplay/components/ColorByModifications.tsx +76 -80
  39. package/src/LinearPileupDisplay/components/ColorByTag.tsx +24 -23
  40. package/src/LinearPileupDisplay/components/FilterByTag.tsx +73 -68
  41. package/src/LinearPileupDisplay/components/SetFeatureHeight.tsx +28 -26
  42. package/src/LinearPileupDisplay/components/SetMaxHeight.tsx +24 -13
  43. package/src/LinearPileupDisplay/components/SortByTag.tsx +29 -21
  44. package/src/LinearPileupDisplay/model.ts +12 -6
  45. package/src/LinearSNPCoverageDisplay/components/Tooltip.tsx +5 -3
  46. package/src/LinearSNPCoverageDisplay/models/configSchema.ts +4 -5
  47. package/src/PileupRenderer/PileupRenderer.tsx +202 -70
  48. package/src/PileupRenderer/components/PileupRendering.tsx +5 -3
  49. package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +192 -237
  50. package/src/SNPCoverageRenderer/SNPCoverageRenderer.ts +91 -60
  51. package/src/SNPCoverageRenderer/configSchema.js +1 -1
  52. package/src/util.ts +25 -0
@@ -15,9 +15,9 @@ var rxjs = require('@jbrowse/core/util/rxjs');
15
15
  var operators = require('rxjs/operators');
16
16
  var ui = require('@jbrowse/core/ui');
17
17
  var pluginWiggle = require('@jbrowse/plugin-wiggle');
18
+ var Color = _interopDefault(require('color'));
18
19
  var BoxRendererType = require('@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType');
19
20
  var BoxRendererType__default = _interopDefault(BoxRendererType);
20
- var Color = _interopDefault(require('color'));
21
21
  var offscreenCanvasUtils = require('@jbrowse/core/util/offscreenCanvasUtils');
22
22
  var dataAdapterCache = require('@jbrowse/core/data_adapters/dataAdapterCache');
23
23
  var range = require('@jbrowse/core/util/range');
@@ -29,6 +29,7 @@ var DisplayType = _interopDefault(require('@jbrowse/core/pluggableElementTypes/D
29
29
  var pluginLinearGenomeView = require('@jbrowse/plugin-linear-genome-view');
30
30
  var models = require('@jbrowse/core/pluggableElementTypes/models');
31
31
  var mobx = require('mobx');
32
+ var core = require('@material-ui/core');
32
33
  var SerializableFilterChain = _interopDefault(require('@jbrowse/core/pluggableElementTypes/renderers/util/serializableFilterChain'));
33
34
  var tracks = require('@jbrowse/core/util/tracks');
34
35
  var VisibilityIcon = _interopDefault(require('@material-ui/icons/Visibility'));
@@ -46,7 +47,6 @@ var RpcMethodType = _interopDefault(require('@jbrowse/core/pluggableElementTypes
46
47
  var cram = require('@gmod/cram');
47
48
  var io = require('@jbrowse/core/util/io');
48
49
  var bam = require('@gmod/bam');
49
- var core = require('@material-ui/core');
50
50
  var CloseIcon = _interopDefault(require('@material-ui/icons/Close'));
51
51
  var BaseFeatureDetail = require('@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail');
52
52
 
@@ -1168,62 +1168,80 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
1168
1168
  });
1169
1169
 
1170
1170
  var _marked = /*#__PURE__*/runtime_1.mark(getNextRefPos);
1171
+ var mdRegex = /*#__PURE__*/new RegExp(/(\d+|\^[a-z]+|[a-z])/gi);
1171
1172
  function parseCigar(cigar) {
1172
1173
  return (cigar || '').split(/([MIDNSHPX=])/);
1173
1174
  }
1174
- function cigarToMismatches(ops, seq, qual) {
1175
- var currOffset = 0;
1176
- var seqOffset = 0;
1175
+ function cigarToMismatches(ops, seq, ref, qual) {
1176
+ var roffset = 0; // reference offset
1177
+
1178
+ var soffset = 0; // seq offset
1179
+
1177
1180
  var mismatches = [];
1181
+ var hasRefAndSeq = ref && seq;
1178
1182
 
1179
- for (var i = 0; i < ops.length - 1; i += 2) {
1183
+ for (var i = 0; i < ops.length; i += 2) {
1180
1184
  var len = +ops[i];
1181
1185
  var op = ops[i + 1];
1182
1186
 
1183
1187
  if (op === 'M' || op === '=' || op === 'E') {
1184
- seqOffset += len;
1188
+ if (hasRefAndSeq) {
1189
+ for (var j = 0; j < len; j++) {
1190
+ if ( // @ts-ignore in the full yarn build of the repo, this says that object is possibly undefined for some reason, ignored
1191
+ seq[soffset + j].toUpperCase() !== ref[roffset + j].toUpperCase()) {
1192
+ mismatches.push({
1193
+ start: roffset + j,
1194
+ type: 'mismatch',
1195
+ base: seq[soffset + j],
1196
+ length: 1
1197
+ });
1198
+ }
1199
+ }
1200
+ }
1201
+
1202
+ soffset += len;
1185
1203
  }
1186
1204
 
1187
1205
  if (op === 'I') {
1188
1206
  mismatches.push({
1189
- start: currOffset,
1207
+ start: roffset,
1190
1208
  type: 'insertion',
1191
1209
  base: "".concat(len),
1192
1210
  length: 0
1193
1211
  });
1194
- seqOffset += len;
1212
+ soffset += len;
1195
1213
  } else if (op === 'D') {
1196
1214
  mismatches.push({
1197
- start: currOffset,
1215
+ start: roffset,
1198
1216
  type: 'deletion',
1199
1217
  base: '*',
1200
1218
  length: len
1201
1219
  });
1202
1220
  } else if (op === 'N') {
1203
1221
  mismatches.push({
1204
- start: currOffset,
1222
+ start: roffset,
1205
1223
  type: 'skip',
1206
1224
  base: 'N',
1207
1225
  length: len
1208
1226
  });
1209
1227
  } else if (op === 'X') {
1210
- var r = seq.slice(seqOffset, seqOffset + len);
1211
- var q = (qual === null || qual === void 0 ? void 0 : qual.slice(seqOffset, seqOffset + len)) || [];
1228
+ var r = seq.slice(soffset, soffset + len);
1229
+ var q = (qual === null || qual === void 0 ? void 0 : qual.slice(soffset, soffset + len)) || [];
1212
1230
 
1213
- for (var j = 0; j < len; j++) {
1231
+ for (var _j = 0; _j < len; _j++) {
1214
1232
  mismatches.push({
1215
- start: currOffset + j,
1233
+ start: roffset + _j,
1216
1234
  type: 'mismatch',
1217
- base: r[j],
1218
- qual: q[j],
1235
+ base: r[_j],
1236
+ qual: q[_j],
1219
1237
  length: 1
1220
1238
  });
1221
1239
  }
1222
1240
 
1223
- seqOffset += len;
1241
+ soffset += len;
1224
1242
  } else if (op === 'H') {
1225
1243
  mismatches.push({
1226
- start: currOffset,
1244
+ start: roffset,
1227
1245
  type: 'hardclip',
1228
1246
  base: "H".concat(len),
1229
1247
  cliplen: len,
@@ -1231,17 +1249,17 @@ function cigarToMismatches(ops, seq, qual) {
1231
1249
  });
1232
1250
  } else if (op === 'S') {
1233
1251
  mismatches.push({
1234
- start: currOffset,
1252
+ start: roffset,
1235
1253
  type: 'softclip',
1236
1254
  base: "S".concat(len),
1237
1255
  cliplen: len,
1238
1256
  length: 1
1239
1257
  });
1240
- seqOffset += len;
1258
+ soffset += len;
1241
1259
  }
1242
1260
 
1243
1261
  if (op !== 'I' && op !== 'S' && op !== 'H') {
1244
- currOffset += len;
1262
+ roffset += len;
1245
1263
  }
1246
1264
  }
1247
1265
 
@@ -1252,7 +1270,7 @@ function cigarToMismatches(ops, seq, qual) {
1252
1270
  * @returns array of mismatches and their positions
1253
1271
  */
1254
1272
 
1255
- function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1273
+ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
1256
1274
  var mismatchRecords = [];
1257
1275
  var curr = {
1258
1276
  start: 0,
@@ -1285,9 +1303,9 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1285
1303
  var templateOffset = lastTemplateOffset;
1286
1304
  var refOffset = lastRefOffset;
1287
1305
 
1288
- for (var i = lastCigar; i < cigarOps.length && refOffset <= refCoord; i += 2, lastCigar = i) {
1289
- var len = +cigarOps[i];
1290
- var op = cigarOps[i + 1];
1306
+ for (var i = lastCigar; i < ops.length && refOffset <= refCoord; i += 2, lastCigar = i) {
1307
+ var len = +ops[i];
1308
+ var op = ops[i + 1];
1291
1309
 
1292
1310
  if (op === 'S' || op === 'I') {
1293
1311
  templateOffset += len;
@@ -1305,7 +1323,7 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1305
1323
  } // now actually parse the MD string
1306
1324
 
1307
1325
 
1308
- var md = mdstring.match(/(\d+|\^[a-z]+|[a-z])/gi) || [];
1326
+ var md = mdstring.match(mdRegex) || [];
1309
1327
 
1310
1328
  for (var i = 0; i < md.length; i++) {
1311
1329
  var token = md[i];
@@ -1314,11 +1332,7 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1314
1332
  if (!Number.isNaN(num)) {
1315
1333
  curr.start += num;
1316
1334
  } else if (token.startsWith('^')) {
1317
- curr.length = token.length - 1;
1318
- curr.base = '*';
1319
- curr.type = 'deletion';
1320
- curr.seq = token.substring(1);
1321
- nextRecord();
1335
+ curr.start += token.length - 1;
1322
1336
  } else {
1323
1337
  // mismatch
1324
1338
  for (var j = 0; j < token.length; j += 1) {
@@ -1335,9 +1349,9 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1335
1349
  }
1336
1350
  }
1337
1351
 
1338
- var s = cigarOps ? getTemplateCoordLocal(curr.start) : curr.start;
1339
- curr.base = seq ? seq.substr(s, 1) : 'X';
1340
- var qualScore = qual === null || qual === void 0 ? void 0 : qual.slice(s, s + 1)[0];
1352
+ var s = getTemplateCoordLocal(curr.start);
1353
+ curr.base = seq[s] || 'X';
1354
+ var qualScore = qual === null || qual === void 0 ? void 0 : qual[s];
1341
1355
 
1342
1356
  if (qualScore) {
1343
1357
  curr.qual = qualScore;
@@ -1351,103 +1365,20 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1351
1365
 
1352
1366
  return mismatchRecords;
1353
1367
  }
1354
- function getTemplateCoord(refCoord, cigarOps) {
1355
- var templateOffset = 0;
1356
- var refOffset = 0;
1357
-
1358
- for (var i = 0; i < cigarOps.length && refOffset <= refCoord; i += 2) {
1359
- var len = +cigarOps[i];
1360
- var op = cigarOps[i + 1];
1361
-
1362
- if (op === 'S' || op === 'I') {
1363
- templateOffset += len;
1364
- } else if (op === 'D' || op === 'P') {
1365
- refOffset += len;
1366
- } else if (op !== 'H') {
1367
- templateOffset += len;
1368
- refOffset += len;
1369
- }
1370
- }
1371
-
1372
- return templateOffset - (refOffset - refCoord);
1373
- }
1374
- function getMismatches(cigarString, mdString, seq, qual) {
1368
+ function getMismatches(cigar, md, seq, ref, qual) {
1375
1369
  var mismatches = [];
1376
- var cigarOps = []; // parse the CIGAR tag if it has one
1370
+ var ops = parseCigar(cigar); // parse the CIGAR tag if it has one
1377
1371
 
1378
- if (cigarString) {
1379
- cigarOps = parseCigar(cigarString);
1380
- mismatches = mismatches.concat(cigarToMismatches(cigarOps, seq, qual));
1372
+ if (cigar) {
1373
+ mismatches = mismatches.concat(cigarToMismatches(ops, seq, ref, qual));
1381
1374
  } // now let's look for CRAM or MD mismatches
1382
1375
 
1383
1376
 
1384
- if (mdString) {
1385
- mismatches = mismatches.concat(mdToMismatches(mdString, cigarOps, mismatches, seq, qual));
1386
- } // uniqify the mismatches
1387
-
1388
-
1389
- var seen = {};
1390
- return mismatches.filter(function (m) {
1391
- var key = "".concat(m.type, ",").concat(m.start, ",").concat(m.length);
1392
- var s = seen[key];
1393
- seen[key] = true;
1394
- return !s;
1395
- });
1396
- } // adapted from minimap2 code static void write_MD_core function
1397
-
1398
- function generateMD(target, query, cigar) {
1399
- var queryOffset = 0;
1400
- var targetOffset = 0;
1401
- var lengthMD = 0;
1402
-
1403
- if (!target) {
1404
- console.warn('no ref supplied to generateMD');
1405
- return '';
1377
+ if (md) {
1378
+ mismatches = mismatches.concat(mdToMismatches(md, ops, mismatches, seq, qual));
1406
1379
  }
1407
1380
 
1408
- var cigarOps = parseCigar(cigar);
1409
- var str = '';
1410
-
1411
- for (var i = 0; i < cigarOps.length; i += 2) {
1412
- var len = +cigarOps[i];
1413
- var op = cigarOps[i + 1];
1414
-
1415
- if (op === 'M' || op === 'X' || op === '=') {
1416
- for (var j = 0; j < len; j++) {
1417
- if (query[queryOffset + j].toLowerCase() !== target[targetOffset + j].toLowerCase()) {
1418
- str += "".concat(lengthMD).concat(target[targetOffset + j].toUpperCase());
1419
- lengthMD = 0;
1420
- } else {
1421
- lengthMD++;
1422
- }
1423
- }
1424
-
1425
- queryOffset += len;
1426
- targetOffset += len;
1427
- } else if (op === 'I') {
1428
- queryOffset += len;
1429
- } else if (op === 'D') {
1430
- var tmp = '';
1431
-
1432
- for (var _j = 0; _j < len; _j++) {
1433
- tmp += target[targetOffset + _j].toUpperCase();
1434
- }
1435
-
1436
- str += "".concat(lengthMD, "^").concat(tmp);
1437
- lengthMD = 0;
1438
- targetOffset += len;
1439
- } else if (op === 'N') {
1440
- targetOffset += len;
1441
- } else if (op === 'S') {
1442
- queryOffset += len;
1443
- }
1444
- }
1445
-
1446
- if (lengthMD > 0) {
1447
- str += lengthMD;
1448
- }
1449
-
1450
- return str;
1381
+ return mismatches;
1451
1382
  } // get relative reference sequence positions for positions given relative to
1452
1383
  // the read sequence
1453
1384
 
@@ -1595,9 +1526,7 @@ var MismatchParser = {
1595
1526
  parseCigar: parseCigar,
1596
1527
  cigarToMismatches: cigarToMismatches,
1597
1528
  mdToMismatches: mdToMismatches,
1598
- getTemplateCoord: getTemplateCoord,
1599
1529
  getMismatches: getMismatches,
1600
- generateMD: generateMD,
1601
1530
  getNextRefPos: getNextRefPos,
1602
1531
  getModificationPositions: getModificationPositions,
1603
1532
  getModificationTypes: getModificationTypes
@@ -1668,10 +1597,6 @@ var configSchema = /*#__PURE__*/mobxStateTree.types.late(function () {
1668
1597
  }
1669
1598
  }
1670
1599
  }),
1671
- chunkSizeLimit: {
1672
- type: 'number',
1673
- defaultValue: 100000000
1674
- },
1675
1600
  fetchSizeLimit: {
1676
1601
  type: 'number',
1677
1602
  defaultValue: 5000000
@@ -1748,8 +1673,8 @@ var configSchemaFactory = (function (pluginManager) {
1748
1673
  });
1749
1674
  });
1750
1675
 
1751
- // get tag from BAM or CRAM feature, where CRAM uses feature.get('tags') and
1752
1676
  // BAM does not
1677
+
1753
1678
  function getTag(feature, tag) {
1754
1679
  var tags = feature.get('tags');
1755
1680
  return tags ? tags[tag] : feature.get(tag);
@@ -1793,6 +1718,43 @@ var orientationTypes = {
1793
1718
  F1F2: 'RL'
1794
1719
  }
1795
1720
  };
1721
+ function fetchSequence(_x, _x2) {
1722
+ return _fetchSequence.apply(this, arguments);
1723
+ } // has to check underlying C-G (aka CpG) on the reference sequence
1724
+
1725
+ function _fetchSequence() {
1726
+ _fetchSequence = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(region, adapter) {
1727
+ var _feats$;
1728
+
1729
+ var end, originalRefName, refName, feats;
1730
+ return runtime_1.wrap(function _callee$(_context) {
1731
+ while (1) {
1732
+ switch (_context.prev = _context.next) {
1733
+ case 0:
1734
+ end = region.end, originalRefName = region.originalRefName, refName = region.refName;
1735
+ _context.next = 3;
1736
+ return adapter.getFeatures(_objectSpread2(_objectSpread2({}, region), {}, {
1737
+ refName: originalRefName || refName,
1738
+ end: end + 1
1739
+ })).pipe(operators.toArray()).toPromise();
1740
+
1741
+ case 3:
1742
+ feats = _context.sent;
1743
+ return _context.abrupt("return", (_feats$ = feats[0]) === null || _feats$ === void 0 ? void 0 : _feats$.get('seq'));
1744
+
1745
+ case 5:
1746
+ case "end":
1747
+ return _context.stop();
1748
+ }
1749
+ }
1750
+ }, _callee);
1751
+ }));
1752
+ return _fetchSequence.apply(this, arguments);
1753
+ }
1754
+
1755
+ function shouldFetchReferenceSequence(type) {
1756
+ return type === 'methylation';
1757
+ }
1796
1758
 
1797
1759
  function mismatchLen(mismatch) {
1798
1760
  return !isInterbase(mismatch.type) ? mismatch.length : 1;
@@ -1858,8 +1820,8 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1858
1820
  while (1) {
1859
1821
  switch (_context.prev = _context.next) {
1860
1822
  case 0:
1861
- subadapterConfig = configuration.readConfObject(this.config, 'subadapter');
1862
- sequenceConf = configuration.readConfObject(this.config, ['subadapter', 'sequenceAdapter']);
1823
+ subadapterConfig = this.getConf('subadapter');
1824
+ sequenceConf = this.getConf(['subadapter', 'sequenceAdapter']);
1863
1825
  _context.next = 4;
1864
1826
  return (_this$getSubAdapter = this.getSubAdapter) === null || _this$getSubAdapter === void 0 ? void 0 : _this$getSubAdapter.call(this, subadapterConfig);
1865
1827
 
@@ -1912,6 +1874,47 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1912
1874
 
1913
1875
  return configure;
1914
1876
  }()
1877
+ }, {
1878
+ key: "fetchSequence",
1879
+ value: function () {
1880
+ var _fetchSequence2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(region) {
1881
+ var _yield$this$configure, sequenceAdapter;
1882
+
1883
+ return runtime_1.wrap(function _callee2$(_context2) {
1884
+ while (1) {
1885
+ switch (_context2.prev = _context2.next) {
1886
+ case 0:
1887
+ _context2.next = 2;
1888
+ return this.configure();
1889
+
1890
+ case 2:
1891
+ _yield$this$configure = _context2.sent;
1892
+ sequenceAdapter = _yield$this$configure.sequenceAdapter;
1893
+
1894
+ if (sequenceAdapter) {
1895
+ _context2.next = 6;
1896
+ break;
1897
+ }
1898
+
1899
+ return _context2.abrupt("return", undefined);
1900
+
1901
+ case 6:
1902
+ return _context2.abrupt("return", fetchSequence(region, sequenceAdapter));
1903
+
1904
+ case 7:
1905
+ case "end":
1906
+ return _context2.stop();
1907
+ }
1908
+ }
1909
+ }, _callee2, this);
1910
+ }));
1911
+
1912
+ function fetchSequence$1(_x) {
1913
+ return _fetchSequence2.apply(this, arguments);
1914
+ }
1915
+
1916
+ return fetchSequence$1;
1917
+ }()
1915
1918
  }, {
1916
1919
  key: "getFeatures",
1917
1920
  value: function getFeatures(region) {
@@ -1919,48 +1922,50 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1919
1922
 
1920
1923
  var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1921
1924
  return rxjs.ObservableCreate( /*#__PURE__*/function () {
1922
- var _ref = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(observer) {
1923
- var _yield$_this$configur, subadapter, stream, filters, _yield$_this$generate, bins, skipmap;
1925
+ var _ref = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(observer) {
1926
+ var _yield$_this$configur, subadapter, feats, filters, _yield$_this$generate, bins, skipmap;
1924
1927
 
1925
- return runtime_1.wrap(function _callee2$(_context2) {
1928
+ return runtime_1.wrap(function _callee3$(_context3) {
1926
1929
  while (1) {
1927
- switch (_context2.prev = _context2.next) {
1930
+ switch (_context3.prev = _context3.next) {
1928
1931
  case 0:
1929
- _context2.next = 2;
1932
+ _context3.next = 2;
1930
1933
  return _this.configure();
1931
1934
 
1932
1935
  case 2:
1933
- _yield$_this$configur = _context2.sent;
1936
+ _yield$_this$configur = _context3.sent;
1934
1937
  subadapter = _yield$_this$configur.subadapter;
1935
- stream = subadapter.getFeatures(region, opts);
1938
+ _context3.next = 6;
1939
+ return subadapter.getFeatures(region, opts).pipe(operators.toArray()).toPromise();
1940
+
1941
+ case 6:
1942
+ feats = _context3.sent;
1936
1943
 
1937
1944
  if (opts.filters) {
1938
1945
  filters = opts.filters;
1939
- stream = stream.pipe(operators.filter(function (f) {
1946
+ feats = feats.filter(function (f) {
1940
1947
  return filters.passes(f, opts);
1941
- }));
1948
+ });
1942
1949
  }
1943
1950
 
1944
- _context2.next = 8;
1945
- return _this.generateCoverageBins(stream, region, opts);
1951
+ _context3.next = 10;
1952
+ return _this.generateCoverageBins(feats, region, opts);
1946
1953
 
1947
- case 8:
1948
- _yield$_this$generate = _context2.sent;
1954
+ case 10:
1955
+ _yield$_this$generate = _context3.sent;
1949
1956
  bins = _yield$_this$generate.bins;
1950
1957
  skipmap = _yield$_this$generate.skipmap;
1951
1958
  bins.forEach(function (bin, index) {
1952
- if (bin.total) {
1953
- observer.next(new SimpleFeature({
1954
- id: "".concat(_this.id, "-").concat(region.start, "-").concat(index),
1955
- data: {
1956
- score: bin.total,
1957
- snpinfo: bin,
1958
- start: region.start + index,
1959
- end: region.start + index + 1,
1960
- refName: region.refName
1961
- }
1962
- }));
1963
- }
1959
+ observer.next(new SimpleFeature({
1960
+ id: "".concat(_this.id, "-").concat(region.start, "-").concat(index),
1961
+ data: {
1962
+ score: bin.total,
1963
+ snpinfo: bin,
1964
+ start: region.start + index,
1965
+ end: region.start + index + 1,
1966
+ refName: region.refName
1967
+ }
1968
+ }));
1964
1969
  }); // make fake features from the coverage
1965
1970
 
1966
1971
  Object.entries(skipmap).forEach(function (_ref2) {
@@ -1982,15 +1987,15 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1982
1987
  });
1983
1988
  observer.complete();
1984
1989
 
1985
- case 14:
1990
+ case 16:
1986
1991
  case "end":
1987
- return _context2.stop();
1992
+ return _context3.stop();
1988
1993
  }
1989
1994
  }
1990
- }, _callee2);
1995
+ }, _callee3);
1991
1996
  }));
1992
1997
 
1993
- return function (_x) {
1998
+ return function (_x2) {
1994
1999
  return _ref.apply(this, arguments);
1995
2000
  };
1996
2001
  }(), opts.signal);
@@ -1998,30 +2003,30 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1998
2003
  }, {
1999
2004
  key: "estimateRegionsStats",
2000
2005
  value: function () {
2001
- var _estimateRegionsStats = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(regions, opts) {
2002
- var _yield$this$configure, subadapter;
2006
+ var _estimateRegionsStats = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee4(regions, opts) {
2007
+ var _yield$this$configure2, subadapter;
2003
2008
 
2004
- return runtime_1.wrap(function _callee3$(_context3) {
2009
+ return runtime_1.wrap(function _callee4$(_context4) {
2005
2010
  while (1) {
2006
- switch (_context3.prev = _context3.next) {
2011
+ switch (_context4.prev = _context4.next) {
2007
2012
  case 0:
2008
- _context3.next = 2;
2013
+ _context4.next = 2;
2009
2014
  return this.configure();
2010
2015
 
2011
2016
  case 2:
2012
- _yield$this$configure = _context3.sent;
2013
- subadapter = _yield$this$configure.subadapter;
2014
- return _context3.abrupt("return", subadapter.estimateRegionsStats(regions, opts));
2017
+ _yield$this$configure2 = _context4.sent;
2018
+ subadapter = _yield$this$configure2.subadapter;
2019
+ return _context4.abrupt("return", subadapter.estimateRegionsStats(regions, opts));
2015
2020
 
2016
2021
  case 5:
2017
2022
  case "end":
2018
- return _context3.stop();
2023
+ return _context4.stop();
2019
2024
  }
2020
2025
  }
2021
- }, _callee3, this);
2026
+ }, _callee4, this);
2022
2027
  }));
2023
2028
 
2024
- function estimateRegionsStats(_x2, _x3) {
2029
+ function estimateRegionsStats(_x3, _x4) {
2025
2030
  return _estimateRegionsStats.apply(this, arguments);
2026
2031
  }
2027
2032
 
@@ -2030,31 +2035,31 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2030
2035
  }, {
2031
2036
  key: "getRefNames",
2032
2037
  value: function () {
2033
- var _getRefNames = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee4() {
2038
+ var _getRefNames = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee5() {
2034
2039
  var opts,
2035
- _yield$this$configure2,
2040
+ _yield$this$configure3,
2036
2041
  subadapter,
2037
- _args4 = arguments;
2042
+ _args5 = arguments;
2038
2043
 
2039
- return runtime_1.wrap(function _callee4$(_context4) {
2044
+ return runtime_1.wrap(function _callee5$(_context5) {
2040
2045
  while (1) {
2041
- switch (_context4.prev = _context4.next) {
2046
+ switch (_context5.prev = _context5.next) {
2042
2047
  case 0:
2043
- opts = _args4.length > 0 && _args4[0] !== undefined ? _args4[0] : {};
2044
- _context4.next = 3;
2048
+ opts = _args5.length > 0 && _args5[0] !== undefined ? _args5[0] : {};
2049
+ _context5.next = 3;
2045
2050
  return this.configure();
2046
2051
 
2047
2052
  case 3:
2048
- _yield$this$configure2 = _context4.sent;
2049
- subadapter = _yield$this$configure2.subadapter;
2050
- return _context4.abrupt("return", subadapter.getRefNames(opts));
2053
+ _yield$this$configure3 = _context5.sent;
2054
+ subadapter = _yield$this$configure3.subadapter;
2055
+ return _context5.abrupt("return", subadapter.getRefNames(opts));
2051
2056
 
2052
2057
  case 6:
2053
2058
  case "end":
2054
- return _context4.stop();
2059
+ return _context5.stop();
2055
2060
  }
2056
2061
  }
2057
- }, _callee4, this);
2062
+ }, _callee5, this);
2058
2063
  }));
2059
2064
 
2060
2065
  function getRefNames() {
@@ -2068,69 +2073,54 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2068
2073
  value: function
2069
2074
  /* { region } */
2070
2075
  freeResources() {}
2071
- /**
2072
- * Generates coverage bins from features which details
2073
- * the reference, mismatches, strands, and coverage info
2074
- * @param features - Features of region to be passed in
2075
- * @param region - Region
2076
- * @param bpPerPx - base pairs per pixel
2077
- * @returns Array of nested frequency tables
2078
- */
2079
-
2080
2076
  }, {
2081
2077
  key: "generateCoverageBins",
2082
2078
  value: function () {
2083
- var _generateCoverageBins = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee5(features, region, opts) {
2084
- var colorBy, _yield$this$configure3, sequenceAdapter, originalRefName, refName, start, end, binMax, skipmap, regionSeq, _yield$sequenceAdapte, _yield$sequenceAdapte2, feat, bins;
2079
+ var _generateCoverageBins = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee6(features, region, opts) {
2080
+ var _opts$colorBy;
2085
2081
 
2086
- return runtime_1.wrap(function _callee5$(_context5) {
2082
+ var colorBy, binMax, skipmap, regionSeq, bins, _loop, i;
2083
+
2084
+ return runtime_1.wrap(function _callee6$(_context6) {
2087
2085
  while (1) {
2088
- switch (_context5.prev = _context5.next) {
2086
+ switch (_context6.prev = _context6.next) {
2089
2087
  case 0:
2090
2088
  colorBy = opts.colorBy;
2091
- _context5.next = 3;
2092
- return this.configure();
2093
-
2094
- case 3:
2095
- _yield$this$configure3 = _context5.sent;
2096
- sequenceAdapter = _yield$this$configure3.sequenceAdapter;
2097
- originalRefName = region.originalRefName, refName = region.refName, start = region.start, end = region.end;
2098
2089
  binMax = Math.ceil(region.end - region.start);
2099
- skipmap = {}; // request an extra +1 on the end to get CpG crossing region boundary
2090
+ skipmap = {};
2100
2091
 
2101
- if (!sequenceAdapter) {
2102
- _context5.next = 15;
2092
+ if (!(features.length && shouldFetchReferenceSequence((_opts$colorBy = opts.colorBy) === null || _opts$colorBy === void 0 ? void 0 : _opts$colorBy.type))) {
2093
+ _context6.next = 9;
2103
2094
  break;
2104
2095
  }
2105
2096
 
2106
- _context5.next = 11;
2107
- return sequenceAdapter.getFeatures({
2108
- refName: originalRefName || refName,
2109
- start: start,
2110
- end: end + 1,
2111
- assemblyName: region.assemblyName
2112
- }).pipe(operators.toArray()).toPromise();
2097
+ _context6.next = 6;
2098
+ return this.fetchSequence(region);
2113
2099
 
2114
- case 11:
2115
- _yield$sequenceAdapte = _context5.sent;
2116
- _yield$sequenceAdapte2 = _slicedToArray(_yield$sequenceAdapte, 1);
2117
- feat = _yield$sequenceAdapte2[0];
2118
- regionSeq = feat === null || feat === void 0 ? void 0 : feat.get('seq');
2100
+ case 6:
2101
+ _context6.t0 = _context6.sent;
2102
+ _context6.next = 10;
2103
+ break;
2119
2104
 
2120
- case 15:
2121
- _context5.next = 17;
2122
- return features.pipe(operators.reduce(function (bins, feature) {
2123
- var cigar = feature.get('CIGAR');
2105
+ case 9:
2106
+ _context6.t0 = undefined;
2107
+
2108
+ case 10:
2109
+ regionSeq = _context6.t0;
2110
+ bins = [];
2111
+
2112
+ _loop = function _loop(i) {
2113
+ var feature = features[i];
2114
+ var ops = parseCigar(feature.get('CIGAR'));
2124
2115
  var fstart = feature.get('start');
2125
2116
  var fend = feature.get('end');
2126
2117
  var fstrand = feature.get('strand');
2127
- var cigarOps = parseCigar(cigar);
2128
2118
 
2129
2119
  for (var j = fstart; j < fend; j++) {
2130
- var i = j - region.start;
2120
+ var _i = j - region.start;
2131
2121
 
2132
- if (i >= 0 && i < binMax) {
2133
- var bin = bins[i] || {
2122
+ if (_i >= 0 && _i < binMax) {
2123
+ var bin = bins[_i] || {
2134
2124
  total: 0,
2135
2125
  lowqual: {},
2136
2126
  cov: {},
@@ -2138,32 +2128,25 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2138
2128
  noncov: {},
2139
2129
  ref: {}
2140
2130
  };
2141
- bin.total++;
2142
- inc(bin, fstrand, 'ref', 'ref');
2143
- bins[i] = bin;
2131
+
2132
+ if (j !== fend) {
2133
+ bin.total++;
2134
+ inc(bin, fstrand, 'ref', 'ref');
2135
+ }
2136
+
2137
+ bins[_i] = bin;
2144
2138
  }
2145
2139
  }
2146
2140
 
2147
2141
  if ((colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'modifications') {
2148
2142
  var seq = feature.get('seq');
2149
2143
  var mm = getTagAlt(feature, 'MM', 'Mm') || '';
2150
- var ml = getTagAlt(feature, 'ML', 'Ml') || [];
2151
- var probabilities = ml ? (typeof ml === 'string' ? ml.split(',').map(function (e) {
2152
- return +e;
2153
- }) : ml).map(function (e) {
2154
- return e / 255;
2155
- }) : getTagAlt(feature, 'MP', 'Mp').split('').map(function (s) {
2156
- return s.charCodeAt(0) - 33;
2157
- }).map(function (elt) {
2158
- return Math.min(1, elt / 50);
2159
- });
2160
- var probIndex = 0;
2161
2144
  getModificationPositions(mm, seq, fstrand).forEach(function (_ref4) {
2162
2145
  var type = _ref4.type,
2163
2146
  positions = _ref4.positions;
2164
2147
  var mod = "mod_".concat(type);
2165
2148
 
2166
- var _iterator = _createForOfIteratorHelper(getNextRefPos(cigarOps, positions)),
2149
+ var _iterator = _createForOfIteratorHelper(getNextRefPos(ops, positions)),
2167
2150
  _step;
2168
2151
 
2169
2152
  try {
@@ -2173,15 +2156,8 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2173
2156
 
2174
2157
  if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
2175
2158
  var _bin = bins[epos];
2176
-
2177
- if (probabilities[probIndex] > 0.5) {
2178
- inc(_bin, fstrand, 'cov', mod);
2179
- } else {
2180
- inc(_bin, fstrand, 'lowqual', mod);
2181
- }
2159
+ inc(_bin, fstrand, 'cov', mod);
2182
2160
  }
2183
-
2184
- probIndex++;
2185
2161
  }
2186
2162
  } catch (err) {
2187
2163
  _iterator.e(err);
@@ -2207,7 +2183,7 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2207
2183
 
2208
2184
  // we are processing methylation
2209
2185
  if (type === 'm') {
2210
- var _iterator2 = _createForOfIteratorHelper(getNextRefPos(cigarOps, positions)),
2186
+ var _iterator2 = _createForOfIteratorHelper(getNextRefPos(ops, positions)),
2211
2187
  _step2;
2212
2188
 
2213
2189
  try {
@@ -2228,19 +2204,18 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2228
2204
  });
2229
2205
 
2230
2206
  for (var _j = fstart; _j < fend; _j++) {
2231
- var _i = _j - region.start;
2207
+ var _i2 = _j - region.start;
2232
2208
 
2233
- if (_i >= 0 && _i < bins.length - 1) {
2234
- var l1 = regionSeq[_i].toLowerCase();
2209
+ if (_i2 >= 0 && _i2 < bins.length - 1) {
2210
+ var l1 = regionSeq[_i2].toLowerCase();
2235
2211
 
2236
- var l2 = regionSeq[_i + 1].toLowerCase();
2212
+ var l2 = regionSeq[_i2 + 1].toLowerCase();
2237
2213
 
2238
- var _bin2 = bins[_i];
2239
- var bin1 = bins[_i + 1]; // color
2214
+ var _bin2 = bins[_i2];
2215
+ var bin1 = bins[_i2 + 1]; // color
2240
2216
 
2241
- // color
2242
2217
  if (l1 === 'c' && l2 === 'g') {
2243
- if (methBins[_i] || methBins[_i + 1]) {
2218
+ if (methBins[_i2] || methBins[_i2 + 1]) {
2244
2219
  inc(_bin2, fstrand, 'cov', 'meth');
2245
2220
  inc(bin1, fstrand, 'cov', 'meth');
2246
2221
  dec(_bin2, fstrand, 'ref', 'ref');
@@ -2259,8 +2234,8 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2259
2234
  var mismatches = feature.get('mismatches');
2260
2235
 
2261
2236
  if (mismatches) {
2262
- for (var _i2 = 0; _i2 < mismatches.length; _i2++) {
2263
- var mismatch = mismatches[_i2];
2237
+ for (var _i3 = 0; _i3 < mismatches.length; _i3++) {
2238
+ var mismatch = mismatches[_i3];
2264
2239
  var mstart = fstart + mismatch.start;
2265
2240
 
2266
2241
  for (var _j2 = mstart; _j2 < mstart + mismatchLen(mismatch); _j2++) {
@@ -2312,26 +2287,26 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2312
2287
  });
2313
2288
  }
2314
2289
  }
2290
+ };
2315
2291
 
2316
- return bins;
2317
- }, [])).toPromise();
2292
+ for (i = 0; i < features.length; i++) {
2293
+ _loop(i);
2294
+ }
2318
2295
 
2319
- case 17:
2320
- bins = _context5.sent;
2321
- return _context5.abrupt("return", {
2296
+ return _context6.abrupt("return", {
2322
2297
  bins: bins,
2323
2298
  skipmap: skipmap
2324
2299
  });
2325
2300
 
2326
- case 19:
2301
+ case 15:
2327
2302
  case "end":
2328
- return _context5.stop();
2303
+ return _context6.stop();
2329
2304
  }
2330
2305
  }
2331
- }, _callee5, this);
2306
+ }, _callee6, this);
2332
2307
  }));
2333
2308
 
2334
- function generateCoverageBins(_x4, _x5, _x6) {
2309
+ function generateCoverageBins(_x5, _x6, _x7) {
2335
2310
  return _generateCoverageBins.apply(this, arguments);
2336
2311
  }
2337
2312
 
@@ -2379,7 +2354,7 @@ var ConfigSchema = /*#__PURE__*/configuration.ConfigurationSchema('SNPCoverageRe
2379
2354
  indicatorThreshold: {
2380
2355
  type: 'number',
2381
2356
  description: 'the proportion of reads containing a insertion/clip indicator',
2382
- defaultValue: 0.3
2357
+ defaultValue: 0.4
2383
2358
  },
2384
2359
  drawArcs: {
2385
2360
  type: 'boolean',
@@ -2420,12 +2395,13 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2420
2395
  regions = props.regions,
2421
2396
  bpPerPx = props.bpPerPx,
2422
2397
  displayCrossHatches = props.displayCrossHatches,
2423
- modificationTagMap = props.modificationTagMap,
2398
+ _props$modificationTa = props.modificationTagMap,
2399
+ modificationTagMap = _props$modificationTa === void 0 ? {} : _props$modificationTa,
2424
2400
  scaleOpts = props.scaleOpts,
2425
2401
  unadjustedHeight = props.height,
2426
2402
  configTheme = props.theme,
2427
2403
  cfg = props.config,
2428
- values = props.ticks.values;
2404
+ ticks = props.ticks;
2429
2405
  var theme = ui.createJBrowseTheme(configTheme);
2430
2406
 
2431
2407
  var _regions = _slicedToArray(regions, 1),
@@ -2437,17 +2413,23 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2437
2413
 
2438
2414
  var offset = pluginWiggle.YSCALEBAR_LABEL_OFFSET;
2439
2415
  var height = unadjustedHeight - offset * 2;
2416
+ var domain = scaleOpts.domain;
2417
+
2418
+ if (!domain) {
2419
+ return;
2420
+ }
2440
2421
 
2441
2422
  var opts = _objectSpread2(_objectSpread2({}, scaleOpts), {}, {
2442
2423
  range: [0, height]
2443
2424
  });
2444
2425
 
2445
- var viewScale = pluginWiggle.getScale(opts);
2446
- var snpViewScale = pluginWiggle.getScale(_objectSpread2(_objectSpread2({}, opts), {}, {
2426
+ var viewScale = pluginWiggle.getScale(opts); // clipping and insertion indicators, uses a smaller height/2 scale
2427
+
2428
+ var indicatorViewScale = pluginWiggle.getScale(_objectSpread2(_objectSpread2({}, opts), {}, {
2429
+ range: [0, height / 2],
2447
2430
  scaleType: 'linear'
2448
2431
  }));
2449
2432
  var originY = pluginWiggle.getOrigin(scaleOpts.scaleType);
2450
- var snpOriginY = pluginWiggle.getOrigin('linear');
2451
2433
  var indicatorThreshold = configuration.readConfObject(cfg, 'indicatorThreshold');
2452
2434
  var drawInterbaseCounts = configuration.readConfObject(cfg, 'drawInterbaseCounts');
2453
2435
  var drawArcs = configuration.readConfObject(cfg, 'drawArcs');
@@ -2459,15 +2441,14 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2459
2441
 
2460
2442
  var toHeight = function toHeight(n) {
2461
2443
  return toY(originY) - toY(n);
2462
- }; // this is always linear scale, even when plotted on top of log scale
2463
-
2444
+ };
2464
2445
 
2465
- var snpToY = function snpToY(n) {
2466
- return height - (snpViewScale(n) || 0) + offset;
2446
+ var indicatorToY = function indicatorToY(n) {
2447
+ return height - (indicatorViewScale(n) || 0) + offset;
2467
2448
  };
2468
2449
 
2469
- var snpToHeight = function snpToHeight(n) {
2470
- return snpToY(snpOriginY) - snpToY(n);
2450
+ var indicatorToHeight = function indicatorToHeight(n) {
2451
+ return indicatorToY(pluginWiggle.getOrigin('linear')) - indicatorToY(n);
2471
2452
  };
2472
2453
 
2473
2454
  var colorForBase = {
@@ -2495,7 +2476,10 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2495
2476
  // bpPerPx First pass: draw the gray background
2496
2477
 
2497
2478
  ctx.fillStyle = colorForBase.total;
2498
- coverage.forEach(function (feature) {
2479
+
2480
+ for (var i = 0; i < coverage.length; i++) {
2481
+ var feature = coverage[i];
2482
+
2499
2483
  var _featureSpanPx = util.featureSpanPx(feature, region, bpPerPx),
2500
2484
  _featureSpanPx2 = _slicedToArray(_featureSpanPx, 2),
2501
2485
  leftPx = _featureSpanPx2[0],
@@ -2504,96 +2488,104 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2504
2488
  var w = rightPx - leftPx + 0.3;
2505
2489
  var score = feature.get('score');
2506
2490
  ctx.fillRect(leftPx, toY(score), w, toHeight(score));
2507
- });
2508
- ctx.fillStyle = 'grey';
2509
- ctx.beginPath();
2510
- ctx.lineTo(0, 0);
2511
- ctx.moveTo(0, width);
2512
- ctx.stroke(); // Second pass: draw the SNP data, and add a minimum feature width of 1px
2491
+ } // Keep track of previous total which we will use it to draw the interbase
2492
+ // indicator (if there is a sudden clip, there will be no read coverage but
2493
+ // there will be "clip" coverage) at that position beyond the read. if the
2494
+ // clip is right at a block boundary then prevTotal will not be available,
2495
+ // so this is a best attempt to plot interbase indicator at the "cliffs"
2496
+
2497
+
2498
+ var prevTotal = 0; // extraHorizontallyFlippedOffset is used to draw interbase items, which
2499
+ // are located to the left when forward and right when reversed
2500
+
2501
+ var extraHorizontallyFlippedOffset = region.reversed ? 1 / bpPerPx : 0; // Second pass: draw the SNP data, and add a minimum feature width of 1px
2513
2502
  // which can be wider than the actual bpPerPx This reduces overdrawing of
2514
2503
  // the grey background over the SNPs
2515
2504
 
2516
- coverage.forEach(function (feature) {
2517
- var _featureSpanPx3 = util.featureSpanPx(feature, region, bpPerPx),
2505
+ for (var _i = 0; _i < coverage.length; _i++) {
2506
+ var _feature = coverage[_i];
2507
+
2508
+ var _featureSpanPx3 = util.featureSpanPx(_feature, region, bpPerPx),
2518
2509
  _featureSpanPx4 = _slicedToArray(_featureSpanPx3, 2),
2519
- leftPx = _featureSpanPx4[0],
2520
- rightPx = _featureSpanPx4[1];
2510
+ _leftPx = _featureSpanPx4[0],
2511
+ _rightPx = _featureSpanPx4[1];
2512
+
2513
+ var _score = _feature.get('score');
2514
+
2515
+ var snpinfo = _feature.get('snpinfo');
2516
+
2517
+ var _w = Math.max(_rightPx - _leftPx + 0.3, 1);
2521
2518
 
2522
- var snpinfo = feature.get('snpinfo');
2523
- var w = Math.max(rightPx - leftPx + 0.3, 1);
2524
2519
  var totalScore = snpinfo.total;
2525
- Object.entries(snpinfo.cov).sort(function (_ref, _ref2) {
2526
- var _ref3 = _slicedToArray(_ref, 1),
2527
- a = _ref3[0];
2520
+ var keys = Object.keys(snpinfo.cov).sort();
2521
+ var curr = 0;
2528
2522
 
2529
- var _ref4 = _slicedToArray(_ref2, 1),
2530
- b = _ref4[0];
2523
+ for (var _i2 = 0; _i2 < keys.length; _i2++) {
2524
+ var base = keys[_i2];
2525
+ var total = snpinfo.cov[base].total;
2526
+ ctx.fillStyle = colorForBase[base] || modificationTagMap[base.replace('mod_', '')] || '#888';
2531
2527
 
2532
- if (a < b) {
2533
- return -1;
2534
- }
2528
+ var _height = toHeight(_score);
2535
2529
 
2536
- if (a > b) {
2537
- return 1;
2538
- }
2530
+ var bottom = toY(_score) + _height;
2539
2531
 
2540
- return 0;
2541
- }).reduce(function (curr, _ref5) {
2542
- var _ref6 = _slicedToArray(_ref5, 2),
2543
- base = _ref6[0],
2544
- total = _ref6[1].total;
2545
-
2546
- ctx.fillStyle = colorForBase[base] || modificationTagMap[base.replace('mod_', '')] || 'red';
2547
- ctx.fillRect(leftPx, snpToY(total + curr), w, snpToHeight(total));
2548
- return curr + total;
2549
- }, 0);
2550
- var interbaseEvents = Object.entries(snpinfo.noncov);
2532
+ ctx.fillRect(_leftPx, bottom - (total + curr) / _score * _height, _w, total / _score * _height);
2533
+ curr += total;
2534
+ }
2535
+
2536
+ var interbaseEvents = Object.keys(snpinfo.noncov);
2551
2537
  var indicatorHeight = 4.5;
2552
2538
 
2553
2539
  if (drawInterbaseCounts) {
2554
- interbaseEvents.reduce(function (curr, _ref7) {
2555
- var _ref8 = _slicedToArray(_ref7, 2),
2556
- base = _ref8[0],
2557
- total = _ref8[1].total;
2558
-
2559
- ctx.fillStyle = colorForBase[base];
2560
- ctx.fillRect(leftPx - 0.6, indicatorHeight + snpToHeight(curr), 1.2, snpToHeight(total));
2561
- return curr + total;
2562
- }, 0);
2540
+ var _curr = 0;
2541
+
2542
+ for (var _i3 = 0; _i3 < interbaseEvents.length; _i3++) {
2543
+ var _base = interbaseEvents[_i3];
2544
+ var _total = snpinfo.noncov[_base].total;
2545
+ ctx.fillStyle = colorForBase[_base];
2546
+ ctx.fillRect(_leftPx - 0.6 + extraHorizontallyFlippedOffset, indicatorHeight + indicatorToHeight(_curr), 1.2, indicatorToHeight(_total));
2547
+ _curr += _total;
2548
+ }
2563
2549
  }
2564
2550
 
2565
2551
  if (drawIndicators) {
2566
2552
  var accum = 0;
2567
2553
  var max = 0;
2568
2554
  var maxBase = '';
2569
- interbaseEvents.forEach(function (_ref9) {
2570
- var _ref10 = _slicedToArray(_ref9, 2),
2571
- base = _ref10[0],
2572
- total = _ref10[1].total;
2573
2555
 
2574
- accum += total;
2556
+ for (var _i4 = 0; _i4 < interbaseEvents.length; _i4++) {
2557
+ var _base2 = interbaseEvents[_i4];
2558
+ var _total2 = snpinfo.noncov[_base2].total;
2559
+ accum += _total2;
2575
2560
 
2576
- if (total > max) {
2577
- max = total;
2578
- maxBase = base;
2561
+ if (_total2 > max) {
2562
+ max = _total2;
2563
+ maxBase = _base2;
2579
2564
  }
2580
- }); // avoid drawing a bunch of indicators if coverage is very low e.g.
2581
- // less than 7
2565
+ } // avoid drawing a bunch of indicators if coverage is very low e.g.
2566
+ // less than 7, uses the prev total in the case of the "cliff"
2567
+
2582
2568
 
2583
- if (accum > totalScore * indicatorThreshold && totalScore > 7) {
2569
+ var indicatorComparatorScore = Math.max(totalScore, prevTotal);
2570
+
2571
+ if (accum > indicatorComparatorScore * indicatorThreshold && indicatorComparatorScore > 7) {
2584
2572
  ctx.fillStyle = colorForBase[maxBase];
2585
2573
  ctx.beginPath();
2586
- ctx.moveTo(leftPx - 3, 0);
2587
- ctx.lineTo(leftPx + 3, 0);
2588
- ctx.lineTo(leftPx, indicatorHeight);
2574
+ var l = _leftPx + extraHorizontallyFlippedOffset;
2575
+ ctx.moveTo(l - 3.5, 0);
2576
+ ctx.lineTo(l + 3.5, 0);
2577
+ ctx.lineTo(l, indicatorHeight);
2589
2578
  ctx.fill();
2590
2579
  }
2591
2580
  }
2592
- });
2593
- ctx.globalAlpha = 0.7;
2581
+
2582
+ prevTotal = totalScore;
2583
+ }
2594
2584
 
2595
2585
  if (drawArcs) {
2596
- skips.forEach(function (f) {
2586
+ for (var _i5 = 0; _i5 < skips.length; _i5++) {
2587
+ var f = skips[_i5];
2588
+
2597
2589
  var _bpSpanPx = util.bpSpanPx(f.get('start'), f.get('end'), region, bpPerPx),
2598
2590
  _bpSpanPx2 = _slicedToArray(_bpSpanPx, 2),
2599
2591
  left = _bpSpanPx2[0],
@@ -2602,9 +2594,9 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2602
2594
  ctx.beginPath();
2603
2595
  var str = f.get('strand');
2604
2596
  var xs = f.get('xs');
2605
- var pos = 'rgb(255,200,200)';
2606
- var neg = 'rgb(200,200,255)';
2607
- var neutral = 'rgb(200,200,200)';
2597
+ var pos = 'rgba(255,200,200,0.7)';
2598
+ var neg = 'rgba(200,200,255,0.7)';
2599
+ var neutral = 'rgba(200,200,200,0.7)';
2608
2600
 
2609
2601
  if (xs === '+') {
2610
2602
  ctx.strokeStyle = pos;
@@ -2622,13 +2614,13 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2622
2614
  ctx.moveTo(left, height - offset * 2);
2623
2615
  ctx.bezierCurveTo(left, 0, right, 0, right, height - offset * 2);
2624
2616
  ctx.stroke();
2625
- });
2617
+ }
2626
2618
  }
2627
2619
 
2628
2620
  if (displayCrossHatches) {
2629
2621
  ctx.lineWidth = 1;
2630
2622
  ctx.strokeStyle = 'rgba(140,140,140,0.8)';
2631
- values.forEach(function (tick) {
2623
+ ticks.values.forEach(function (tick) {
2632
2624
  ctx.beginPath();
2633
2625
  ctx.moveTo(0, Math.round(toY(tick)));
2634
2626
  ctx.lineTo(width, Math.round(toY(tick)));
@@ -2811,6 +2803,16 @@ function getColorBaseMap(theme) {
2811
2803
  };
2812
2804
  }
2813
2805
 
2806
+ function getContrastBaseMap(theme) {
2807
+ return Object.fromEntries(Object.entries(getColorBaseMap(theme)).map(function (_ref) {
2808
+ var _ref2 = _slicedToArray(_ref, 2),
2809
+ key = _ref2[0],
2810
+ value = _ref2[1];
2811
+
2812
+ return [key, theme.palette.getContrastText(value)];
2813
+ }));
2814
+ }
2815
+
2814
2816
  var alignmentColoring = {
2815
2817
  color_fwd_strand_not_proper: '#ECC8C8',
2816
2818
  color_rev_strand_not_proper: '#BEBED8',
@@ -2863,14 +2865,14 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
2863
2865
  }
2864
2866
  }, {
2865
2867
  key: "layoutFeature",
2866
- value: function layoutFeature(_ref) {
2867
- var feature = _ref.feature,
2868
- layout = _ref.layout,
2869
- bpPerPx = _ref.bpPerPx,
2870
- region = _ref.region,
2871
- showSoftClip = _ref.showSoftClip,
2872
- heightPx = _ref.heightPx,
2873
- displayMode = _ref.displayMode;
2868
+ value: function layoutFeature(_ref3) {
2869
+ var feature = _ref3.feature,
2870
+ layout = _ref3.layout,
2871
+ bpPerPx = _ref3.bpPerPx,
2872
+ region = _ref3.region,
2873
+ showSoftClip = _ref3.showSoftClip,
2874
+ heightPx = _ref3.heightPx,
2875
+ displayMode = _ref3.displayMode;
2874
2876
  var expansionBefore = 0;
2875
2877
  var expansionAfter = 0; // Expand the start and end of feature when softclipping enabled
2876
2878
 
@@ -2990,6 +2992,56 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
2990
2992
 
2991
2993
  return strand === 1 ? 'color_fwd_strand' : 'color_rev_strand';
2992
2994
  }
2995
+ }, {
2996
+ key: "colorByPerBaseLettering",
2997
+ value: function colorByPerBaseLettering(ctx, feat, _config, region, bpPerPx, props) {
2998
+ var colorForBase = props.colorForBase,
2999
+ contrastForBase = props.contrastForBase,
3000
+ charWidth = props.charWidth,
3001
+ charHeight = props.charHeight;
3002
+ var heightLim = charHeight - 2;
3003
+ var feature = feat.feature,
3004
+ topPx = feat.topPx,
3005
+ heightPx = feat.heightPx;
3006
+ var seq = feature.get('seq');
3007
+ var cigarOps = parseCigar(feature.get('CIGAR'));
3008
+ var widthPx = 1 / bpPerPx;
3009
+ var start = feature.get('start');
3010
+ var soffset = 0; // sequence offset
3011
+
3012
+ var roffset = 0; // reference offset
3013
+
3014
+ for (var i = 0; i < cigarOps.length; i += 2) {
3015
+ var len = +cigarOps[i];
3016
+ var op = cigarOps[i + 1];
3017
+
3018
+ if (op === 'S' || op === 'I') {
3019
+ soffset += len;
3020
+ } else if (op === 'D' || op === 'N') {
3021
+ roffset += len;
3022
+ } else if (op === 'M' || op === 'X' || op === '=') {
3023
+ for (var m = 0; m < len; m++) {
3024
+ var letter = seq[soffset + m];
3025
+ ctx.fillStyle = colorForBase[letter];
3026
+
3027
+ var _bpSpanPx3 = util.bpSpanPx(start + roffset + m, start + roffset + m + 1, region, bpPerPx),
3028
+ _bpSpanPx4 = _slicedToArray(_bpSpanPx3, 1),
3029
+ leftPx = _bpSpanPx4[0];
3030
+
3031
+ ctx.fillRect(leftPx, topPx, widthPx + 0.5, heightPx);
3032
+
3033
+ if (widthPx >= charWidth && heightPx >= heightLim) {
3034
+ // normal SNP coloring
3035
+ ctx.fillStyle = contrastForBase[letter];
3036
+ ctx.fillText(letter, leftPx + (widthPx - charWidth) / 2 + 1, topPx + heightPx);
3037
+ }
3038
+ }
3039
+
3040
+ soffset += len;
3041
+ roffset += len;
3042
+ }
3043
+ }
3044
+ }
2993
3045
  }, {
2994
3046
  key: "colorByPerBaseQuality",
2995
3047
  value: function colorByPerBaseQuality(ctx, feat, _config, region, bpPerPx) {
@@ -3003,28 +3055,32 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3003
3055
  var cigarOps = parseCigar(feature.get('CIGAR'));
3004
3056
  var width = 1 / bpPerPx;
3005
3057
  var start = feature.get('start');
3058
+ var soffset = 0; // sequence offset
3059
+
3060
+ var roffset = 0; // reference offset
3006
3061
 
3007
- for (var i = 0, j = 0, k = 0; k < scores.length; i += 2, k++) {
3062
+ for (var i = 0; i < cigarOps.length; i += 2) {
3008
3063
  var len = +cigarOps[i];
3009
3064
  var op = cigarOps[i + 1];
3010
3065
 
3011
3066
  if (op === 'S' || op === 'I') {
3012
- k += len;
3067
+ soffset += len;
3013
3068
  } else if (op === 'D' || op === 'N') {
3014
- j += len;
3069
+ roffset += len;
3015
3070
  } else if (op === 'M' || op === 'X' || op === '=') {
3016
3071
  for (var m = 0; m < len; m++) {
3017
- var score = scores[k + m];
3072
+ var score = scores[soffset + m];
3018
3073
  ctx.fillStyle = "hsl(".concat(score === 255 ? 150 : score * 1.5, ",55%,50%)");
3019
3074
 
3020
- var _bpSpanPx3 = util.bpSpanPx(start + j + m, start + j + m + 1, region, bpPerPx),
3021
- _bpSpanPx4 = _slicedToArray(_bpSpanPx3, 1),
3022
- leftPx = _bpSpanPx4[0];
3075
+ var _bpSpanPx5 = util.bpSpanPx(start + roffset + m, start + roffset + m + 1, region, bpPerPx),
3076
+ _bpSpanPx6 = _slicedToArray(_bpSpanPx5, 1),
3077
+ leftPx = _bpSpanPx6[0];
3023
3078
 
3024
3079
  ctx.fillRect(leftPx, topPx, width + 0.5, heightPx);
3025
3080
  }
3026
3081
 
3027
- j += len;
3082
+ soffset += len;
3083
+ roffset += len;
3028
3084
  }
3029
3085
  }
3030
3086
  } // ML stores probabilities as array of numerics and MP is scaled phred scores
@@ -3065,9 +3121,11 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3065
3121
  var modifications = getModificationPositions(mm, seq, strand); // probIndex applies across multiple modifications e.g.
3066
3122
 
3067
3123
  var probIndex = 0;
3068
- modifications.forEach(function (_ref2) {
3069
- var type = _ref2.type,
3070
- positions = _ref2.positions;
3124
+
3125
+ for (var i = 0; i < modifications.length; i++) {
3126
+ var _modifications$i = modifications[i],
3127
+ type = _modifications$i.type,
3128
+ positions = _modifications$i.positions;
3071
3129
  var col = modificationTagMap[type] || 'black';
3072
3130
  var base = Color(col);
3073
3131
 
@@ -3079,10 +3137,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3079
3137
  var readPos = _step.value;
3080
3138
 
3081
3139
  if (readPos >= 0 && start + readPos < end) {
3082
- var _bpSpanPx5 = util.bpSpanPx(start + readPos, start + readPos + 1, region, bpPerPx),
3083
- _bpSpanPx6 = _slicedToArray(_bpSpanPx5, 2),
3084
- leftPx = _bpSpanPx6[0],
3085
- rightPx = _bpSpanPx6[1]; // give it a little boost of 0.1 to not make them fully
3140
+ var _bpSpanPx7 = util.bpSpanPx(start + readPos, start + readPos + 1, region, bpPerPx),
3141
+ _bpSpanPx8 = _slicedToArray(_bpSpanPx7, 2),
3142
+ leftPx = _bpSpanPx8[0],
3143
+ rightPx = _bpSpanPx8[1]; // give it a little boost of 0.1 to not make them fully
3086
3144
  // invisible to avoid confusion
3087
3145
 
3088
3146
 
@@ -3097,10 +3155,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3097
3155
  } finally {
3098
3156
  _iterator.f();
3099
3157
  }
3100
- });
3158
+ }
3101
3159
  } // Color by methylation is slightly modified version of color by
3102
- // modifications
3103
- //
3160
+ // modifications that focuses on CpG sites, with non-methylated CpG colored
3161
+ // blue
3104
3162
 
3105
3163
  }, {
3106
3164
  key: "colorByMethylation",
@@ -3124,9 +3182,12 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3124
3182
  var rstart = region.start,
3125
3183
  rend = region.end;
3126
3184
  var methBins = new Array(rend - rstart).fill(0);
3127
- getModificationPositions(mm, seq, strand).forEach(function (_ref3) {
3128
- var type = _ref3.type,
3129
- positions = _ref3.positions;
3185
+ var modifications = getModificationPositions(mm, seq, strand);
3186
+
3187
+ for (var i = 0; i < modifications.length; i++) {
3188
+ var _modifications$i2 = modifications[i],
3189
+ type = _modifications$i2.type,
3190
+ positions = _modifications$i2.positions;
3130
3191
 
3131
3192
  if (type === 'm' && positions) {
3132
3193
  var _iterator2 = _createForOfIteratorHelper(getNextRefPos(cigarOps, positions)),
@@ -3147,25 +3208,27 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3147
3208
  _iterator2.f();
3148
3209
  }
3149
3210
  }
3150
- });
3211
+ }
3151
3212
 
3152
3213
  for (var j = fstart; j < fend; j++) {
3153
- var i = j - rstart;
3214
+ var _i = j - rstart;
3215
+
3216
+ if (_i >= 0 && _i < methBins.length) {
3217
+ var l1 = regionSequence[_i].toLowerCase();
3218
+
3219
+ var l2 = regionSequence[_i + 1].toLowerCase(); // if we are zoomed out, display just a block over the cpg
3154
3220
 
3155
- if (i >= 0 && i < methBins.length) {
3156
- var l1 = regionSequence[i].toLowerCase();
3157
- var l2 = regionSequence[i + 1].toLowerCase(); // if we are zoomed out, display just a block over the cpg
3158
3221
 
3159
3222
  if (bpPerPx > 2) {
3160
3223
  if (l1 === 'c' && l2 === 'g') {
3161
- var s = rstart + i;
3224
+ var s = rstart + _i;
3162
3225
 
3163
- var _bpSpanPx7 = util.bpSpanPx(s, s + 2, region, bpPerPx),
3164
- _bpSpanPx8 = _slicedToArray(_bpSpanPx7, 2),
3165
- leftPx = _bpSpanPx8[0],
3166
- rightPx = _bpSpanPx8[1];
3226
+ var _bpSpanPx9 = util.bpSpanPx(s, s + 2, region, bpPerPx),
3227
+ _bpSpanPx10 = _slicedToArray(_bpSpanPx9, 2),
3228
+ leftPx = _bpSpanPx10[0],
3229
+ rightPx = _bpSpanPx10[1];
3167
3230
 
3168
- if (methBins[i] || methBins[i + 1]) {
3231
+ if (methBins[_i] || methBins[_i + 1]) {
3169
3232
  ctx.fillStyle = 'red';
3170
3233
  } else {
3171
3234
  ctx.fillStyle = 'blue';
@@ -3177,14 +3240,14 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3177
3240
  else {
3178
3241
  // color
3179
3242
  if (l1 === 'c' && l2 === 'g') {
3180
- var _s = rstart + i;
3243
+ var _s = rstart + _i;
3181
3244
 
3182
- var _bpSpanPx9 = util.bpSpanPx(_s, _s + 1, region, bpPerPx),
3183
- _bpSpanPx10 = _slicedToArray(_bpSpanPx9, 2),
3184
- _leftPx = _bpSpanPx10[0],
3185
- _rightPx = _bpSpanPx10[1];
3245
+ var _bpSpanPx11 = util.bpSpanPx(_s, _s + 1, region, bpPerPx),
3246
+ _bpSpanPx12 = _slicedToArray(_bpSpanPx11, 2),
3247
+ _leftPx = _bpSpanPx12[0],
3248
+ _rightPx = _bpSpanPx12[1];
3186
3249
 
3187
- if (methBins[i]) {
3250
+ if (methBins[_i]) {
3188
3251
  ctx.fillStyle = 'red';
3189
3252
  } else {
3190
3253
  ctx.fillStyle = 'blue';
@@ -3192,12 +3255,12 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3192
3255
 
3193
3256
  ctx.fillRect(_leftPx, topPx, _rightPx - _leftPx + 0.5, heightPx);
3194
3257
 
3195
- var _bpSpanPx11 = util.bpSpanPx(_s + 1, _s + 2, region, bpPerPx),
3196
- _bpSpanPx12 = _slicedToArray(_bpSpanPx11, 2),
3197
- leftPx2 = _bpSpanPx12[0],
3198
- rightPx2 = _bpSpanPx12[1];
3258
+ var _bpSpanPx13 = util.bpSpanPx(_s + 1, _s + 2, region, bpPerPx),
3259
+ _bpSpanPx14 = _slicedToArray(_bpSpanPx13, 2),
3260
+ leftPx2 = _bpSpanPx14[0],
3261
+ rightPx2 = _bpSpanPx14[1];
3199
3262
 
3200
- if (methBins[i + 1]) {
3263
+ if (methBins[_i + 1]) {
3201
3264
  ctx.fillStyle = 'red';
3202
3265
  } else {
3203
3266
  ctx.fillStyle = 'blue';
@@ -3221,10 +3284,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3221
3284
  var _regions = _slicedToArray(regions, 1),
3222
3285
  region = _regions[0];
3223
3286
 
3224
- var _bpSpanPx13 = util.bpSpanPx(feature.get('start'), feature.get('end'), region, bpPerPx),
3225
- _bpSpanPx14 = _slicedToArray(_bpSpanPx13, 2),
3226
- leftPx = _bpSpanPx14[0],
3227
- rightPx = _bpSpanPx14[1];
3287
+ var _bpSpanPx15 = util.bpSpanPx(feature.get('start'), feature.get('end'), region, bpPerPx),
3288
+ _bpSpanPx16 = _slicedToArray(_bpSpanPx15, 2),
3289
+ leftPx = _bpSpanPx16[0],
3290
+ rightPx = _bpSpanPx16[1];
3228
3291
 
3229
3292
  var flip = region.reversed ? -1 : 1;
3230
3293
  var strand = feature.get('strand') * flip;
@@ -3262,7 +3325,11 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3262
3325
  regions = props.regions,
3263
3326
  colorBy = props.colorBy,
3264
3327
  _props$colorTagMap = props.colorTagMap,
3265
- colorTagMap = _props$colorTagMap === void 0 ? {} : _props$colorTagMap;
3328
+ colorTagMap = _props$colorTagMap === void 0 ? {} : _props$colorTagMap,
3329
+ colorForBase = props.colorForBase,
3330
+ contrastForBase = props.contrastForBase,
3331
+ charWidth = props.charWidth,
3332
+ charHeight = props.charHeight;
3266
3333
 
3267
3334
  var _ref4 = colorBy || {},
3268
3335
  _ref4$tag = _ref4.tag,
@@ -3329,6 +3396,21 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3329
3396
  case 'insertSizeAndPairOrientation':
3330
3397
  break;
3331
3398
 
3399
+ case 'modifications':
3400
+ case 'methylation':
3401
+ // this coloring is similar to igv.js, and is helpful to color negative
3402
+ // strand reads differently because their c-g will be flipped (e.g. g-c
3403
+ // read right to left)
3404
+ var flags = feature.get('flags');
3405
+
3406
+ if (flags & 16) {
3407
+ ctx.fillStyle = '#c8dcc8';
3408
+ } else {
3409
+ ctx.fillStyle = '#c8c8c8';
3410
+ }
3411
+
3412
+ break;
3413
+
3332
3414
  case 'normal':
3333
3415
  default:
3334
3416
  if (defaultColor) {
@@ -3351,6 +3433,15 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3351
3433
  this.colorByPerBaseQuality(ctx, feat, config, region, bpPerPx);
3352
3434
  break;
3353
3435
 
3436
+ case 'perBaseLettering':
3437
+ this.colorByPerBaseLettering(ctx, feat, config, region, bpPerPx, {
3438
+ colorForBase: colorForBase,
3439
+ contrastForBase: contrastForBase,
3440
+ charWidth: charWidth,
3441
+ charHeight: charHeight
3442
+ });
3443
+ break;
3444
+
3354
3445
  case 'modifications':
3355
3446
  this.colorByModifications(ctx, feat, config, region, bpPerPx, props);
3356
3447
  break;
@@ -3362,8 +3453,8 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3362
3453
  }
3363
3454
  }, {
3364
3455
  key: "drawMismatches",
3365
- value: function drawMismatches(ctx, feat, props, theme, colorForBase, opts) {
3366
- var minWidth = opts.minSubfeatureWidth,
3456
+ value: function drawMismatches(ctx, feat, props, opts) {
3457
+ var minSubfeatureWidth = opts.minSubfeatureWidth,
3367
3458
  largeInsertionIndicatorScale = opts.largeInsertionIndicatorScale,
3368
3459
  mismatchAlpha = opts.mismatchAlpha,
3369
3460
  _opts$drawSNPs = opts.drawSNPs,
@@ -3371,7 +3462,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3371
3462
  _opts$drawIndels = opts.drawIndels,
3372
3463
  drawIndels = _opts$drawIndels === void 0 ? true : _opts$drawIndels,
3373
3464
  charWidth = opts.charWidth,
3374
- charHeight = opts.charHeight;
3465
+ charHeight = opts.charHeight,
3466
+ colorForBase = opts.colorForBase,
3467
+ contrastForBase = opts.contrastForBase;
3375
3468
  var bpPerPx = props.bpPerPx,
3376
3469
  regions = props.regions;
3377
3470
  var heightPx = feat.heightPx,
@@ -3383,7 +3476,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3383
3476
 
3384
3477
  var start = feature.get('start');
3385
3478
  var pxPerBp = Math.min(1 / bpPerPx, 2);
3386
- var w = Math.max(minWidth, pxPerBp);
3479
+ var w = Math.max(minSubfeatureWidth, pxPerBp);
3387
3480
  var mismatches = feature.get('mismatches');
3388
3481
  var heightLim = charHeight - 2;
3389
3482
 
@@ -3395,22 +3488,25 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3395
3488
  }
3396
3489
 
3397
3490
  return color;
3398
- } // two pass rendering: first pass, draw all the mismatches except wide
3399
- // insertion markers
3491
+ } // extraHorizontallyFlippedOffset is used to draw interbase items, which
3492
+ // are located to the left when forward and right when reversed
3400
3493
 
3401
3494
 
3495
+ var extraHorizontallyFlippedOffset = region.reversed ? 1 / bpPerPx + 1 : -1; // two pass rendering: first pass, draw all the mismatches except wide
3496
+ // insertion markers
3497
+
3402
3498
  for (var i = 0; i < mismatches.length; i += 1) {
3403
3499
  var mismatch = mismatches[i];
3404
3500
  var mstart = start + mismatch.start;
3405
3501
  var mlen = mismatch.length;
3406
3502
  var mbase = mismatch.base;
3407
3503
 
3408
- var _bpSpanPx15 = util.bpSpanPx(mstart, mstart + mlen, region, bpPerPx),
3409
- _bpSpanPx16 = _slicedToArray(_bpSpanPx15, 2),
3410
- leftPx = _bpSpanPx16[0],
3411
- rightPx = _bpSpanPx16[1];
3504
+ var _bpSpanPx17 = util.bpSpanPx(mstart, mstart + mlen, region, bpPerPx),
3505
+ _bpSpanPx18 = _slicedToArray(_bpSpanPx17, 2),
3506
+ leftPx = _bpSpanPx18[0],
3507
+ rightPx = _bpSpanPx18[1];
3412
3508
 
3413
- var widthPx = Math.max(minWidth, Math.abs(leftPx - rightPx));
3509
+ var widthPx = Math.max(minSubfeatureWidth, Math.abs(leftPx - rightPx));
3414
3510
 
3415
3511
  if (mismatch.type === 'mismatch' && drawSNPs) {
3416
3512
  var baseColor = colorForBase[mismatch.base] || '#888';
@@ -3419,7 +3515,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3419
3515
 
3420
3516
  if (widthPx >= charWidth && heightPx >= heightLim) {
3421
3517
  // normal SNP coloring
3422
- ctx.fillStyle = getAlphaColor(theme.palette.getContrastText(baseColor), mismatch);
3518
+ ctx.fillStyle = getAlphaColor(contrastForBase[mismatch.base], mismatch);
3423
3519
  ctx.fillText(mbase, leftPx + (widthPx - charWidth) / 2 + 1, topPx + heightPx);
3424
3520
  }
3425
3521
  } else if (mismatch.type === 'deletion' && drawIndels) {
@@ -3427,40 +3523,38 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3427
3523
  ctx.fillStyle = _baseColor;
3428
3524
  ctx.fillRect(leftPx, topPx, widthPx, heightPx);
3429
3525
  var txt = "".concat(mismatch.length);
3430
- var rect = ctx.measureText(txt);
3526
+ var rwidth = util.measureText(txt, 10);
3431
3527
 
3432
- if (widthPx >= rect.width && heightPx >= heightLim) {
3433
- ctx.fillStyle = theme.palette.getContrastText(_baseColor);
3434
- ctx.fillText(txt, leftPx + (rightPx - leftPx) / 2 - rect.width / 2, topPx + heightPx);
3528
+ if (widthPx >= rwidth && heightPx >= heightLim) {
3529
+ ctx.fillStyle = contrastForBase.deletion;
3530
+ ctx.fillText(txt, (leftPx + rightPx) / 2 - rwidth / 2, topPx + heightPx);
3435
3531
  }
3436
3532
  } else if (mismatch.type === 'insertion' && drawIndels) {
3437
3533
  ctx.fillStyle = 'purple';
3438
- var pos = leftPx - 1;
3534
+ var pos = leftPx + extraHorizontallyFlippedOffset;
3439
3535
  var len = +mismatch.base || mismatch.length;
3536
+ var insW = Math.max(minSubfeatureWidth, Math.min(1.2, 1 / bpPerPx));
3440
3537
 
3441
3538
  if (len < 10) {
3442
- ctx.fillRect(pos, topPx, w, heightPx);
3443
-
3444
- if (1 / bpPerPx >= charWidth) {
3445
- ctx.fillRect(pos - w, topPx, w * 3, 1);
3446
- ctx.fillRect(pos - w, topPx + heightPx - 1, w * 3, 1);
3447
- }
3539
+ ctx.fillRect(pos, topPx, insW, heightPx);
3448
3540
 
3449
3541
  if (1 / bpPerPx >= charWidth && heightPx >= heightLim) {
3450
- ctx.fillText("(".concat(mismatch.base, ")"), leftPx + 2, topPx + heightPx);
3542
+ ctx.fillRect(pos - insW, topPx, insW * 3, 1);
3543
+ ctx.fillRect(pos - insW, topPx + heightPx - 1, insW * 3, 1);
3544
+ ctx.fillText("(".concat(mismatch.base, ")"), pos + 3, topPx + heightPx);
3451
3545
  }
3452
3546
  }
3453
3547
  } else if (mismatch.type === 'hardclip' || mismatch.type === 'softclip') {
3454
3548
  ctx.fillStyle = mismatch.type === 'hardclip' ? 'red' : 'blue';
3455
3549
 
3456
- var _pos = leftPx - 1;
3550
+ var _pos = leftPx + extraHorizontallyFlippedOffset;
3457
3551
 
3458
- ctx.fillRect(_pos, topPx + 1, w, heightPx - 2);
3459
- ctx.fillRect(_pos - w, topPx, w * 3, 1);
3460
- ctx.fillRect(_pos - w, topPx + heightPx - 1, w * 3, 1);
3552
+ ctx.fillRect(_pos, topPx, w, heightPx);
3461
3553
 
3462
- if (widthPx >= charWidth && heightPx >= heightLim) {
3463
- ctx.fillText("(".concat(mismatch.base, ")"), leftPx + 2, topPx + heightPx);
3554
+ if (1 / bpPerPx >= charWidth && heightPx >= heightLim) {
3555
+ ctx.fillRect(_pos - w, topPx, w * 3, 1);
3556
+ ctx.fillRect(_pos - w, topPx + heightPx - 1, w * 3, 1);
3557
+ ctx.fillText("(".concat(mismatch.base, ")"), _pos + 3, topPx + heightPx);
3464
3558
  }
3465
3559
  } else if (mismatch.type === 'skip') {
3466
3560
  // fix to avoid bad rendering note that this was also related to chrome
@@ -3478,16 +3572,16 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3478
3572
 
3479
3573
 
3480
3574
  if (drawIndels) {
3481
- for (var _i = 0; _i < mismatches.length; _i += 1) {
3482
- var _mismatch = mismatches[_i];
3575
+ for (var _i2 = 0; _i2 < mismatches.length; _i2 += 1) {
3576
+ var _mismatch = mismatches[_i2];
3483
3577
 
3484
3578
  var _mstart = start + _mismatch.start;
3485
3579
 
3486
3580
  var _mlen = _mismatch.length;
3487
3581
 
3488
- var _bpSpanPx17 = util.bpSpanPx(_mstart, _mstart + _mlen, region, bpPerPx),
3489
- _bpSpanPx18 = _slicedToArray(_bpSpanPx17, 1),
3490
- _leftPx2 = _bpSpanPx18[0];
3582
+ var _bpSpanPx19 = util.bpSpanPx(_mstart, _mstart + _mlen, region, bpPerPx),
3583
+ _bpSpanPx20 = _slicedToArray(_bpSpanPx19, 1),
3584
+ _leftPx2 = _bpSpanPx20[0];
3491
3585
 
3492
3586
  var _len = +_mismatch.base || _mismatch.length;
3493
3587
 
@@ -3498,13 +3592,12 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3498
3592
  ctx.fillStyle = 'purple';
3499
3593
  ctx.fillRect(_leftPx2 - 1, topPx, 2, heightPx);
3500
3594
  } else if (heightPx > charHeight) {
3501
- var _rect = ctx.measureText(_txt);
3502
-
3595
+ var rect = ctx.measureText(_txt);
3503
3596
  var padding = 5;
3504
3597
  ctx.fillStyle = 'purple';
3505
- ctx.fillRect(_leftPx2 - _rect.width / 2 - padding, topPx, _rect.width + 2 * padding, heightPx);
3598
+ ctx.fillRect(_leftPx2 - rect.width / 2 - padding, topPx, rect.width + 2 * padding, heightPx);
3506
3599
  ctx.fillStyle = 'white';
3507
- ctx.fillText(_txt, _leftPx2 - _rect.width / 2, topPx + heightPx);
3600
+ ctx.fillText(_txt, _leftPx2 - rect.width / 2, topPx + heightPx);
3508
3601
  } else {
3509
3602
  var _padding = 2;
3510
3603
  ctx.fillStyle = 'purple';
@@ -3547,7 +3640,8 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3547
3640
  return mismatch.type === 'softclip';
3548
3641
  }).forEach(function (mismatch) {
3549
3642
  var softClipLength = mismatch.cliplen || 0;
3550
- var softClipStart = mismatch.start === 0 ? feature.get('start') - softClipLength : feature.get('start') + mismatch.start;
3643
+ var s = feature.get('start');
3644
+ var softClipStart = mismatch.start === 0 ? s - softClipLength : s + mismatch.start;
3551
3645
 
3552
3646
  for (var k = 0; k < softClipLength; k += 1) {
3553
3647
  var base = seq.charAt(k + mismatch.start); // If softclip length+start is longer than sequence, no need to
@@ -3557,10 +3651,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3557
3651
  return;
3558
3652
  }
3559
3653
 
3560
- var _bpSpanPx19 = util.bpSpanPx(softClipStart + k, softClipStart + k + 1, region, bpPerPx),
3561
- _bpSpanPx20 = _slicedToArray(_bpSpanPx19, 2),
3562
- softClipLeftPx = _bpSpanPx20[0],
3563
- softClipRightPx = _bpSpanPx20[1];
3654
+ var _bpSpanPx21 = util.bpSpanPx(softClipStart + k, softClipStart + k + 1, region, bpPerPx),
3655
+ _bpSpanPx22 = _slicedToArray(_bpSpanPx21, 2),
3656
+ softClipLeftPx = _bpSpanPx22[0],
3657
+ softClipRightPx = _bpSpanPx22[1];
3564
3658
 
3565
3659
  var softClipWidthPx = Math.max(minFeatWidth, Math.abs(softClipLeftPx - softClipRightPx)); // Black accounts for IUPAC ambiguity code bases such as N that
3566
3660
  // show in soft clipping
@@ -3583,7 +3677,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3583
3677
  var _makeImageData = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(ctx, layoutRecords, props) {
3584
3678
  var _this2 = this;
3585
3679
 
3586
- var layout, config, showSoftClip, colorBy, configTheme, mismatchAlpha, minSubfeatureWidth, insertScale, defaultColor, theme, colorForBase, _this$getCharWidthHei2, charWidth, charHeight;
3680
+ var layout, config, showSoftClip, colorBy, configTheme, mismatchAlpha, minSubfeatureWidth, insertScale, defaultColor, theme, colorForBase, contrastForBase, _this$getCharWidthHei2, charWidth, charHeight;
3587
3681
 
3588
3682
  return runtime_1.wrap(function _callee$(_context) {
3589
3683
  while (1) {
@@ -3596,23 +3690,24 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3596
3690
  defaultColor = configuration.readConfObject(config, 'color') === '#f0f';
3597
3691
  theme = ui.createJBrowseTheme(configTheme);
3598
3692
  colorForBase = getColorBaseMap(theme);
3693
+ contrastForBase = getContrastBaseMap(theme);
3599
3694
 
3600
3695
  if (layout) {
3601
- _context.next = 9;
3696
+ _context.next = 10;
3602
3697
  break;
3603
3698
  }
3604
3699
 
3605
3700
  throw new Error("layout required");
3606
3701
 
3607
- case 9:
3702
+ case 10:
3608
3703
  if (layout.addRect) {
3609
- _context.next = 11;
3704
+ _context.next = 12;
3610
3705
  break;
3611
3706
  }
3612
3707
 
3613
3708
  throw new Error('invalid layout object');
3614
3709
 
3615
- case 11:
3710
+ case 12:
3616
3711
  ctx.font = 'bold 10px Courier New,monospace';
3617
3712
  _this$getCharWidthHei2 = this.getCharWidthHeight(ctx), charWidth = _this$getCharWidthHei2.charWidth, charHeight = _this$getCharWidthHei2.charHeight;
3618
3713
  layoutRecords.forEach(function (feat) {
@@ -3621,17 +3716,23 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3621
3716
  }
3622
3717
 
3623
3718
  _this2.drawAlignmentRect(ctx, feat, _objectSpread2(_objectSpread2({}, props), {}, {
3624
- defaultColor: defaultColor
3719
+ defaultColor: defaultColor,
3720
+ colorForBase: colorForBase,
3721
+ contrastForBase: contrastForBase,
3722
+ charWidth: charWidth,
3723
+ charHeight: charHeight
3625
3724
  }));
3626
3725
 
3627
- _this2.drawMismatches(ctx, feat, props, theme, colorForBase, {
3726
+ _this2.drawMismatches(ctx, feat, props, {
3628
3727
  mismatchAlpha: mismatchAlpha,
3629
3728
  drawSNPs: shouldDrawMismatches(colorBy === null || colorBy === void 0 ? void 0 : colorBy.type),
3630
3729
  drawIndels: shouldDrawMismatches(colorBy === null || colorBy === void 0 ? void 0 : colorBy.type),
3631
3730
  largeInsertionIndicatorScale: insertScale,
3632
3731
  minSubfeatureWidth: minSubfeatureWidth,
3633
3732
  charWidth: charWidth,
3634
- charHeight: charHeight
3733
+ charHeight: charHeight,
3734
+ colorForBase: colorForBase,
3735
+ contrastForBase: contrastForBase
3635
3736
  });
3636
3737
 
3637
3738
  if (showSoftClip) {
@@ -3639,7 +3740,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3639
3740
  }
3640
3741
  });
3641
3742
 
3642
- case 14:
3743
+ case 15:
3643
3744
  case "end":
3644
3745
  return _context.stop();
3645
3746
  }
@@ -3696,57 +3797,98 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3696
3797
  return layoutRecords;
3697
3798
  }
3698
3799
  }, {
3699
- key: "render",
3800
+ key: "fetchSequence",
3700
3801
  value: function () {
3701
- var _render = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(renderProps) {
3702
- var _this4 = this;
3703
-
3704
- var sessionId, bpPerPx, regions, adapterConfig, sequenceAdapter, features, layout, layoutRecords, _regions5, region, regionSequence, end, start, originalRefName, refName, _feats$, _yield$getAdapter, dataAdapter, feats, width, height, res, results;
3802
+ var _fetchSequence2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(renderProps) {
3803
+ var sessionId, regions, adapterConfig, sequenceAdapter, _yield$getAdapter, dataAdapter, _regions5, region;
3705
3804
 
3706
3805
  return runtime_1.wrap(function _callee2$(_context2) {
3707
3806
  while (1) {
3708
3807
  switch (_context2.prev = _context2.next) {
3709
3808
  case 0:
3710
- sessionId = renderProps.sessionId, bpPerPx = renderProps.bpPerPx, regions = renderProps.regions, adapterConfig = renderProps.adapterConfig;
3809
+ sessionId = renderProps.sessionId, regions = renderProps.regions, adapterConfig = renderProps.adapterConfig;
3711
3810
  sequenceAdapter = adapterConfig.sequenceAdapter;
3712
- _context2.next = 4;
3713
- return this.getFeatures(renderProps);
3811
+
3812
+ if (sequenceAdapter) {
3813
+ _context2.next = 4;
3814
+ break;
3815
+ }
3816
+
3817
+ return _context2.abrupt("return", undefined);
3714
3818
 
3715
3819
  case 4:
3716
- features = _context2.sent;
3820
+ _context2.next = 6;
3821
+ return dataAdapterCache.getAdapter(this.pluginManager, sessionId, sequenceAdapter);
3822
+
3823
+ case 6:
3824
+ _yield$getAdapter = _context2.sent;
3825
+ dataAdapter = _yield$getAdapter.dataAdapter;
3826
+ _regions5 = _slicedToArray(regions, 1), region = _regions5[0];
3827
+ return _context2.abrupt("return", fetchSequence(region, dataAdapter));
3828
+
3829
+ case 10:
3830
+ case "end":
3831
+ return _context2.stop();
3832
+ }
3833
+ }
3834
+ }, _callee2, this);
3835
+ }));
3836
+
3837
+ function fetchSequence$1(_x4) {
3838
+ return _fetchSequence2.apply(this, arguments);
3839
+ }
3840
+
3841
+ return fetchSequence$1;
3842
+ }()
3843
+ }, {
3844
+ key: "render",
3845
+ value: function () {
3846
+ var _render = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(renderProps) {
3847
+ var _renderProps$colorBy,
3848
+ _this4 = this;
3849
+
3850
+ var features, layout, regions, bpPerPx, layoutRecords, _regions6, region, regionSequence, end, start, width, height, res, results;
3851
+
3852
+ return runtime_1.wrap(function _callee3$(_context3) {
3853
+ while (1) {
3854
+ switch (_context3.prev = _context3.next) {
3855
+ case 0:
3856
+ _context3.next = 2;
3857
+ return this.getFeatures(renderProps);
3858
+
3859
+ case 2:
3860
+ features = _context3.sent;
3717
3861
  layout = this.createLayoutInWorker(renderProps);
3862
+ regions = renderProps.regions, bpPerPx = renderProps.bpPerPx;
3718
3863
  layoutRecords = this.layoutFeats(_objectSpread2(_objectSpread2({}, renderProps), {}, {
3719
3864
  features: features,
3720
3865
  layout: layout
3721
3866
  }));
3722
- _regions5 = _slicedToArray(regions, 1), region = _regions5[0];
3723
- end = region.end, start = region.start, originalRefName = region.originalRefName, refName = region.refName;
3867
+ _regions6 = _slicedToArray(regions, 1), region = _regions6[0]; // only need reference sequence if there are features and only for some
3868
+ // cases
3724
3869
 
3725
- if (!sequenceAdapter) {
3726
- _context2.next = 18;
3870
+ if (!(features.size && shouldFetchReferenceSequence((_renderProps$colorBy = renderProps.colorBy) === null || _renderProps$colorBy === void 0 ? void 0 : _renderProps$colorBy.type))) {
3871
+ _context3.next = 13;
3727
3872
  break;
3728
3873
  }
3729
3874
 
3730
- _context2.next = 12;
3731
- return dataAdapterCache.getAdapter(this.pluginManager, sessionId, sequenceAdapter);
3875
+ _context3.next = 10;
3876
+ return this.fetchSequence(renderProps);
3732
3877
 
3733
- case 12:
3734
- _yield$getAdapter = _context2.sent;
3735
- dataAdapter = _yield$getAdapter.dataAdapter;
3736
- _context2.next = 16;
3737
- return dataAdapter.getFeatures(_objectSpread2(_objectSpread2({}, region), {}, {
3738
- refName: originalRefName || refName,
3739
- end: region.end + 1
3740
- })).pipe(operators.toArray()).toPromise();
3878
+ case 10:
3879
+ _context3.t0 = _context3.sent;
3880
+ _context3.next = 14;
3881
+ break;
3741
3882
 
3742
- case 16:
3743
- feats = _context2.sent;
3744
- regionSequence = (_feats$ = feats[0]) === null || _feats$ === void 0 ? void 0 : _feats$.get('seq');
3883
+ case 13:
3884
+ _context3.t0 = undefined;
3745
3885
 
3746
- case 18:
3886
+ case 14:
3887
+ regionSequence = _context3.t0;
3888
+ end = region.end, start = region.start;
3747
3889
  width = (end - start) / bpPerPx;
3748
3890
  height = Math.max(layout.getTotalHeight(), 1);
3749
- _context2.next = 22;
3891
+ _context3.next = 20;
3750
3892
  return offscreenCanvasUtils.renderToAbstractCanvas(width, height, renderProps, function (ctx) {
3751
3893
  return _this4.makeImageData(ctx, layoutRecords, _objectSpread2(_objectSpread2({}, renderProps), {}, {
3752
3894
  layout: layout,
@@ -3755,9 +3897,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3755
3897
  }));
3756
3898
  });
3757
3899
 
3758
- case 22:
3759
- res = _context2.sent;
3760
- _context2.next = 25;
3900
+ case 20:
3901
+ res = _context3.sent;
3902
+ _context3.next = 23;
3761
3903
  return _get(_getPrototypeOf(PileupRenderer.prototype), "render", this).call(this, _objectSpread2(_objectSpread2(_objectSpread2({}, renderProps), res), {}, {
3762
3904
  features: features,
3763
3905
  layout: layout,
@@ -3765,9 +3907,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3765
3907
  width: width
3766
3908
  }));
3767
3909
 
3768
- case 25:
3769
- results = _context2.sent;
3770
- return _context2.abrupt("return", _objectSpread2(_objectSpread2(_objectSpread2({}, results), res), {}, {
3910
+ case 23:
3911
+ results = _context3.sent;
3912
+ return _context3.abrupt("return", _objectSpread2(_objectSpread2(_objectSpread2({}, results), res), {}, {
3771
3913
  features: features,
3772
3914
  layout: layout,
3773
3915
  height: height,
@@ -3775,15 +3917,15 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3775
3917
  maxHeightReached: layout.maxHeightReached
3776
3918
  }));
3777
3919
 
3778
- case 27:
3920
+ case 25:
3779
3921
  case "end":
3780
- return _context2.stop();
3922
+ return _context3.stop();
3781
3923
  }
3782
3924
  }
3783
- }, _callee2, this);
3925
+ }, _callee3, this);
3784
3926
  }));
3785
3927
 
3786
- function render(_x4) {
3928
+ function render(_x5) {
3787
3929
  return _render.apply(this, arguments);
3788
3930
  }
3789
3931
 
@@ -3943,10 +4085,15 @@ function PileupRendering(props) {
3943
4085
 
3944
4086
  var offsetX = 0;
3945
4087
  var offsetY = 0;
4088
+ var canvas = highlightOverlayCanvas.current;
3946
4089
 
3947
- if (highlightOverlayCanvas.current) {
3948
- offsetX = highlightOverlayCanvas.current.getBoundingClientRect().left;
3949
- offsetY = highlightOverlayCanvas.current.getBoundingClientRect().top;
4090
+ if (canvas) {
4091
+ var _canvas$getBoundingCl = canvas.getBoundingClientRect(),
4092
+ left = _canvas$getBoundingCl.left,
4093
+ top = _canvas$getBoundingCl.top;
4094
+
4095
+ offsetX = left;
4096
+ offsetY = top;
3950
4097
  }
3951
4098
 
3952
4099
  offsetX = event.clientX - offsetX;
@@ -4330,45 +4477,51 @@ var stateModelFactory = function stateModelFactory(pluginManager, configSchema)
4330
4477
  });
4331
4478
  };
4332
4479
 
4480
+ var useStyles = /*#__PURE__*/core.makeStyles(function () {
4481
+ return {
4482
+ resizeHandle: {
4483
+ height: 2,
4484
+ position: 'absolute',
4485
+ zIndex: 2
4486
+ }
4487
+ };
4488
+ });
4489
+
4333
4490
  function AlignmentsDisplay(_ref) {
4334
4491
  var model = _ref.model;
4335
4492
  var PileupDisplay = model.PileupDisplay,
4336
4493
  SNPCoverageDisplay = model.SNPCoverageDisplay,
4337
4494
  showPileup = model.showPileup,
4338
4495
  showCoverage = model.showCoverage;
4496
+ var classes = useStyles();
4497
+ var top = SNPCoverageDisplay.height;
4339
4498
  return /*#__PURE__*/React__default.createElement("div", {
4340
4499
  "data-testid": "display-".concat(configuration.getConf(model, 'displayId')),
4341
4500
  style: {
4342
4501
  position: 'relative'
4343
4502
  }
4344
- }, /*#__PURE__*/React__default.createElement("div", {
4503
+ }, showCoverage ? /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("div", {
4345
4504
  "data-testid": "Blockset-snpcoverage"
4346
- }, showCoverage ? /*#__PURE__*/React__default.createElement(SNPCoverageDisplay.RenderingComponent, {
4505
+ }, /*#__PURE__*/React__default.createElement(SNPCoverageDisplay.RenderingComponent, {
4347
4506
  model: SNPCoverageDisplay
4348
- }) : null), /*#__PURE__*/React__default.createElement(ui.ResizeHandle, {
4507
+ })), /*#__PURE__*/React__default.createElement(ui.ResizeHandle, {
4349
4508
  onDrag: function onDrag(delta) {
4350
- if (SNPCoverageDisplay) {
4351
- SNPCoverageDisplay.setHeight(SNPCoverageDisplay.height + delta);
4352
- return delta;
4353
- }
4354
-
4355
- return 0;
4509
+ SNPCoverageDisplay.setHeight(SNPCoverageDisplay.height + delta);
4510
+ return delta;
4356
4511
  },
4512
+ className: classes.resizeHandle,
4357
4513
  style: {
4358
- position: 'absolute',
4359
- top: showCoverage ? SNPCoverageDisplay.height + 2 : 0,
4360
- height: 3
4514
+ top: top
4361
4515
  }
4362
- }), /*#__PURE__*/React__default.createElement("div", {
4516
+ })) : null, showPileup ? /*#__PURE__*/React__default.createElement("div", {
4363
4517
  "data-testid": "Blockset-pileup",
4364
4518
  style: {
4365
4519
  position: 'absolute',
4366
- top: showCoverage ? SNPCoverageDisplay.height + 5 : 0,
4367
- height: 3
4520
+ top: showCoverage ? SNPCoverageDisplay.height : 0
4368
4521
  }
4369
- }, showPileup ? /*#__PURE__*/React__default.createElement(PileupDisplay.RenderingComponent, {
4522
+ }, /*#__PURE__*/React__default.createElement(PileupDisplay.RenderingComponent, {
4370
4523
  model: PileupDisplay
4371
- }) : null));
4524
+ })) : null);
4372
4525
  }
4373
4526
 
4374
4527
  var ReactComponent$1 = /*#__PURE__*/mobxReact.observer(AlignmentsDisplay);
@@ -4417,10 +4570,10 @@ function SNPCoverageConfigFactory(pluginManager) {
4417
4570
  description: 'draw upside down',
4418
4571
  defaultValue: false
4419
4572
  },
4420
- headroom: {
4421
- type: 'number',
4422
- description: 'round the upper value of the domain scale to the nearest N',
4423
- defaultValue: 0
4573
+ multiTicks: {
4574
+ type: 'boolean',
4575
+ description: 'Display multiple values for the ticks',
4576
+ defaultValue: false
4424
4577
  },
4425
4578
  renderers: configuration.ConfigurationSchema('RenderersConfiguration', {
4426
4579
  SNPCoverageRenderer: SNPCoverageRendererConfigSchema
@@ -4440,10 +4593,10 @@ var TooltipContents = /*#__PURE__*/React__default.forwardRef(function (_ref, ref
4440
4593
  var start = feature.get('start');
4441
4594
  var end = feature.get('end');
4442
4595
  var name = feature.get('refName');
4596
+ var info = feature.get('snpinfo');
4443
4597
  var loc = [name, start === end ? en(start) : "".concat(en(start), "..").concat(en(end))].filter(function (f) {
4444
4598
  return !!f;
4445
4599
  }).join(':');
4446
- var info = feature.get('snpinfo');
4447
4600
  var total = info === null || info === void 0 ? void 0 : info.total;
4448
4601
  return /*#__PURE__*/React__default.createElement("div", {
4449
4602
  ref: ref
@@ -4460,7 +4613,7 @@ var TooltipContents = /*#__PURE__*/React__default.forwardRef(function (_ref, ref
4460
4613
  var strands = score.strands;
4461
4614
  return /*#__PURE__*/React__default.createElement("tr", {
4462
4615
  key: base
4463
- }, /*#__PURE__*/React__default.createElement("td", null, base.toUpperCase()), /*#__PURE__*/React__default.createElement("td", null, score.total), /*#__PURE__*/React__default.createElement("td", null, base === 'total' || base === 'skip' ? '---' : "".concat(Math.floor(score.total / total * 100), "%")), /*#__PURE__*/React__default.createElement("td", null, strands['-1'] ? "".concat(strands['-1'], "(-)") : '', strands['1'] ? "".concat(strands['1'], "(+)") : ''), /*#__PURE__*/React__default.createElement("td", null, key));
4616
+ }, /*#__PURE__*/React__default.createElement("td", null, base.toUpperCase()), /*#__PURE__*/React__default.createElement("td", null, score.total), /*#__PURE__*/React__default.createElement("td", null, base === 'total' || base === 'skip' ? '---' : "".concat(Math.floor(score.total / (total || score.total || 1) * 100), "%")), /*#__PURE__*/React__default.createElement("td", null, strands['-1'] ? "".concat(strands['-1'], "(-)") : '', strands['1'] ? "".concat(strands['1'], "(+)") : ''), /*#__PURE__*/React__default.createElement("td", null, key));
4464
4617
  });
4465
4618
  }))));
4466
4619
  });
@@ -5301,6 +5454,13 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
5301
5454
  type: 'perBaseQuality'
5302
5455
  });
5303
5456
  }
5457
+ }, {
5458
+ label: 'Per-base lettering',
5459
+ onClick: function onClick() {
5460
+ self.setColorScheme({
5461
+ type: 'perBaseLettering'
5462
+ });
5463
+ }
5304
5464
  }, {
5305
5465
  label: 'Modifications or methylation',
5306
5466
  onClick: function onClick() {
@@ -5764,12 +5924,14 @@ var AlignmentsPlugin = /*#__PURE__*/function (_Plugin) {
5764
5924
  }(Plugin);
5765
5925
 
5766
5926
  var CramSlightlyLazyFeature = /*#__PURE__*/function () {
5927
+ // uses parameter properties to automatically create fields on the class
5928
+ // https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties
5767
5929
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5768
- function CramSlightlyLazyFeature(record, store) {
5930
+ function CramSlightlyLazyFeature(record, _store) {
5769
5931
  _classCallCheck(this, CramSlightlyLazyFeature);
5770
5932
 
5771
5933
  this.record = record;
5772
- this._store = store;
5934
+ this._store = _store;
5773
5935
  }
5774
5936
 
5775
5937
  _createClass(CramSlightlyLazyFeature, [{
@@ -6012,7 +6174,7 @@ var CramSlightlyLazyFeature = /*#__PURE__*/function () {
6012
6174
  value: function tags() {
6013
6175
  var properties = Object.getOwnPropertyNames(CramSlightlyLazyFeature.prototype);
6014
6176
  return properties.filter(function (prop) {
6015
- return prop.startsWith('_get_') && prop !== '_get_mismatches' && prop !== '_get_skips_and_dels' && prop !== '_get_cram_read_features';
6177
+ return prop.startsWith('_get_') && prop !== '_get_mismatches' && prop !== '_get_cram_read_features';
6016
6178
  }).map(function (methodName) {
6017
6179
  return methodName.replace('_get_', '');
6018
6180
  });
@@ -6176,11 +6338,6 @@ var CramSlightlyLazyFeature = /*#__PURE__*/function () {
6176
6338
  });
6177
6339
  return mismatches;
6178
6340
  }
6179
- }, {
6180
- key: "_get_skips_and_dels",
6181
- value: function _get_skips_and_dels() {
6182
- return this._get_mismatches();
6183
- }
6184
6341
  }]);
6185
6342
 
6186
6343
  return CramSlightlyLazyFeature;
@@ -6774,6 +6931,8 @@ var CramAdapter$1 = {
6774
6931
  };
6775
6932
 
6776
6933
  var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6934
+ // uses parameter properties to automatically create fields on the class
6935
+ // https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties
6777
6936
  function BamSlightlyLazyFeature(record, adapter, ref) {
6778
6937
  _classCallCheck(this, BamSlightlyLazyFeature);
6779
6938
 
@@ -6840,18 +6999,6 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6840
6999
  value: function _get_seq() {
6841
7000
  return this.record.getReadBases();
6842
7001
  }
6843
- }, {
6844
- key: "_get_MD",
6845
- value: function _get_MD() {
6846
- var md = this.record.get('MD');
6847
- var seq = this.get('seq');
6848
-
6849
- if (!md && seq && this.ref) {
6850
- return generateMD(this.ref, this.record.getReadBases(), this.get('CIGAR'));
6851
- }
6852
-
6853
- return md;
6854
- }
6855
7002
  }, {
6856
7003
  key: "qualRaw",
6857
7004
  value: function qualRaw() {
@@ -6865,7 +7012,7 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6865
7012
  value: function tags() {
6866
7013
  var properties = Object.getOwnPropertyNames(BamSlightlyLazyFeature.prototype);
6867
7014
  return _toConsumableArray(new Set(properties.filter(function (prop) {
6868
- return prop.startsWith('_get_') && prop !== '_get_mismatches' && prop !== '_get_skips_and_dels' && prop !== '_get_cram_read_features' && prop !== '_get_tags' && prop !== '_get_next_seq_id' && prop !== '_get_seq_id';
7015
+ return prop.startsWith('_get_') && prop !== '_get_mismatches' && prop !== '_get_tags' && prop !== '_get_next_seq_id' && prop !== '_get_seq_id';
6869
7016
  }).map(function (methodName) {
6870
7017
  return methodName.replace('_get_', '');
6871
7018
  }).concat(this.record._tags())));
@@ -6921,61 +7068,10 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6921
7068
  uniqueId: this.id()
6922
7069
  });
6923
7070
  }
6924
- }, {
6925
- key: "_get_skips_and_dels",
6926
- value: function _get_skips_and_dels() {
6927
- var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
6928
- cigarAttributeName: 'CIGAR'
6929
- };
6930
- var cigarAttributeName = opts.cigarAttributeName;
6931
- var mismatches = [];
6932
- var cigarOps = []; // parse the CIGAR tag if it has one
6933
-
6934
- var cigarString = this.get(cigarAttributeName);
6935
-
6936
- if (cigarString) {
6937
- cigarOps = parseCigar(cigarString);
6938
- mismatches = mismatches.concat(cigarToMismatches(cigarOps, this.get('seq'), this.qualRaw()));
6939
- }
6940
-
6941
- return mismatches;
6942
- }
6943
7071
  }, {
6944
7072
  key: "_get_mismatches",
6945
7073
  value: function _get_mismatches() {
6946
- var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
6947
- _ref$cigarAttributeNa = _ref.cigarAttributeName,
6948
- cigarAttributeName = _ref$cigarAttributeNa === void 0 ? 'CIGAR' : _ref$cigarAttributeNa,
6949
- _ref$mdAttributeName = _ref.mdAttributeName,
6950
- mdAttributeName = _ref$mdAttributeName === void 0 ? 'MD' : _ref$mdAttributeName;
6951
-
6952
- var mismatches = [];
6953
- var cigarOps = []; // parse the CIGAR tag if it has one
6954
-
6955
- var cigarString = this.get(cigarAttributeName);
6956
- var seq = this.get('seq');
6957
- var qual = this.qualRaw();
6958
-
6959
- if (cigarString) {
6960
- cigarOps = parseCigar(cigarString);
6961
- mismatches = mismatches.concat(cigarToMismatches(cigarOps, seq, qual));
6962
- } // now let's look for CRAM or MD mismatches
6963
-
6964
-
6965
- var mdString = this.get(mdAttributeName);
6966
-
6967
- if (mdString) {
6968
- mismatches = mismatches.concat(mdToMismatches(mdString, cigarOps, mismatches, seq, qual));
6969
- } // uniqify the mismatches
6970
-
6971
-
6972
- var seen = {};
6973
- return mismatches.filter(function (m) {
6974
- var key = "".concat(m.type, ",").concat(m.start, ",").concat(m.length);
6975
- var s = seen[key];
6976
- seen[key] = true;
6977
- return !s;
6978
- });
7074
+ return getMismatches(this.get('CIGAR'), this.get('MD'), this.get('seq'), this.ref, this.qualRaw());
6979
7075
  }
6980
7076
  }, {
6981
7077
  key: "_get_clipPos",
@@ -7005,7 +7101,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7005
7101
  // configure method allows derived classes to override this behavior
7006
7102
  function () {
7007
7103
  var _configure = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
7008
- var bamLocation, location, indexType, chunkSizeLimit, bam$1, adapterConfig;
7104
+ var bamLocation, location, indexType, bam$1, adapterConfig;
7009
7105
  return runtime_1.wrap(function _callee$(_context) {
7010
7106
  while (1) {
7011
7107
  switch (_context.prev = _context.next) {
@@ -7014,13 +7110,16 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7014
7110
  bamLocation = configuration.readConfObject(this.config, 'bamLocation');
7015
7111
  location = configuration.readConfObject(this.config, ['index', 'location']);
7016
7112
  indexType = configuration.readConfObject(this.config, ['index', 'indexType']);
7017
- chunkSizeLimit = configuration.readConfObject(this.config, 'chunkSizeLimit');
7018
7113
  bam$1 = new bam.BamFile({
7019
7114
  bamFilehandle: io.openLocation(bamLocation, this.pluginManager),
7020
7115
  csiFilehandle: indexType === 'CSI' ? io.openLocation(location, this.pluginManager) : undefined,
7021
7116
  baiFilehandle: indexType !== 'CSI' ? io.openLocation(location, this.pluginManager) : undefined,
7022
- chunkSizeLimit: chunkSizeLimit,
7023
- fetchSizeLimit: 100000000
7117
+ // chunkSizeLimit and fetchSizeLimit are more troublesome than
7118
+ // helpful, and have given overly large values on the ultra long
7119
+ // nanopore reads even with 500MB limits, so disabled with infinity
7120
+ chunkSizeLimit: Infinity,
7121
+ fetchSizeLimit: Infinity,
7122
+ yieldThreadTime: Infinity
7024
7123
  });
7025
7124
  adapterConfig = configuration.readConfObject(this.config, 'sequenceAdapter');
7026
7125
 
@@ -7232,7 +7331,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7232
7331
  key: "seqFetch",
7233
7332
  value: function () {
7234
7333
  var _seqFetch = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee7(refName, start, end) {
7235
- var _yield$this$configure3, sequenceAdapter, refSeqStore, features, seqChunks, trimmed, sequence;
7334
+ var _yield$this$configure3, sequenceAdapter, refSeqStore, features, seqChunks, sequence;
7236
7335
 
7237
7336
  return runtime_1.wrap(function _callee7$(_context7) {
7238
7337
  while (1) {
@@ -7273,7 +7372,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7273
7372
 
7274
7373
  case 12:
7275
7374
  seqChunks = _context7.sent;
7276
- trimmed = [];
7375
+ sequence = '';
7277
7376
  seqChunks.sort(function (a, b) {
7278
7377
  return a.get('start') - b.get('start');
7279
7378
  }).forEach(function (chunk) {
@@ -7283,21 +7382,20 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7283
7382
  var trimEnd = Math.min(end - chunkStart, chunkEnd - chunkStart);
7284
7383
  var trimLength = trimEnd - trimStart;
7285
7384
  var chunkSeq = chunk.get('seq') || chunk.get('residues');
7286
- trimmed.push(chunkSeq.substr(trimStart, trimLength));
7385
+ sequence += chunkSeq.substr(trimStart, trimLength);
7287
7386
  });
7288
- sequence = trimmed.join('');
7289
7387
 
7290
7388
  if (!(sequence.length !== end - start)) {
7291
- _context7.next = 18;
7389
+ _context7.next = 17;
7292
7390
  break;
7293
7391
  }
7294
7392
 
7295
7393
  throw new Error("sequence fetch failed: fetching ".concat(refName, ":").concat((start - 1).toLocaleString(), "-").concat(end.toLocaleString(), " returned ").concat(sequence.length.toLocaleString(), " bases, but should have returned ").concat((end - start).toLocaleString()));
7296
7394
 
7297
- case 18:
7395
+ case 17:
7298
7396
  return _context7.abrupt("return", sequence);
7299
7397
 
7300
- case 19:
7398
+ case 18:
7301
7399
  case "end":
7302
7400
  return _context7.stop();
7303
7401
  }
@@ -7365,7 +7463,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7365
7463
  record = _step.value;
7366
7464
  ref = void 0;
7367
7465
 
7368
- if (record.get('md')) {
7466
+ if (record.get('MD')) {
7369
7467
  _context8.next = 21;
7370
7468
  break;
7371
7469
  }
@@ -7560,7 +7658,7 @@ var HtsgetBamAdapter$1 = {
7560
7658
  'default': HtsgetBamAdapter
7561
7659
  };
7562
7660
 
7563
- var useStyles = /*#__PURE__*/core.makeStyles(function (theme) {
7661
+ var useStyles$1 = /*#__PURE__*/core.makeStyles(function (theme) {
7564
7662
  return {
7565
7663
  root: {
7566
7664
  width: 300
@@ -7575,7 +7673,7 @@ var useStyles = /*#__PURE__*/core.makeStyles(function (theme) {
7575
7673
  });
7576
7674
 
7577
7675
  function ColorByTagDlg$1(props) {
7578
- var classes = useStyles();
7676
+ var classes = useStyles$1();
7579
7677
  var model = props.model,
7580
7678
  handleClose = props.handleClose;
7581
7679
 
@@ -7596,14 +7694,12 @@ function ColorByTagDlg$1(props) {
7596
7694
  style: {
7597
7695
  overflowX: 'hidden'
7598
7696
  }
7599
- }, /*#__PURE__*/React__default.createElement("div", {
7600
- className: classes.root
7601
7697
  }, /*#__PURE__*/React__default.createElement(core.Typography, null, "Enter tag to color by: "), /*#__PURE__*/React__default.createElement(core.Typography, {
7602
7698
  color: "textSecondary"
7603
7699
  }, "Examples: XS or TS for RNA-seq inferred read strand, ts (lower-case) for minimap2 read strand, HP for haplotype, RG for read group, etc."), /*#__PURE__*/React__default.createElement(core.TextField, {
7604
7700
  value: tag,
7605
7701
  onChange: function onChange(event) {
7606
- setTag(event.target.value);
7702
+ return setTag(event.target.value);
7607
7703
  },
7608
7704
  placeholder: "Enter tag name",
7609
7705
  inputProps: {
@@ -7614,12 +7710,9 @@ function ColorByTagDlg$1(props) {
7614
7710
  helperText: tag.length === 2 && !validTag ? 'Not a valid tag' : '',
7615
7711
  autoComplete: "off",
7616
7712
  "data-testid": "color-tag-name"
7617
- }), /*#__PURE__*/React__default.createElement(core.Button, {
7713
+ }), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
7618
7714
  variant: "contained",
7619
7715
  color: "primary",
7620
- style: {
7621
- marginLeft: 20
7622
- },
7623
7716
  onClick: function onClick() {
7624
7717
  model.setColorScheme({
7625
7718
  type: 'tag',
@@ -7628,7 +7721,11 @@ function ColorByTagDlg$1(props) {
7628
7721
  handleClose();
7629
7722
  },
7630
7723
  disabled: !validTag
7631
- }, "Submit"))));
7724
+ }, "Submit"), /*#__PURE__*/React__default.createElement(core.Button, {
7725
+ variant: "contained",
7726
+ color: "secondary",
7727
+ onClick: handleClose
7728
+ }, "Cancel"))));
7632
7729
  }
7633
7730
 
7634
7731
  var ColorByTag = /*#__PURE__*/mobxReact.observer(ColorByTagDlg$1);
@@ -7638,11 +7735,8 @@ var ColorByTag$1 = {
7638
7735
  'default': ColorByTag
7639
7736
  };
7640
7737
 
7641
- var useStyles$1 = /*#__PURE__*/core.makeStyles(function (theme) {
7738
+ var useStyles$2 = /*#__PURE__*/core.makeStyles(function (theme) {
7642
7739
  return {
7643
- root: {
7644
- width: 500
7645
- },
7646
7740
  paper: {
7647
7741
  padding: theme.spacing(2),
7648
7742
  margin: theme.spacing(2)
@@ -7696,7 +7790,7 @@ function FilterByTagDlg$1(props) {
7696
7790
 
7697
7791
  var model = props.model,
7698
7792
  handleClose = props.handleClose;
7699
- var classes = useStyles$1();
7793
+ var classes = useStyles$2();
7700
7794
  var filterBy = model.filterBy;
7701
7795
 
7702
7796
  var _useState = React.useState(filterBy === null || filterBy === void 0 ? void 0 : filterBy.flagInclude),
@@ -7735,9 +7829,7 @@ function FilterByTagDlg$1(props) {
7735
7829
  onClick: handleClose
7736
7830
  }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement(core.Typography, null, "Set filter bitmask options. Refer to ", /*#__PURE__*/React__default.createElement(core.Link, {
7737
7831
  href: site
7738
- }, site), ' ', "for details"), /*#__PURE__*/React__default.createElement("div", {
7739
- className: classes.root
7740
- }, /*#__PURE__*/React__default.createElement(core.Paper, {
7832
+ }, site), ' ', "for details"), /*#__PURE__*/React__default.createElement(core.Paper, {
7741
7833
  className: classes.paper,
7742
7834
  variant: "outlined"
7743
7835
  }, /*#__PURE__*/React__default.createElement("div", {
@@ -7792,9 +7884,11 @@ function FilterByTagDlg$1(props) {
7792
7884
  'data-testid': 'color-tag-readname-input'
7793
7885
  },
7794
7886
  "data-testid": "color-tag-readname"
7795
- })), /*#__PURE__*/React__default.createElement(core.Button, {
7887
+ })), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
7796
7888
  variant: "contained",
7797
7889
  color: "primary",
7890
+ autoFocus: true,
7891
+ type: "submit",
7798
7892
  onClick: function onClick() {
7799
7893
  model.setFilterBy({
7800
7894
  flagInclude: flagInclude,
@@ -7807,7 +7901,13 @@ function FilterByTagDlg$1(props) {
7807
7901
  });
7808
7902
  handleClose();
7809
7903
  }
7810
- }, "Submit"))));
7904
+ }, "Submit"), /*#__PURE__*/React__default.createElement(core.Button, {
7905
+ variant: "contained",
7906
+ color: "secondary",
7907
+ onClick: function onClick() {
7908
+ return handleClose();
7909
+ }
7910
+ }, "Cancel"))));
7811
7911
  }
7812
7912
 
7813
7913
  var FilterByTag = /*#__PURE__*/mobxReact.observer(FilterByTagDlg$1);
@@ -7817,7 +7917,7 @@ var FilterByTag$1 = {
7817
7917
  'default': FilterByTag
7818
7918
  };
7819
7919
 
7820
- var useStyles$2 = /*#__PURE__*/core.makeStyles(function (theme) {
7920
+ var useStyles$3 = /*#__PURE__*/core.makeStyles(function (theme) {
7821
7921
  return {
7822
7922
  root: {
7823
7923
  margin: 0,
@@ -7833,7 +7933,7 @@ var useStyles$2 = /*#__PURE__*/core.makeStyles(function (theme) {
7833
7933
  });
7834
7934
 
7835
7935
  function SortByTagDlg$1(props) {
7836
- var classes = useStyles$2();
7936
+ var classes = useStyles$3();
7837
7937
  var model = props.model,
7838
7938
  handleClose = props.handleClose;
7839
7939
 
@@ -7850,12 +7950,12 @@ function SortByTagDlg$1(props) {
7850
7950
  "aria-label": "close",
7851
7951
  className: classes.closeButton,
7852
7952
  onClick: handleClose
7853
- }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement("div", null, /*#__PURE__*/React__default.createElement(core.Typography, null, "Set the tag to sort by"), /*#__PURE__*/React__default.createElement(core.Typography, {
7953
+ }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement(core.Typography, null, "Set the tag to sort by"), /*#__PURE__*/React__default.createElement(core.Typography, {
7854
7954
  color: "textSecondary"
7855
7955
  }, "Examples: HP for haplotype, RG for read group, etc."), /*#__PURE__*/React__default.createElement(core.TextField, {
7856
7956
  value: tag,
7857
7957
  onChange: function onChange(event) {
7858
- setTag(event.target.value);
7958
+ return setTag(event.target.value);
7859
7959
  },
7860
7960
  placeholder: "Enter tag name",
7861
7961
  inputProps: {
@@ -7866,14 +7966,22 @@ function SortByTagDlg$1(props) {
7866
7966
  helperText: tag.length === 2 && !validTag ? 'Not a valid tag' : '',
7867
7967
  autoComplete: "off",
7868
7968
  "data-testid": "sort-tag-name"
7869
- }), /*#__PURE__*/React__default.createElement(core.Button, {
7969
+ }), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
7870
7970
  variant: "contained",
7871
7971
  color: "primary",
7972
+ type: "submit",
7973
+ autoFocus: true,
7872
7974
  onClick: function onClick() {
7873
7975
  model.setSortedBy('tag', tag);
7874
7976
  handleClose();
7875
7977
  }
7876
- }, "Submit"))));
7978
+ }, "Submit"), /*#__PURE__*/React__default.createElement(core.Button, {
7979
+ variant: "contained",
7980
+ color: "secondary",
7981
+ onClick: function onClick() {
7982
+ return handleClose();
7983
+ }
7984
+ }, "Cancel"))));
7877
7985
  }
7878
7986
 
7879
7987
  var SortByTag = /*#__PURE__*/mobxReact.observer(SortByTagDlg$1);
@@ -7883,11 +7991,8 @@ var SortByTag$1 = {
7883
7991
  'default': SortByTag
7884
7992
  };
7885
7993
 
7886
- var useStyles$3 = /*#__PURE__*/core.makeStyles(function (theme) {
7994
+ var useStyles$4 = /*#__PURE__*/core.makeStyles(function (theme) {
7887
7995
  return {
7888
- root: {
7889
- margin: theme.spacing(4)
7890
- },
7891
7996
  closeButton: {
7892
7997
  position: 'absolute',
7893
7998
  right: theme.spacing(1),
@@ -7898,7 +8003,7 @@ var useStyles$3 = /*#__PURE__*/core.makeStyles(function (theme) {
7898
8003
  });
7899
8004
 
7900
8005
  function SetFeatureHeightDlg$1(props) {
7901
- var classes = useStyles$3();
8006
+ var classes = useStyles$4();
7902
8007
  var model = props.model,
7903
8008
  handleClose = props.handleClose;
7904
8009
  var featureHeightSetting = model.featureHeightSetting,
@@ -7921,10 +8026,9 @@ function SetFeatureHeightDlg$1(props) {
7921
8026
  }, /*#__PURE__*/React__default.createElement(core.DialogTitle, null, "Set feature height", /*#__PURE__*/React__default.createElement(core.IconButton, {
7922
8027
  className: classes.closeButton,
7923
8028
  onClick: handleClose
7924
- }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement(core.Typography, null, "Adjust the feature height and whether there is any spacing between features. Setting feature height to 1 and removing spacing makes the display very compact"), /*#__PURE__*/React__default.createElement("div", {
7925
- className: classes.root
7926
- }, /*#__PURE__*/React__default.createElement(core.Typography, null, "Enter feature height: "), /*#__PURE__*/React__default.createElement(core.TextField, {
8029
+ }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement(core.Typography, null, "Adjust the feature height and whether there is any spacing between features. Setting feature height to 1 and removing spacing makes the display very compact."), /*#__PURE__*/React__default.createElement(core.TextField, {
7927
8030
  value: height,
8031
+ helperText: "Feature height",
7928
8032
  onChange: function onChange(event) {
7929
8033
  setHeight(event.target.value);
7930
8034
  }
@@ -7938,20 +8042,24 @@ function SetFeatureHeightDlg$1(props) {
7938
8042
  }
7939
8043
  }),
7940
8044
  label: "Remove spacing between features in y-direction?"
7941
- }), /*#__PURE__*/React__default.createElement(core.Button, {
8045
+ }), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
7942
8046
  variant: "contained",
7943
8047
  color: "primary",
7944
8048
  type: "submit",
7945
- style: {
7946
- marginLeft: 20
7947
- },
8049
+ autoFocus: true,
7948
8050
  disabled: !ok,
7949
8051
  onClick: function onClick() {
7950
8052
  model.setFeatureHeight(height !== '' && !Number.isNaN(+height) ? +height : undefined);
7951
8053
  model.setNoSpacing(noSpacing);
7952
8054
  handleClose();
7953
8055
  }
7954
- }, "Submit"))));
8056
+ }, "Submit"), /*#__PURE__*/React__default.createElement(core.Button, {
8057
+ variant: "contained",
8058
+ color: "secondary",
8059
+ onClick: function onClick() {
8060
+ return handleClose();
8061
+ }
8062
+ }, "Cancel"))));
7955
8063
  }
7956
8064
 
7957
8065
  var SetFeatureHeight = /*#__PURE__*/mobxReact.observer(SetFeatureHeightDlg$1);
@@ -7961,7 +8069,7 @@ var SetFeatureHeight$1 = {
7961
8069
  'default': SetFeatureHeight
7962
8070
  };
7963
8071
 
7964
- var useStyles$4 = /*#__PURE__*/core.makeStyles(function (theme) {
8072
+ var useStyles$5 = /*#__PURE__*/core.makeStyles(function (theme) {
7965
8073
  return {
7966
8074
  root: {
7967
8075
  width: 500
@@ -7981,7 +8089,7 @@ var useStyles$4 = /*#__PURE__*/core.makeStyles(function (theme) {
7981
8089
  function SetMaxHeightDlg$1(props) {
7982
8090
  var model = props.model,
7983
8091
  handleClose = props.handleClose;
7984
- var classes = useStyles$4();
8092
+ var classes = useStyles$5();
7985
8093
  var _model$maxHeight = model.maxHeight,
7986
8094
  maxHeight = _model$maxHeight === void 0 ? '' : _model$maxHeight;
7987
8095
 
@@ -7993,32 +8101,34 @@ function SetMaxHeightDlg$1(props) {
7993
8101
  return /*#__PURE__*/React__default.createElement(core.Dialog, {
7994
8102
  open: true,
7995
8103
  onClose: handleClose
7996
- }, /*#__PURE__*/React__default.createElement(core.DialogTitle, {
7997
- id: "alert-dialog-title"
7998
- }, "Filter options", /*#__PURE__*/React__default.createElement(core.IconButton, {
8104
+ }, /*#__PURE__*/React__default.createElement(core.DialogTitle, null, "Filter options", /*#__PURE__*/React__default.createElement(core.IconButton, {
7999
8105
  "aria-label": "close",
8000
8106
  className: classes.closeButton,
8001
8107
  onClick: handleClose
8002
- }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement("div", {
8108
+ }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, {
8003
8109
  className: classes.root
8004
- }, /*#__PURE__*/React__default.createElement(core.Typography, null, "Set max height for the track"), /*#__PURE__*/React__default.createElement(core.TextField, {
8110
+ }, /*#__PURE__*/React__default.createElement(core.Typography, null, "Set max height for the track. For example, you can increase this if the layout says \"Max height reached\""), /*#__PURE__*/React__default.createElement(core.TextField, {
8005
8111
  value: max,
8006
8112
  onChange: function onChange(event) {
8007
8113
  setMax(event.target.value);
8008
8114
  },
8009
8115
  placeholder: "Enter max height for layout"
8010
- }), /*#__PURE__*/React__default.createElement(core.Button, {
8116
+ }), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
8011
8117
  variant: "contained",
8012
8118
  color: "primary",
8013
8119
  type: "submit",
8014
- style: {
8015
- marginLeft: 20
8016
- },
8120
+ autoFocus: true,
8017
8121
  onClick: function onClick() {
8018
8122
  model.setMaxHeight(max !== '' && !Number.isNaN(+max) ? +max : undefined);
8019
8123
  handleClose();
8020
8124
  }
8021
- }, "Submit"))));
8125
+ }, "Submit"), /*#__PURE__*/React__default.createElement(core.Button, {
8126
+ variant: "contained",
8127
+ color: "secondary",
8128
+ onClick: function onClick() {
8129
+ return handleClose();
8130
+ }
8131
+ }, "Cancel"))));
8022
8132
  }
8023
8133
 
8024
8134
  var SetMaxHeight = /*#__PURE__*/mobxReact.observer(SetMaxHeightDlg$1);
@@ -8028,9 +8138,8 @@ var SetMaxHeight$1 = {
8028
8138
  'default': SetMaxHeight
8029
8139
  };
8030
8140
 
8031
- var useStyles$5 = /*#__PURE__*/core.makeStyles(function (theme) {
8141
+ var useStyles$6 = /*#__PURE__*/core.makeStyles(function (theme) {
8032
8142
  return {
8033
- root: {},
8034
8143
  closeButton: {
8035
8144
  position: 'absolute',
8036
8145
  right: theme.spacing(1),
@@ -8049,7 +8158,7 @@ var useStyles$5 = /*#__PURE__*/core.makeStyles(function (theme) {
8049
8158
 
8050
8159
  function ModificationTable(_ref) {
8051
8160
  var modifications = _ref.modifications;
8052
- var classes = useStyles$5();
8161
+ var classes = useStyles$6();
8053
8162
  return /*#__PURE__*/React__default.createElement("table", {
8054
8163
  className: classes.table
8055
8164
  }, /*#__PURE__*/React__default.createElement("tbody", null, modifications.map(function (_ref2) {
@@ -8069,7 +8178,7 @@ function ModificationTable(_ref) {
8069
8178
  }
8070
8179
 
8071
8180
  function ColorByTagDlg$2(props) {
8072
- var classes = useStyles$5();
8181
+ var classes = useStyles$6();
8073
8182
  var model = props.model,
8074
8183
  handleClose = props.handleClose;
8075
8184
  var colorBy = model.colorBy,
@@ -8084,9 +8193,7 @@ function ColorByTagDlg$2(props) {
8084
8193
  "aria-label": "close",
8085
8194
  className: classes.closeButton,
8086
8195
  onClick: handleClose
8087
- }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement("div", {
8088
- className: classes.root
8089
- }, /*#__PURE__*/React__default.createElement(core.Typography, null, "You can choose to color the modifications in the BAM/CRAM MM/ML specification using this dialog. Choosing modifications colors the modified positions and can color multiple modification types. Choosing the methylation setting colors methylated and unmethylated CpG."), /*#__PURE__*/React__default.createElement(core.Typography, null, "Note: you can revisit this dialog to see the current mapping of colors to modification type for the modification coloring mode"), /*#__PURE__*/React__default.createElement("div", {
8196
+ }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement(core.Typography, null, "You can choose to color the modifications in the BAM/CRAM MM/ML specification using this dialog. Choosing modifications colors the modified positions and can color multiple modification types. Choosing the methylation setting colors methylated and unmethylated CpG."), /*#__PURE__*/React__default.createElement(core.Typography, null, "Note: you can revisit this dialog to see the current mapping of colors to modification type for the modification coloring mode"), /*#__PURE__*/React__default.createElement("div", {
8090
8197
  style: {
8091
8198
  margin: 20
8092
8199
  }
@@ -8096,11 +8203,7 @@ function ColorByTagDlg$2(props) {
8096
8203
  size: 15
8097
8204
  }))) : null, (colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'methylation' ? /*#__PURE__*/React__default.createElement(ModificationTable, {
8098
8205
  modifications: [['methylated', 'red'], ['unmethylated', 'blue']]
8099
- }) : null), /*#__PURE__*/React__default.createElement("div", {
8100
- style: {
8101
- display: 'flex'
8102
- }
8103
- }, /*#__PURE__*/React__default.createElement(core.Button, {
8206
+ }) : null), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
8104
8207
  variant: "contained",
8105
8208
  color: "primary",
8106
8209
  style: {
@@ -8133,7 +8236,7 @@ function ColorByTagDlg$2(props) {
8133
8236
  onClick: function onClick() {
8134
8237
  return handleClose();
8135
8238
  }
8136
- }, "Cancel")))));
8239
+ }, "Cancel"))));
8137
8240
  }
8138
8241
 
8139
8242
  var ColorByModifications = /*#__PURE__*/mobxReact.observer(ColorByTagDlg$2);
@@ -8143,7 +8246,7 @@ var ColorByModifications$1 = {
8143
8246
  'default': ColorByModifications
8144
8247
  };
8145
8248
 
8146
- var useStyles$6 = /*#__PURE__*/core.makeStyles(function () {
8249
+ var useStyles$7 = /*#__PURE__*/core.makeStyles(function () {
8147
8250
  return {
8148
8251
  compact: {
8149
8252
  paddingRight: 0,
@@ -8155,7 +8258,7 @@ var useStyles$6 = /*#__PURE__*/core.makeStyles(function () {
8155
8258
  var omit = ['clipPos', 'flags']; // eslint-disable-next-line @typescript-eslint/no-explicit-any
8156
8259
 
8157
8260
  function AlignmentFlags(props) {
8158
- var classes = useStyles$6();
8261
+ var classes = useStyles$7();
8159
8262
  var feature = props.feature;
8160
8263
  var flags = feature.flags;
8161
8264
  var flagNames = ['read paired', 'read mapped in proper pair', 'read unmapped', 'mate unmapped', 'read reverse strand', 'mate reverse strand', 'first in pair', 'second in pair', 'not primary alignment', 'read fails platform/vendor quality checks', 'read is PCR or optical duplicate', 'supplementary alignment'];
@@ -8257,10 +8360,15 @@ function SupplementaryAlignments(props) {
8257
8360
  onClick: function onClick() {
8258
8361
  var view = model.view;
8259
8362
 
8260
- if (view) {
8261
- view.navToLocString(locString);
8262
- } else {
8263
- session.notify('No view associated with this feature detail panel anymore', 'warning');
8363
+ try {
8364
+ if (view) {
8365
+ view.navToLocString(locString);
8366
+ } else {
8367
+ throw new Error('No view associated with this view anymore');
8368
+ }
8369
+ } catch (e) {
8370
+ console.error(e);
8371
+ session.notify("".concat(e));
8264
8372
  }
8265
8373
  },
8266
8374
  href: "#"
@@ -8277,10 +8385,15 @@ function PairLink(_ref2) {
8277
8385
  onClick: function onClick() {
8278
8386
  var view = model.view;
8279
8387
 
8280
- if (view) {
8281
- view.navToLocString(locString);
8282
- } else {
8283
- session.notify('No view associated with this feature detail panel anymore', 'warning');
8388
+ try {
8389
+ if (view) {
8390
+ view.navToLocString(locString);
8391
+ } else {
8392
+ session.notify('No view associated with this feature detail panel anymore', 'warning');
8393
+ }
8394
+ } catch (e) {
8395
+ console.error(e);
8396
+ session.notify("".concat(e));
8284
8397
  }
8285
8398
  },
8286
8399
  href: "#"