@jbrowse/plugin-alignments 1.6.7 → 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 (31) hide show
  1. package/dist/BamAdapter/BamSlightlyLazyFeature.d.ts +1 -10
  2. package/dist/BamAdapter/MismatchParser.d.ts +3 -5
  3. package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +1 -2
  4. package/dist/LinearSNPCoverageDisplay/models/model.d.ts +2 -2
  5. package/dist/PileupRenderer/PileupRenderer.d.ts +20 -6
  6. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +3 -11
  7. package/dist/plugin-alignments.cjs.development.js +591 -552
  8. package/dist/plugin-alignments.cjs.development.js.map +1 -1
  9. package/dist/plugin-alignments.cjs.production.min.js +1 -1
  10. package/dist/plugin-alignments.cjs.production.min.js.map +1 -1
  11. package/dist/plugin-alignments.esm.js +594 -555
  12. package/dist/plugin-alignments.esm.js.map +1 -1
  13. package/dist/util.d.ts +4 -0
  14. package/package.json +3 -3
  15. package/src/BamAdapter/BamAdapter.ts +10 -7
  16. package/src/BamAdapter/BamSlightlyLazyFeature.ts +11 -79
  17. package/src/BamAdapter/MismatchParser.test.ts +53 -297
  18. package/src/BamAdapter/MismatchParser.ts +54 -116
  19. package/src/BamAdapter/configSchema.ts +0 -4
  20. package/src/CramAdapter/CramSlightlyLazyFeature.ts +3 -10
  21. package/src/LinearPileupDisplay/components/ColorByModifications.tsx +76 -80
  22. package/src/LinearPileupDisplay/components/ColorByTag.tsx +24 -23
  23. package/src/LinearPileupDisplay/components/FilterByTag.tsx +73 -68
  24. package/src/LinearPileupDisplay/components/SetFeatureHeight.tsx +28 -26
  25. package/src/LinearPileupDisplay/components/SetMaxHeight.tsx +24 -13
  26. package/src/LinearPileupDisplay/components/SortByTag.tsx +29 -21
  27. package/src/LinearPileupDisplay/model.ts +6 -0
  28. package/src/PileupRenderer/PileupRenderer.tsx +178 -57
  29. package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +180 -229
  30. package/src/SNPCoverageRenderer/SNPCoverageRenderer.ts +12 -11
  31. 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');
@@ -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 '';
1406
- }
1407
-
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;
1377
+ if (md) {
1378
+ mismatches = mismatches.concat(mdToMismatches(md, ops, mismatches, seq, qual));
1448
1379
  }
1449
1380
 
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,33 +1922,37 @@ 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) {
@@ -1980,15 +1987,15 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1980
1987
  });
1981
1988
  observer.complete();
1982
1989
 
1983
- case 14:
1990
+ case 16:
1984
1991
  case "end":
1985
- return _context2.stop();
1992
+ return _context3.stop();
1986
1993
  }
1987
1994
  }
1988
- }, _callee2);
1995
+ }, _callee3);
1989
1996
  }));
1990
1997
 
1991
- return function (_x) {
1998
+ return function (_x2) {
1992
1999
  return _ref.apply(this, arguments);
1993
2000
  };
1994
2001
  }(), opts.signal);
@@ -1996,30 +2003,30 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1996
2003
  }, {
1997
2004
  key: "estimateRegionsStats",
1998
2005
  value: function () {
1999
- var _estimateRegionsStats = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(regions, opts) {
2000
- var _yield$this$configure, subadapter;
2006
+ var _estimateRegionsStats = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee4(regions, opts) {
2007
+ var _yield$this$configure2, subadapter;
2001
2008
 
2002
- return runtime_1.wrap(function _callee3$(_context3) {
2009
+ return runtime_1.wrap(function _callee4$(_context4) {
2003
2010
  while (1) {
2004
- switch (_context3.prev = _context3.next) {
2011
+ switch (_context4.prev = _context4.next) {
2005
2012
  case 0:
2006
- _context3.next = 2;
2013
+ _context4.next = 2;
2007
2014
  return this.configure();
2008
2015
 
2009
2016
  case 2:
2010
- _yield$this$configure = _context3.sent;
2011
- subadapter = _yield$this$configure.subadapter;
2012
- 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));
2013
2020
 
2014
2021
  case 5:
2015
2022
  case "end":
2016
- return _context3.stop();
2023
+ return _context4.stop();
2017
2024
  }
2018
2025
  }
2019
- }, _callee3, this);
2026
+ }, _callee4, this);
2020
2027
  }));
2021
2028
 
2022
- function estimateRegionsStats(_x2, _x3) {
2029
+ function estimateRegionsStats(_x3, _x4) {
2023
2030
  return _estimateRegionsStats.apply(this, arguments);
2024
2031
  }
2025
2032
 
@@ -2028,31 +2035,31 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2028
2035
  }, {
2029
2036
  key: "getRefNames",
2030
2037
  value: function () {
2031
- var _getRefNames = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee4() {
2038
+ var _getRefNames = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee5() {
2032
2039
  var opts,
2033
- _yield$this$configure2,
2040
+ _yield$this$configure3,
2034
2041
  subadapter,
2035
- _args4 = arguments;
2042
+ _args5 = arguments;
2036
2043
 
2037
- return runtime_1.wrap(function _callee4$(_context4) {
2044
+ return runtime_1.wrap(function _callee5$(_context5) {
2038
2045
  while (1) {
2039
- switch (_context4.prev = _context4.next) {
2046
+ switch (_context5.prev = _context5.next) {
2040
2047
  case 0:
2041
- opts = _args4.length > 0 && _args4[0] !== undefined ? _args4[0] : {};
2042
- _context4.next = 3;
2048
+ opts = _args5.length > 0 && _args5[0] !== undefined ? _args5[0] : {};
2049
+ _context5.next = 3;
2043
2050
  return this.configure();
2044
2051
 
2045
2052
  case 3:
2046
- _yield$this$configure2 = _context4.sent;
2047
- subadapter = _yield$this$configure2.subadapter;
2048
- 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));
2049
2056
 
2050
2057
  case 6:
2051
2058
  case "end":
2052
- return _context4.stop();
2059
+ return _context5.stop();
2053
2060
  }
2054
2061
  }
2055
- }, _callee4, this);
2062
+ }, _callee5, this);
2056
2063
  }));
2057
2064
 
2058
2065
  function getRefNames() {
@@ -2066,69 +2073,54 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2066
2073
  value: function
2067
2074
  /* { region } */
2068
2075
  freeResources() {}
2069
- /**
2070
- * Generates coverage bins from features which details
2071
- * the reference, mismatches, strands, and coverage info
2072
- * @param features - Features of region to be passed in
2073
- * @param region - Region
2074
- * @param bpPerPx - base pairs per pixel
2075
- * @returns Array of nested frequency tables
2076
- */
2077
-
2078
2076
  }, {
2079
2077
  key: "generateCoverageBins",
2080
2078
  value: function () {
2081
- var _generateCoverageBins = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee5(features, region, opts) {
2082
- 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;
2083
2081
 
2084
- 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) {
2085
2085
  while (1) {
2086
- switch (_context5.prev = _context5.next) {
2086
+ switch (_context6.prev = _context6.next) {
2087
2087
  case 0:
2088
2088
  colorBy = opts.colorBy;
2089
- _context5.next = 3;
2090
- return this.configure();
2091
-
2092
- case 3:
2093
- _yield$this$configure3 = _context5.sent;
2094
- sequenceAdapter = _yield$this$configure3.sequenceAdapter;
2095
- originalRefName = region.originalRefName, refName = region.refName, start = region.start, end = region.end;
2096
2089
  binMax = Math.ceil(region.end - region.start);
2097
- skipmap = {}; // request an extra +1 on the end to get CpG crossing region boundary
2090
+ skipmap = {};
2098
2091
 
2099
- if (!sequenceAdapter) {
2100
- _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;
2101
2094
  break;
2102
2095
  }
2103
2096
 
2104
- _context5.next = 11;
2105
- return sequenceAdapter.getFeatures({
2106
- refName: originalRefName || refName,
2107
- start: start,
2108
- end: end + 1,
2109
- assemblyName: region.assemblyName
2110
- }).pipe(operators.toArray()).toPromise();
2097
+ _context6.next = 6;
2098
+ return this.fetchSequence(region);
2111
2099
 
2112
- case 11:
2113
- _yield$sequenceAdapte = _context5.sent;
2114
- _yield$sequenceAdapte2 = _slicedToArray(_yield$sequenceAdapte, 1);
2115
- feat = _yield$sequenceAdapte2[0];
2116
- 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;
2117
2104
 
2118
- case 15:
2119
- _context5.next = 17;
2120
- return features.pipe(operators.reduce(function (bins, feature) {
2121
- 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'));
2122
2115
  var fstart = feature.get('start');
2123
2116
  var fend = feature.get('end');
2124
2117
  var fstrand = feature.get('strand');
2125
- var cigarOps = parseCigar(cigar);
2126
2118
 
2127
- for (var j = fstart; j < fend + 1; j++) {
2128
- var i = j - region.start;
2119
+ for (var j = fstart; j < fend; j++) {
2120
+ var _i = j - region.start;
2129
2121
 
2130
- if (i >= 0 && i < binMax) {
2131
- var bin = bins[i] || {
2122
+ if (_i >= 0 && _i < binMax) {
2123
+ var bin = bins[_i] || {
2132
2124
  total: 0,
2133
2125
  lowqual: {},
2134
2126
  cov: {},
@@ -2142,30 +2134,19 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2142
2134
  inc(bin, fstrand, 'ref', 'ref');
2143
2135
  }
2144
2136
 
2145
- bins[i] = bin;
2137
+ bins[_i] = bin;
2146
2138
  }
2147
2139
  }
2148
2140
 
2149
2141
  if ((colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'modifications') {
2150
2142
  var seq = feature.get('seq');
2151
2143
  var mm = getTagAlt(feature, 'MM', 'Mm') || '';
2152
- var ml = getTagAlt(feature, 'ML', 'Ml') || [];
2153
- var probabilities = ml ? (typeof ml === 'string' ? ml.split(',').map(function (e) {
2154
- return +e;
2155
- }) : ml).map(function (e) {
2156
- return e / 255;
2157
- }) : getTagAlt(feature, 'MP', 'Mp').split('').map(function (s) {
2158
- return s.charCodeAt(0) - 33;
2159
- }).map(function (elt) {
2160
- return Math.min(1, elt / 50);
2161
- });
2162
- var probIndex = 0;
2163
2144
  getModificationPositions(mm, seq, fstrand).forEach(function (_ref4) {
2164
2145
  var type = _ref4.type,
2165
2146
  positions = _ref4.positions;
2166
2147
  var mod = "mod_".concat(type);
2167
2148
 
2168
- var _iterator = _createForOfIteratorHelper(getNextRefPos(cigarOps, positions)),
2149
+ var _iterator = _createForOfIteratorHelper(getNextRefPos(ops, positions)),
2169
2150
  _step;
2170
2151
 
2171
2152
  try {
@@ -2174,23 +2155,9 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2174
2155
  var epos = pos + fstart - region.start;
2175
2156
 
2176
2157
  if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
2177
- var _bin = bins[epos] || {
2178
- total: 0,
2179
- lowqual: {},
2180
- cov: {},
2181
- delskips: {},
2182
- noncov: {},
2183
- ref: {}
2184
- };
2185
-
2186
- if (probabilities[probIndex] > 0.5) {
2187
- inc(_bin, fstrand, 'cov', mod);
2188
- } else {
2189
- inc(_bin, fstrand, 'lowqual', mod);
2190
- }
2158
+ var _bin = bins[epos];
2159
+ inc(_bin, fstrand, 'cov', mod);
2191
2160
  }
2192
-
2193
- probIndex++;
2194
2161
  }
2195
2162
  } catch (err) {
2196
2163
  _iterator.e(err);
@@ -2216,7 +2183,7 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2216
2183
 
2217
2184
  // we are processing methylation
2218
2185
  if (type === 'm') {
2219
- var _iterator2 = _createForOfIteratorHelper(getNextRefPos(cigarOps, positions)),
2186
+ var _iterator2 = _createForOfIteratorHelper(getNextRefPos(ops, positions)),
2220
2187
  _step2;
2221
2188
 
2222
2189
  try {
@@ -2237,19 +2204,18 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2237
2204
  });
2238
2205
 
2239
2206
  for (var _j = fstart; _j < fend; _j++) {
2240
- var _i = _j - region.start;
2207
+ var _i2 = _j - region.start;
2241
2208
 
2242
- if (_i >= 0 && _i < bins.length - 1) {
2243
- var l1 = regionSeq[_i].toLowerCase();
2209
+ if (_i2 >= 0 && _i2 < bins.length - 1) {
2210
+ var l1 = regionSeq[_i2].toLowerCase();
2244
2211
 
2245
- var l2 = regionSeq[_i + 1].toLowerCase();
2212
+ var l2 = regionSeq[_i2 + 1].toLowerCase();
2246
2213
 
2247
- var _bin2 = bins[_i];
2248
- var bin1 = bins[_i + 1]; // color
2214
+ var _bin2 = bins[_i2];
2215
+ var bin1 = bins[_i2 + 1]; // color
2249
2216
 
2250
- // color
2251
2217
  if (l1 === 'c' && l2 === 'g') {
2252
- if (methBins[_i] || methBins[_i + 1]) {
2218
+ if (methBins[_i2] || methBins[_i2 + 1]) {
2253
2219
  inc(_bin2, fstrand, 'cov', 'meth');
2254
2220
  inc(bin1, fstrand, 'cov', 'meth');
2255
2221
  dec(_bin2, fstrand, 'ref', 'ref');
@@ -2268,11 +2234,11 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2268
2234
  var mismatches = feature.get('mismatches');
2269
2235
 
2270
2236
  if (mismatches) {
2271
- for (var _i2 = 0; _i2 < mismatches.length; _i2++) {
2272
- var mismatch = mismatches[_i2];
2273
- var ms = fstart + mismatch.start;
2237
+ for (var _i3 = 0; _i3 < mismatches.length; _i3++) {
2238
+ var mismatch = mismatches[_i3];
2239
+ var mstart = fstart + mismatch.start;
2274
2240
 
2275
- for (var _j2 = ms; _j2 < ms + mismatchLen(mismatch); _j2++) {
2241
+ for (var _j2 = mstart; _j2 < mstart + mismatchLen(mismatch); _j2++) {
2276
2242
  var epos = _j2 - region.start;
2277
2243
 
2278
2244
  if (epos >= 0 && epos < bins.length) {
@@ -2321,26 +2287,26 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2321
2287
  });
2322
2288
  }
2323
2289
  }
2290
+ };
2324
2291
 
2325
- return bins;
2326
- }, [])).toPromise();
2292
+ for (i = 0; i < features.length; i++) {
2293
+ _loop(i);
2294
+ }
2327
2295
 
2328
- case 17:
2329
- bins = _context5.sent;
2330
- return _context5.abrupt("return", {
2296
+ return _context6.abrupt("return", {
2331
2297
  bins: bins,
2332
2298
  skipmap: skipmap
2333
2299
  });
2334
2300
 
2335
- case 19:
2301
+ case 15:
2336
2302
  case "end":
2337
- return _context5.stop();
2303
+ return _context6.stop();
2338
2304
  }
2339
2305
  }
2340
- }, _callee5, this);
2306
+ }, _callee6, this);
2341
2307
  }));
2342
2308
 
2343
- function generateCoverageBins(_x4, _x5, _x6) {
2309
+ function generateCoverageBins(_x5, _x6, _x7) {
2344
2310
  return _generateCoverageBins.apply(this, arguments);
2345
2311
  }
2346
2312
 
@@ -2457,18 +2423,13 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2457
2423
  range: [0, height]
2458
2424
  });
2459
2425
 
2460
- var viewScale = pluginWiggle.getScale(opts);
2461
- var snpViewScale = pluginWiggle.getScale(_objectSpread2(_objectSpread2({}, opts), {}, {
2462
- range: [0, height],
2463
- scaleType: 'linear'
2464
- })); // clipping and insertion indicators, uses a smaller height/2 scale
2426
+ var viewScale = pluginWiggle.getScale(opts); // clipping and insertion indicators, uses a smaller height/2 scale
2465
2427
 
2466
2428
  var indicatorViewScale = pluginWiggle.getScale(_objectSpread2(_objectSpread2({}, opts), {}, {
2467
2429
  range: [0, height / 2],
2468
2430
  scaleType: 'linear'
2469
2431
  }));
2470
2432
  var originY = pluginWiggle.getOrigin(scaleOpts.scaleType);
2471
- var snpOriginY = pluginWiggle.getOrigin('linear');
2472
2433
  var indicatorThreshold = configuration.readConfObject(cfg, 'indicatorThreshold');
2473
2434
  var drawInterbaseCounts = configuration.readConfObject(cfg, 'drawInterbaseCounts');
2474
2435
  var drawArcs = configuration.readConfObject(cfg, 'drawArcs');
@@ -2480,23 +2441,14 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2480
2441
 
2481
2442
  var toHeight = function toHeight(n) {
2482
2443
  return toY(originY) - toY(n);
2483
- }; // this is always linear scale, even when plotted on top of log scale
2484
-
2485
-
2486
- var snpToY = function snpToY(n) {
2487
- return height - (snpViewScale(n) || 0) + offset;
2488
2444
  };
2489
2445
 
2490
2446
  var indicatorToY = function indicatorToY(n) {
2491
2447
  return height - (indicatorViewScale(n) || 0) + offset;
2492
2448
  };
2493
2449
 
2494
- var snpToHeight = function snpToHeight(n) {
2495
- return snpToY(snpOriginY) - snpToY(n);
2496
- };
2497
-
2498
2450
  var indicatorToHeight = function indicatorToHeight(n) {
2499
- return indicatorToY(snpOriginY) - indicatorToY(n);
2451
+ return indicatorToY(pluginWiggle.getOrigin('linear')) - indicatorToY(n);
2500
2452
  };
2501
2453
 
2502
2454
  var colorForBase = {
@@ -2558,6 +2510,8 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2558
2510
  _leftPx = _featureSpanPx4[0],
2559
2511
  _rightPx = _featureSpanPx4[1];
2560
2512
 
2513
+ var _score = _feature.get('score');
2514
+
2561
2515
  var snpinfo = _feature.get('snpinfo');
2562
2516
 
2563
2517
  var _w = Math.max(_rightPx - _leftPx + 0.3, 1);
@@ -2570,7 +2524,12 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2570
2524
  var base = keys[_i2];
2571
2525
  var total = snpinfo.cov[base].total;
2572
2526
  ctx.fillStyle = colorForBase[base] || modificationTagMap[base.replace('mod_', '')] || '#888';
2573
- ctx.fillRect(_leftPx, snpToY(total + curr), _w, snpToHeight(total));
2527
+
2528
+ var _height = toHeight(_score);
2529
+
2530
+ var bottom = toY(_score) + _height;
2531
+
2532
+ ctx.fillRect(_leftPx, bottom - (total + curr) / _score * _height, _w, total / _score * _height);
2574
2533
  curr += total;
2575
2534
  }
2576
2535
 
@@ -2844,6 +2803,16 @@ function getColorBaseMap(theme) {
2844
2803
  };
2845
2804
  }
2846
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
+
2847
2816
  var alignmentColoring = {
2848
2817
  color_fwd_strand_not_proper: '#ECC8C8',
2849
2818
  color_rev_strand_not_proper: '#BEBED8',
@@ -2896,14 +2865,14 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
2896
2865
  }
2897
2866
  }, {
2898
2867
  key: "layoutFeature",
2899
- value: function layoutFeature(_ref) {
2900
- var feature = _ref.feature,
2901
- layout = _ref.layout,
2902
- bpPerPx = _ref.bpPerPx,
2903
- region = _ref.region,
2904
- showSoftClip = _ref.showSoftClip,
2905
- heightPx = _ref.heightPx,
2906
- 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;
2907
2876
  var expansionBefore = 0;
2908
2877
  var expansionAfter = 0; // Expand the start and end of feature when softclipping enabled
2909
2878
 
@@ -3023,6 +2992,56 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3023
2992
 
3024
2993
  return strand === 1 ? 'color_fwd_strand' : 'color_rev_strand';
3025
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
+ }
3026
3045
  }, {
3027
3046
  key: "colorByPerBaseQuality",
3028
3047
  value: function colorByPerBaseQuality(ctx, feat, _config, region, bpPerPx) {
@@ -3036,28 +3055,32 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3036
3055
  var cigarOps = parseCigar(feature.get('CIGAR'));
3037
3056
  var width = 1 / bpPerPx;
3038
3057
  var start = feature.get('start');
3058
+ var soffset = 0; // sequence offset
3059
+
3060
+ var roffset = 0; // reference offset
3039
3061
 
3040
- for (var i = 0, j = 0, k = 0; k < scores.length; i += 2, k++) {
3062
+ for (var i = 0; i < cigarOps.length; i += 2) {
3041
3063
  var len = +cigarOps[i];
3042
3064
  var op = cigarOps[i + 1];
3043
3065
 
3044
3066
  if (op === 'S' || op === 'I') {
3045
- k += len;
3067
+ soffset += len;
3046
3068
  } else if (op === 'D' || op === 'N') {
3047
- j += len;
3069
+ roffset += len;
3048
3070
  } else if (op === 'M' || op === 'X' || op === '=') {
3049
3071
  for (var m = 0; m < len; m++) {
3050
- var score = scores[k + m];
3072
+ var score = scores[soffset + m];
3051
3073
  ctx.fillStyle = "hsl(".concat(score === 255 ? 150 : score * 1.5, ",55%,50%)");
3052
3074
 
3053
- var _bpSpanPx3 = util.bpSpanPx(start + j + m, start + j + m + 1, region, bpPerPx),
3054
- _bpSpanPx4 = _slicedToArray(_bpSpanPx3, 1),
3055
- 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];
3056
3078
 
3057
3079
  ctx.fillRect(leftPx, topPx, width + 0.5, heightPx);
3058
3080
  }
3059
3081
 
3060
- j += len;
3082
+ soffset += len;
3083
+ roffset += len;
3061
3084
  }
3062
3085
  }
3063
3086
  } // ML stores probabilities as array of numerics and MP is scaled phred scores
@@ -3114,10 +3137,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3114
3137
  var readPos = _step.value;
3115
3138
 
3116
3139
  if (readPos >= 0 && start + readPos < end) {
3117
- var _bpSpanPx5 = util.bpSpanPx(start + readPos, start + readPos + 1, region, bpPerPx),
3118
- _bpSpanPx6 = _slicedToArray(_bpSpanPx5, 2),
3119
- leftPx = _bpSpanPx6[0],
3120
- 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
3121
3144
  // invisible to avoid confusion
3122
3145
 
3123
3146
 
@@ -3134,8 +3157,8 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3134
3157
  }
3135
3158
  }
3136
3159
  } // Color by methylation is slightly modified version of color by
3137
- // modifications
3138
- //
3160
+ // modifications that focuses on CpG sites, with non-methylated CpG colored
3161
+ // blue
3139
3162
 
3140
3163
  }, {
3141
3164
  key: "colorByMethylation",
@@ -3200,10 +3223,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3200
3223
  if (l1 === 'c' && l2 === 'g') {
3201
3224
  var s = rstart + _i;
3202
3225
 
3203
- var _bpSpanPx7 = util.bpSpanPx(s, s + 2, region, bpPerPx),
3204
- _bpSpanPx8 = _slicedToArray(_bpSpanPx7, 2),
3205
- leftPx = _bpSpanPx8[0],
3206
- 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];
3207
3230
 
3208
3231
  if (methBins[_i] || methBins[_i + 1]) {
3209
3232
  ctx.fillStyle = 'red';
@@ -3219,10 +3242,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3219
3242
  if (l1 === 'c' && l2 === 'g') {
3220
3243
  var _s = rstart + _i;
3221
3244
 
3222
- var _bpSpanPx9 = util.bpSpanPx(_s, _s + 1, region, bpPerPx),
3223
- _bpSpanPx10 = _slicedToArray(_bpSpanPx9, 2),
3224
- _leftPx = _bpSpanPx10[0],
3225
- _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];
3226
3249
 
3227
3250
  if (methBins[_i]) {
3228
3251
  ctx.fillStyle = 'red';
@@ -3232,10 +3255,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3232
3255
 
3233
3256
  ctx.fillRect(_leftPx, topPx, _rightPx - _leftPx + 0.5, heightPx);
3234
3257
 
3235
- var _bpSpanPx11 = util.bpSpanPx(_s + 1, _s + 2, region, bpPerPx),
3236
- _bpSpanPx12 = _slicedToArray(_bpSpanPx11, 2),
3237
- leftPx2 = _bpSpanPx12[0],
3238
- 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];
3239
3262
 
3240
3263
  if (methBins[_i + 1]) {
3241
3264
  ctx.fillStyle = 'red';
@@ -3261,10 +3284,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3261
3284
  var _regions = _slicedToArray(regions, 1),
3262
3285
  region = _regions[0];
3263
3286
 
3264
- var _bpSpanPx13 = util.bpSpanPx(feature.get('start'), feature.get('end'), region, bpPerPx),
3265
- _bpSpanPx14 = _slicedToArray(_bpSpanPx13, 2),
3266
- leftPx = _bpSpanPx14[0],
3267
- 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];
3268
3291
 
3269
3292
  var flip = region.reversed ? -1 : 1;
3270
3293
  var strand = feature.get('strand') * flip;
@@ -3302,13 +3325,17 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3302
3325
  regions = props.regions,
3303
3326
  colorBy = props.colorBy,
3304
3327
  _props$colorTagMap = props.colorTagMap,
3305
- colorTagMap = _props$colorTagMap === void 0 ? {} : _props$colorTagMap;
3306
-
3307
- var _ref2 = colorBy || {},
3308
- _ref2$tag = _ref2.tag,
3309
- tag = _ref2$tag === void 0 ? '' : _ref2$tag,
3310
- _ref2$type = _ref2.type,
3311
- colorType = _ref2$type === void 0 ? '' : _ref2$type;
3328
+ colorTagMap = _props$colorTagMap === void 0 ? {} : _props$colorTagMap,
3329
+ colorForBase = props.colorForBase,
3330
+ contrastForBase = props.contrastForBase,
3331
+ charWidth = props.charWidth,
3332
+ charHeight = props.charHeight;
3333
+
3334
+ var _ref4 = colorBy || {},
3335
+ _ref4$tag = _ref4.tag,
3336
+ tag = _ref4$tag === void 0 ? '' : _ref4$tag,
3337
+ _ref4$type = _ref4.type,
3338
+ colorType = _ref4$type === void 0 ? '' : _ref4$type;
3312
3339
 
3313
3340
  var feature = feat.feature;
3314
3341
  var region = regions[0]; // first pass for simple color changes that change the color of the
@@ -3369,6 +3396,21 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3369
3396
  case 'insertSizeAndPairOrientation':
3370
3397
  break;
3371
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
+
3372
3414
  case 'normal':
3373
3415
  default:
3374
3416
  if (defaultColor) {
@@ -3391,6 +3433,15 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3391
3433
  this.colorByPerBaseQuality(ctx, feat, config, region, bpPerPx);
3392
3434
  break;
3393
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
+
3394
3445
  case 'modifications':
3395
3446
  this.colorByModifications(ctx, feat, config, region, bpPerPx, props);
3396
3447
  break;
@@ -3402,8 +3453,8 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3402
3453
  }
3403
3454
  }, {
3404
3455
  key: "drawMismatches",
3405
- value: function drawMismatches(ctx, feat, props, theme, colorForBase, opts) {
3406
- var minWidth = opts.minSubfeatureWidth,
3456
+ value: function drawMismatches(ctx, feat, props, opts) {
3457
+ var minSubfeatureWidth = opts.minSubfeatureWidth,
3407
3458
  largeInsertionIndicatorScale = opts.largeInsertionIndicatorScale,
3408
3459
  mismatchAlpha = opts.mismatchAlpha,
3409
3460
  _opts$drawSNPs = opts.drawSNPs,
@@ -3411,7 +3462,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3411
3462
  _opts$drawIndels = opts.drawIndels,
3412
3463
  drawIndels = _opts$drawIndels === void 0 ? true : _opts$drawIndels,
3413
3464
  charWidth = opts.charWidth,
3414
- charHeight = opts.charHeight;
3465
+ charHeight = opts.charHeight,
3466
+ colorForBase = opts.colorForBase,
3467
+ contrastForBase = opts.contrastForBase;
3415
3468
  var bpPerPx = props.bpPerPx,
3416
3469
  regions = props.regions;
3417
3470
  var heightPx = feat.heightPx,
@@ -3423,7 +3476,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3423
3476
 
3424
3477
  var start = feature.get('start');
3425
3478
  var pxPerBp = Math.min(1 / bpPerPx, 2);
3426
- var w = Math.max(minWidth, pxPerBp);
3479
+ var w = Math.max(minSubfeatureWidth, pxPerBp);
3427
3480
  var mismatches = feature.get('mismatches');
3428
3481
  var heightLim = charHeight - 2;
3429
3482
 
@@ -3448,12 +3501,12 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3448
3501
  var mlen = mismatch.length;
3449
3502
  var mbase = mismatch.base;
3450
3503
 
3451
- var _bpSpanPx15 = util.bpSpanPx(mstart, mstart + mlen, region, bpPerPx),
3452
- _bpSpanPx16 = _slicedToArray(_bpSpanPx15, 2),
3453
- leftPx = _bpSpanPx16[0],
3454
- 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];
3455
3508
 
3456
- var widthPx = Math.max(minWidth, Math.abs(leftPx - rightPx));
3509
+ var widthPx = Math.max(minSubfeatureWidth, Math.abs(leftPx - rightPx));
3457
3510
 
3458
3511
  if (mismatch.type === 'mismatch' && drawSNPs) {
3459
3512
  var baseColor = colorForBase[mismatch.base] || '#888';
@@ -3462,7 +3515,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3462
3515
 
3463
3516
  if (widthPx >= charWidth && heightPx >= heightLim) {
3464
3517
  // normal SNP coloring
3465
- ctx.fillStyle = getAlphaColor(theme.palette.getContrastText(baseColor), mismatch);
3518
+ ctx.fillStyle = getAlphaColor(contrastForBase[mismatch.base], mismatch);
3466
3519
  ctx.fillText(mbase, leftPx + (widthPx - charWidth) / 2 + 1, topPx + heightPx);
3467
3520
  }
3468
3521
  } else if (mismatch.type === 'deletion' && drawIndels) {
@@ -3470,27 +3523,24 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3470
3523
  ctx.fillStyle = _baseColor;
3471
3524
  ctx.fillRect(leftPx, topPx, widthPx, heightPx);
3472
3525
  var txt = "".concat(mismatch.length);
3473
- var rect = ctx.measureText(txt);
3526
+ var rwidth = util.measureText(txt, 10);
3474
3527
 
3475
- if (widthPx >= rect.width && heightPx >= heightLim) {
3476
- ctx.fillStyle = theme.palette.getContrastText(_baseColor);
3477
- 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);
3478
3531
  }
3479
3532
  } else if (mismatch.type === 'insertion' && drawIndels) {
3480
3533
  ctx.fillStyle = 'purple';
3481
3534
  var pos = leftPx + extraHorizontallyFlippedOffset;
3482
3535
  var len = +mismatch.base || mismatch.length;
3483
- var insW = Math.max(minWidth, Math.min(1.2, 1 / bpPerPx));
3536
+ var insW = Math.max(minSubfeatureWidth, Math.min(1.2, 1 / bpPerPx));
3484
3537
 
3485
3538
  if (len < 10) {
3486
3539
  ctx.fillRect(pos, topPx, insW, heightPx);
3487
3540
 
3488
- if (1 / bpPerPx >= charWidth) {
3541
+ if (1 / bpPerPx >= charWidth && heightPx >= heightLim) {
3489
3542
  ctx.fillRect(pos - insW, topPx, insW * 3, 1);
3490
3543
  ctx.fillRect(pos - insW, topPx + heightPx - 1, insW * 3, 1);
3491
- }
3492
-
3493
- if (1 / bpPerPx >= charWidth && heightPx >= heightLim) {
3494
3544
  ctx.fillText("(".concat(mismatch.base, ")"), pos + 3, topPx + heightPx);
3495
3545
  }
3496
3546
  }
@@ -3501,12 +3551,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3501
3551
 
3502
3552
  ctx.fillRect(_pos, topPx, w, heightPx);
3503
3553
 
3504
- if (1 / bpPerPx >= charWidth) {
3554
+ if (1 / bpPerPx >= charWidth && heightPx >= heightLim) {
3505
3555
  ctx.fillRect(_pos - w, topPx, w * 3, 1);
3506
3556
  ctx.fillRect(_pos - w, topPx + heightPx - 1, w * 3, 1);
3507
- }
3508
-
3509
- if (widthPx >= charWidth && heightPx >= heightLim) {
3510
3557
  ctx.fillText("(".concat(mismatch.base, ")"), _pos + 3, topPx + heightPx);
3511
3558
  }
3512
3559
  } else if (mismatch.type === 'skip') {
@@ -3532,9 +3579,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3532
3579
 
3533
3580
  var _mlen = _mismatch.length;
3534
3581
 
3535
- var _bpSpanPx17 = util.bpSpanPx(_mstart, _mstart + _mlen, region, bpPerPx),
3536
- _bpSpanPx18 = _slicedToArray(_bpSpanPx17, 1),
3537
- _leftPx2 = _bpSpanPx18[0];
3582
+ var _bpSpanPx19 = util.bpSpanPx(_mstart, _mstart + _mlen, region, bpPerPx),
3583
+ _bpSpanPx20 = _slicedToArray(_bpSpanPx19, 1),
3584
+ _leftPx2 = _bpSpanPx20[0];
3538
3585
 
3539
3586
  var _len = +_mismatch.base || _mismatch.length;
3540
3587
 
@@ -3545,13 +3592,12 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3545
3592
  ctx.fillStyle = 'purple';
3546
3593
  ctx.fillRect(_leftPx2 - 1, topPx, 2, heightPx);
3547
3594
  } else if (heightPx > charHeight) {
3548
- var _rect = ctx.measureText(_txt);
3549
-
3595
+ var rect = ctx.measureText(_txt);
3550
3596
  var padding = 5;
3551
3597
  ctx.fillStyle = 'purple';
3552
- 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);
3553
3599
  ctx.fillStyle = 'white';
3554
- ctx.fillText(_txt, _leftPx2 - _rect.width / 2, topPx + heightPx);
3600
+ ctx.fillText(_txt, _leftPx2 - rect.width / 2, topPx + heightPx);
3555
3601
  } else {
3556
3602
  var _padding = 2;
3557
3603
  ctx.fillStyle = 'purple';
@@ -3605,10 +3651,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3605
3651
  return;
3606
3652
  }
3607
3653
 
3608
- var _bpSpanPx19 = util.bpSpanPx(softClipStart + k, softClipStart + k + 1, region, bpPerPx),
3609
- _bpSpanPx20 = _slicedToArray(_bpSpanPx19, 2),
3610
- softClipLeftPx = _bpSpanPx20[0],
3611
- 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];
3612
3658
 
3613
3659
  var softClipWidthPx = Math.max(minFeatWidth, Math.abs(softClipLeftPx - softClipRightPx)); // Black accounts for IUPAC ambiguity code bases such as N that
3614
3660
  // show in soft clipping
@@ -3631,7 +3677,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3631
3677
  var _makeImageData = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(ctx, layoutRecords, props) {
3632
3678
  var _this2 = this;
3633
3679
 
3634
- 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;
3635
3681
 
3636
3682
  return runtime_1.wrap(function _callee$(_context) {
3637
3683
  while (1) {
@@ -3644,23 +3690,24 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3644
3690
  defaultColor = configuration.readConfObject(config, 'color') === '#f0f';
3645
3691
  theme = ui.createJBrowseTheme(configTheme);
3646
3692
  colorForBase = getColorBaseMap(theme);
3693
+ contrastForBase = getContrastBaseMap(theme);
3647
3694
 
3648
3695
  if (layout) {
3649
- _context.next = 9;
3696
+ _context.next = 10;
3650
3697
  break;
3651
3698
  }
3652
3699
 
3653
3700
  throw new Error("layout required");
3654
3701
 
3655
- case 9:
3702
+ case 10:
3656
3703
  if (layout.addRect) {
3657
- _context.next = 11;
3704
+ _context.next = 12;
3658
3705
  break;
3659
3706
  }
3660
3707
 
3661
3708
  throw new Error('invalid layout object');
3662
3709
 
3663
- case 11:
3710
+ case 12:
3664
3711
  ctx.font = 'bold 10px Courier New,monospace';
3665
3712
  _this$getCharWidthHei2 = this.getCharWidthHeight(ctx), charWidth = _this$getCharWidthHei2.charWidth, charHeight = _this$getCharWidthHei2.charHeight;
3666
3713
  layoutRecords.forEach(function (feat) {
@@ -3669,17 +3716,23 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3669
3716
  }
3670
3717
 
3671
3718
  _this2.drawAlignmentRect(ctx, feat, _objectSpread2(_objectSpread2({}, props), {}, {
3672
- defaultColor: defaultColor
3719
+ defaultColor: defaultColor,
3720
+ colorForBase: colorForBase,
3721
+ contrastForBase: contrastForBase,
3722
+ charWidth: charWidth,
3723
+ charHeight: charHeight
3673
3724
  }));
3674
3725
 
3675
- _this2.drawMismatches(ctx, feat, props, theme, colorForBase, {
3726
+ _this2.drawMismatches(ctx, feat, props, {
3676
3727
  mismatchAlpha: mismatchAlpha,
3677
3728
  drawSNPs: shouldDrawMismatches(colorBy === null || colorBy === void 0 ? void 0 : colorBy.type),
3678
3729
  drawIndels: shouldDrawMismatches(colorBy === null || colorBy === void 0 ? void 0 : colorBy.type),
3679
3730
  largeInsertionIndicatorScale: insertScale,
3680
3731
  minSubfeatureWidth: minSubfeatureWidth,
3681
3732
  charWidth: charWidth,
3682
- charHeight: charHeight
3733
+ charHeight: charHeight,
3734
+ colorForBase: colorForBase,
3735
+ contrastForBase: contrastForBase
3683
3736
  });
3684
3737
 
3685
3738
  if (showSoftClip) {
@@ -3687,7 +3740,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3687
3740
  }
3688
3741
  });
3689
3742
 
3690
- case 14:
3743
+ case 15:
3691
3744
  case "end":
3692
3745
  return _context.stop();
3693
3746
  }
@@ -3744,57 +3797,98 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3744
3797
  return layoutRecords;
3745
3798
  }
3746
3799
  }, {
3747
- key: "render",
3800
+ key: "fetchSequence",
3748
3801
  value: function () {
3749
- var _render = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(renderProps) {
3750
- var _this4 = this;
3751
-
3752
- 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;
3753
3804
 
3754
3805
  return runtime_1.wrap(function _callee2$(_context2) {
3755
3806
  while (1) {
3756
3807
  switch (_context2.prev = _context2.next) {
3757
3808
  case 0:
3758
- sessionId = renderProps.sessionId, bpPerPx = renderProps.bpPerPx, regions = renderProps.regions, adapterConfig = renderProps.adapterConfig;
3809
+ sessionId = renderProps.sessionId, regions = renderProps.regions, adapterConfig = renderProps.adapterConfig;
3759
3810
  sequenceAdapter = adapterConfig.sequenceAdapter;
3760
- _context2.next = 4;
3761
- return this.getFeatures(renderProps);
3811
+
3812
+ if (sequenceAdapter) {
3813
+ _context2.next = 4;
3814
+ break;
3815
+ }
3816
+
3817
+ return _context2.abrupt("return", undefined);
3762
3818
 
3763
3819
  case 4:
3764
- 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;
3765
3861
  layout = this.createLayoutInWorker(renderProps);
3862
+ regions = renderProps.regions, bpPerPx = renderProps.bpPerPx;
3766
3863
  layoutRecords = this.layoutFeats(_objectSpread2(_objectSpread2({}, renderProps), {}, {
3767
3864
  features: features,
3768
3865
  layout: layout
3769
3866
  }));
3770
- _regions5 = _slicedToArray(regions, 1), region = _regions5[0];
3771
- 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
3772
3869
 
3773
- if (!sequenceAdapter) {
3774
- _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;
3775
3872
  break;
3776
3873
  }
3777
3874
 
3778
- _context2.next = 12;
3779
- return dataAdapterCache.getAdapter(this.pluginManager, sessionId, sequenceAdapter);
3875
+ _context3.next = 10;
3876
+ return this.fetchSequence(renderProps);
3780
3877
 
3781
- case 12:
3782
- _yield$getAdapter = _context2.sent;
3783
- dataAdapter = _yield$getAdapter.dataAdapter;
3784
- _context2.next = 16;
3785
- return dataAdapter.getFeatures(_objectSpread2(_objectSpread2({}, region), {}, {
3786
- refName: originalRefName || refName,
3787
- end: region.end + 1
3788
- })).pipe(operators.toArray()).toPromise();
3878
+ case 10:
3879
+ _context3.t0 = _context3.sent;
3880
+ _context3.next = 14;
3881
+ break;
3789
3882
 
3790
- case 16:
3791
- feats = _context2.sent;
3792
- regionSequence = (_feats$ = feats[0]) === null || _feats$ === void 0 ? void 0 : _feats$.get('seq');
3883
+ case 13:
3884
+ _context3.t0 = undefined;
3793
3885
 
3794
- case 18:
3886
+ case 14:
3887
+ regionSequence = _context3.t0;
3888
+ end = region.end, start = region.start;
3795
3889
  width = (end - start) / bpPerPx;
3796
3890
  height = Math.max(layout.getTotalHeight(), 1);
3797
- _context2.next = 22;
3891
+ _context3.next = 20;
3798
3892
  return offscreenCanvasUtils.renderToAbstractCanvas(width, height, renderProps, function (ctx) {
3799
3893
  return _this4.makeImageData(ctx, layoutRecords, _objectSpread2(_objectSpread2({}, renderProps), {}, {
3800
3894
  layout: layout,
@@ -3803,9 +3897,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3803
3897
  }));
3804
3898
  });
3805
3899
 
3806
- case 22:
3807
- res = _context2.sent;
3808
- _context2.next = 25;
3900
+ case 20:
3901
+ res = _context3.sent;
3902
+ _context3.next = 23;
3809
3903
  return _get(_getPrototypeOf(PileupRenderer.prototype), "render", this).call(this, _objectSpread2(_objectSpread2(_objectSpread2({}, renderProps), res), {}, {
3810
3904
  features: features,
3811
3905
  layout: layout,
@@ -3813,9 +3907,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3813
3907
  width: width
3814
3908
  }));
3815
3909
 
3816
- case 25:
3817
- results = _context2.sent;
3818
- 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), {}, {
3819
3913
  features: features,
3820
3914
  layout: layout,
3821
3915
  height: height,
@@ -3823,15 +3917,15 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3823
3917
  maxHeightReached: layout.maxHeightReached
3824
3918
  }));
3825
3919
 
3826
- case 27:
3920
+ case 25:
3827
3921
  case "end":
3828
- return _context2.stop();
3922
+ return _context3.stop();
3829
3923
  }
3830
3924
  }
3831
- }, _callee2, this);
3925
+ }, _callee3, this);
3832
3926
  }));
3833
3927
 
3834
- function render(_x4) {
3928
+ function render(_x5) {
3835
3929
  return _render.apply(this, arguments);
3836
3930
  }
3837
3931
 
@@ -5360,6 +5454,13 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
5360
5454
  type: 'perBaseQuality'
5361
5455
  });
5362
5456
  }
5457
+ }, {
5458
+ label: 'Per-base lettering',
5459
+ onClick: function onClick() {
5460
+ self.setColorScheme({
5461
+ type: 'perBaseLettering'
5462
+ });
5463
+ }
5363
5464
  }, {
5364
5465
  label: 'Modifications or methylation',
5365
5466
  onClick: function onClick() {
@@ -5823,12 +5924,14 @@ var AlignmentsPlugin = /*#__PURE__*/function (_Plugin) {
5823
5924
  }(Plugin);
5824
5925
 
5825
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
5826
5929
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5827
- function CramSlightlyLazyFeature(record, store) {
5930
+ function CramSlightlyLazyFeature(record, _store) {
5828
5931
  _classCallCheck(this, CramSlightlyLazyFeature);
5829
5932
 
5830
5933
  this.record = record;
5831
- this._store = store;
5934
+ this._store = _store;
5832
5935
  }
5833
5936
 
5834
5937
  _createClass(CramSlightlyLazyFeature, [{
@@ -6071,7 +6174,7 @@ var CramSlightlyLazyFeature = /*#__PURE__*/function () {
6071
6174
  value: function tags() {
6072
6175
  var properties = Object.getOwnPropertyNames(CramSlightlyLazyFeature.prototype);
6073
6176
  return properties.filter(function (prop) {
6074
- 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';
6075
6178
  }).map(function (methodName) {
6076
6179
  return methodName.replace('_get_', '');
6077
6180
  });
@@ -6235,11 +6338,6 @@ var CramSlightlyLazyFeature = /*#__PURE__*/function () {
6235
6338
  });
6236
6339
  return mismatches;
6237
6340
  }
6238
- }, {
6239
- key: "_get_skips_and_dels",
6240
- value: function _get_skips_and_dels() {
6241
- return this._get_mismatches();
6242
- }
6243
6341
  }]);
6244
6342
 
6245
6343
  return CramSlightlyLazyFeature;
@@ -6833,13 +6931,14 @@ var CramAdapter$1 = {
6833
6931
  };
6834
6932
 
6835
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
6836
6936
  function BamSlightlyLazyFeature(record, adapter, ref) {
6837
6937
  _classCallCheck(this, BamSlightlyLazyFeature);
6838
6938
 
6839
6939
  this.record = record;
6840
6940
  this.adapter = adapter;
6841
6941
  this.ref = ref;
6842
- this.cachedMD = '';
6843
6942
  }
6844
6943
 
6845
6944
  _createClass(BamSlightlyLazyFeature, [{
@@ -6900,22 +6999,6 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6900
6999
  value: function _get_seq() {
6901
7000
  return this.record.getReadBases();
6902
7001
  }
6903
- }, {
6904
- key: "_get_MD",
6905
- value: function _get_MD() {
6906
- var md = this.record.get('MD') || this.cachedMD;
6907
-
6908
- if (!md) {
6909
- var seq = this.get('seq');
6910
-
6911
- if (seq && this.ref) {
6912
- this.cachedMD = generateMD(this.ref, this.get('seq'), this.get('CIGAR'));
6913
- return this.cachedMD;
6914
- }
6915
- }
6916
-
6917
- return md;
6918
- }
6919
7002
  }, {
6920
7003
  key: "qualRaw",
6921
7004
  value: function qualRaw() {
@@ -6929,7 +7012,7 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6929
7012
  value: function tags() {
6930
7013
  var properties = Object.getOwnPropertyNames(BamSlightlyLazyFeature.prototype);
6931
7014
  return _toConsumableArray(new Set(properties.filter(function (prop) {
6932
- 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';
6933
7016
  }).map(function (methodName) {
6934
7017
  return methodName.replace('_get_', '');
6935
7018
  }).concat(this.record._tags())));
@@ -6985,61 +7068,10 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6985
7068
  uniqueId: this.id()
6986
7069
  });
6987
7070
  }
6988
- }, {
6989
- key: "_get_skips_and_dels",
6990
- value: function _get_skips_and_dels() {
6991
- var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
6992
- cigarAttributeName: 'CIGAR'
6993
- };
6994
- var cigarAttributeName = opts.cigarAttributeName;
6995
- var mismatches = [];
6996
- var cigarOps = []; // parse the CIGAR tag if it has one
6997
-
6998
- var cigarString = this.get(cigarAttributeName);
6999
-
7000
- if (cigarString) {
7001
- cigarOps = parseCigar(cigarString);
7002
- mismatches = mismatches.concat(cigarToMismatches(cigarOps, this.get('seq'), this.qualRaw()));
7003
- }
7004
-
7005
- return mismatches;
7006
- }
7007
7071
  }, {
7008
7072
  key: "_get_mismatches",
7009
7073
  value: function _get_mismatches() {
7010
- var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
7011
- _ref$cigarAttributeNa = _ref.cigarAttributeName,
7012
- cigarAttributeName = _ref$cigarAttributeNa === void 0 ? 'CIGAR' : _ref$cigarAttributeNa,
7013
- _ref$mdAttributeName = _ref.mdAttributeName,
7014
- mdAttributeName = _ref$mdAttributeName === void 0 ? 'MD' : _ref$mdAttributeName;
7015
-
7016
- var mismatches = [];
7017
- var cigarOps = []; // parse the CIGAR tag if it has one
7018
-
7019
- var cigarString = this.get(cigarAttributeName);
7020
- var seq = this.get('seq');
7021
- var qual = this.qualRaw();
7022
-
7023
- if (cigarString) {
7024
- cigarOps = parseCigar(cigarString);
7025
- mismatches = mismatches.concat(cigarToMismatches(cigarOps, seq, qual));
7026
- } // now let's look for CRAM or MD mismatches
7027
-
7028
-
7029
- var mdString = this.get(mdAttributeName);
7030
-
7031
- if (mdString) {
7032
- mismatches = mismatches.concat(mdToMismatches(mdString, cigarOps, mismatches, seq, qual));
7033
- } // uniqify the mismatches
7034
-
7035
-
7036
- var seen = {};
7037
- return mismatches.filter(function (m) {
7038
- var key = "".concat(m.type, ",").concat(m.start, ",").concat(m.length);
7039
- var s = seen[key];
7040
- seen[key] = true;
7041
- return !s;
7042
- });
7074
+ return getMismatches(this.get('CIGAR'), this.get('MD'), this.get('seq'), this.ref, this.qualRaw());
7043
7075
  }
7044
7076
  }, {
7045
7077
  key: "_get_clipPos",
@@ -7069,7 +7101,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7069
7101
  // configure method allows derived classes to override this behavior
7070
7102
  function () {
7071
7103
  var _configure = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
7072
- var bamLocation, location, indexType, chunkSizeLimit, bam$1, adapterConfig;
7104
+ var bamLocation, location, indexType, bam$1, adapterConfig;
7073
7105
  return runtime_1.wrap(function _callee$(_context) {
7074
7106
  while (1) {
7075
7107
  switch (_context.prev = _context.next) {
@@ -7078,13 +7110,16 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7078
7110
  bamLocation = configuration.readConfObject(this.config, 'bamLocation');
7079
7111
  location = configuration.readConfObject(this.config, ['index', 'location']);
7080
7112
  indexType = configuration.readConfObject(this.config, ['index', 'indexType']);
7081
- chunkSizeLimit = configuration.readConfObject(this.config, 'chunkSizeLimit');
7082
7113
  bam$1 = new bam.BamFile({
7083
7114
  bamFilehandle: io.openLocation(bamLocation, this.pluginManager),
7084
7115
  csiFilehandle: indexType === 'CSI' ? io.openLocation(location, this.pluginManager) : undefined,
7085
7116
  baiFilehandle: indexType !== 'CSI' ? io.openLocation(location, this.pluginManager) : undefined,
7086
- chunkSizeLimit: chunkSizeLimit,
7087
- 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
7088
7123
  });
7089
7124
  adapterConfig = configuration.readConfObject(this.config, 'sequenceAdapter');
7090
7125
 
@@ -7296,7 +7331,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7296
7331
  key: "seqFetch",
7297
7332
  value: function () {
7298
7333
  var _seqFetch = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee7(refName, start, end) {
7299
- var _yield$this$configure3, sequenceAdapter, refSeqStore, features, seqChunks, trimmed, sequence;
7334
+ var _yield$this$configure3, sequenceAdapter, refSeqStore, features, seqChunks, sequence;
7300
7335
 
7301
7336
  return runtime_1.wrap(function _callee7$(_context7) {
7302
7337
  while (1) {
@@ -7337,7 +7372,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7337
7372
 
7338
7373
  case 12:
7339
7374
  seqChunks = _context7.sent;
7340
- trimmed = [];
7375
+ sequence = '';
7341
7376
  seqChunks.sort(function (a, b) {
7342
7377
  return a.get('start') - b.get('start');
7343
7378
  }).forEach(function (chunk) {
@@ -7347,21 +7382,20 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7347
7382
  var trimEnd = Math.min(end - chunkStart, chunkEnd - chunkStart);
7348
7383
  var trimLength = trimEnd - trimStart;
7349
7384
  var chunkSeq = chunk.get('seq') || chunk.get('residues');
7350
- trimmed.push(chunkSeq.substr(trimStart, trimLength));
7385
+ sequence += chunkSeq.substr(trimStart, trimLength);
7351
7386
  });
7352
- sequence = trimmed.join('');
7353
7387
 
7354
7388
  if (!(sequence.length !== end - start)) {
7355
- _context7.next = 18;
7389
+ _context7.next = 17;
7356
7390
  break;
7357
7391
  }
7358
7392
 
7359
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()));
7360
7394
 
7361
- case 18:
7395
+ case 17:
7362
7396
  return _context7.abrupt("return", sequence);
7363
7397
 
7364
- case 19:
7398
+ case 18:
7365
7399
  case "end":
7366
7400
  return _context7.stop();
7367
7401
  }
@@ -7429,7 +7463,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7429
7463
  record = _step.value;
7430
7464
  ref = void 0;
7431
7465
 
7432
- if (record.get('md')) {
7466
+ if (record.get('MD')) {
7433
7467
  _context8.next = 21;
7434
7468
  break;
7435
7469
  }
@@ -7660,14 +7694,12 @@ function ColorByTagDlg$1(props) {
7660
7694
  style: {
7661
7695
  overflowX: 'hidden'
7662
7696
  }
7663
- }, /*#__PURE__*/React__default.createElement("div", {
7664
- className: classes.root
7665
7697
  }, /*#__PURE__*/React__default.createElement(core.Typography, null, "Enter tag to color by: "), /*#__PURE__*/React__default.createElement(core.Typography, {
7666
7698
  color: "textSecondary"
7667
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, {
7668
7700
  value: tag,
7669
7701
  onChange: function onChange(event) {
7670
- setTag(event.target.value);
7702
+ return setTag(event.target.value);
7671
7703
  },
7672
7704
  placeholder: "Enter tag name",
7673
7705
  inputProps: {
@@ -7678,12 +7710,9 @@ function ColorByTagDlg$1(props) {
7678
7710
  helperText: tag.length === 2 && !validTag ? 'Not a valid tag' : '',
7679
7711
  autoComplete: "off",
7680
7712
  "data-testid": "color-tag-name"
7681
- }), /*#__PURE__*/React__default.createElement(core.Button, {
7713
+ }), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
7682
7714
  variant: "contained",
7683
7715
  color: "primary",
7684
- style: {
7685
- marginLeft: 20
7686
- },
7687
7716
  onClick: function onClick() {
7688
7717
  model.setColorScheme({
7689
7718
  type: 'tag',
@@ -7692,7 +7721,11 @@ function ColorByTagDlg$1(props) {
7692
7721
  handleClose();
7693
7722
  },
7694
7723
  disabled: !validTag
7695
- }, "Submit"))));
7724
+ }, "Submit"), /*#__PURE__*/React__default.createElement(core.Button, {
7725
+ variant: "contained",
7726
+ color: "secondary",
7727
+ onClick: handleClose
7728
+ }, "Cancel"))));
7696
7729
  }
7697
7730
 
7698
7731
  var ColorByTag = /*#__PURE__*/mobxReact.observer(ColorByTagDlg$1);
@@ -7704,9 +7737,6 @@ var ColorByTag$1 = {
7704
7737
 
7705
7738
  var useStyles$2 = /*#__PURE__*/core.makeStyles(function (theme) {
7706
7739
  return {
7707
- root: {
7708
- width: 500
7709
- },
7710
7740
  paper: {
7711
7741
  padding: theme.spacing(2),
7712
7742
  margin: theme.spacing(2)
@@ -7799,9 +7829,7 @@ function FilterByTagDlg$1(props) {
7799
7829
  onClick: handleClose
7800
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, {
7801
7831
  href: site
7802
- }, site), ' ', "for details"), /*#__PURE__*/React__default.createElement("div", {
7803
- className: classes.root
7804
- }, /*#__PURE__*/React__default.createElement(core.Paper, {
7832
+ }, site), ' ', "for details"), /*#__PURE__*/React__default.createElement(core.Paper, {
7805
7833
  className: classes.paper,
7806
7834
  variant: "outlined"
7807
7835
  }, /*#__PURE__*/React__default.createElement("div", {
@@ -7856,9 +7884,11 @@ function FilterByTagDlg$1(props) {
7856
7884
  'data-testid': 'color-tag-readname-input'
7857
7885
  },
7858
7886
  "data-testid": "color-tag-readname"
7859
- })), /*#__PURE__*/React__default.createElement(core.Button, {
7887
+ })), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
7860
7888
  variant: "contained",
7861
7889
  color: "primary",
7890
+ autoFocus: true,
7891
+ type: "submit",
7862
7892
  onClick: function onClick() {
7863
7893
  model.setFilterBy({
7864
7894
  flagInclude: flagInclude,
@@ -7871,7 +7901,13 @@ function FilterByTagDlg$1(props) {
7871
7901
  });
7872
7902
  handleClose();
7873
7903
  }
7874
- }, "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"))));
7875
7911
  }
7876
7912
 
7877
7913
  var FilterByTag = /*#__PURE__*/mobxReact.observer(FilterByTagDlg$1);
@@ -7914,12 +7950,12 @@ function SortByTagDlg$1(props) {
7914
7950
  "aria-label": "close",
7915
7951
  className: classes.closeButton,
7916
7952
  onClick: handleClose
7917
- }, /*#__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, {
7918
7954
  color: "textSecondary"
7919
7955
  }, "Examples: HP for haplotype, RG for read group, etc."), /*#__PURE__*/React__default.createElement(core.TextField, {
7920
7956
  value: tag,
7921
7957
  onChange: function onChange(event) {
7922
- setTag(event.target.value);
7958
+ return setTag(event.target.value);
7923
7959
  },
7924
7960
  placeholder: "Enter tag name",
7925
7961
  inputProps: {
@@ -7930,14 +7966,22 @@ function SortByTagDlg$1(props) {
7930
7966
  helperText: tag.length === 2 && !validTag ? 'Not a valid tag' : '',
7931
7967
  autoComplete: "off",
7932
7968
  "data-testid": "sort-tag-name"
7933
- }), /*#__PURE__*/React__default.createElement(core.Button, {
7969
+ }), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
7934
7970
  variant: "contained",
7935
7971
  color: "primary",
7972
+ type: "submit",
7973
+ autoFocus: true,
7936
7974
  onClick: function onClick() {
7937
7975
  model.setSortedBy('tag', tag);
7938
7976
  handleClose();
7939
7977
  }
7940
- }, "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"))));
7941
7985
  }
7942
7986
 
7943
7987
  var SortByTag = /*#__PURE__*/mobxReact.observer(SortByTagDlg$1);
@@ -7949,9 +7993,6 @@ var SortByTag$1 = {
7949
7993
 
7950
7994
  var useStyles$4 = /*#__PURE__*/core.makeStyles(function (theme) {
7951
7995
  return {
7952
- root: {
7953
- margin: theme.spacing(4)
7954
- },
7955
7996
  closeButton: {
7956
7997
  position: 'absolute',
7957
7998
  right: theme.spacing(1),
@@ -7985,10 +8026,9 @@ function SetFeatureHeightDlg$1(props) {
7985
8026
  }, /*#__PURE__*/React__default.createElement(core.DialogTitle, null, "Set feature height", /*#__PURE__*/React__default.createElement(core.IconButton, {
7986
8027
  className: classes.closeButton,
7987
8028
  onClick: handleClose
7988
- }, /*#__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", {
7989
- className: classes.root
7990
- }, /*#__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, {
7991
8030
  value: height,
8031
+ helperText: "Feature height",
7992
8032
  onChange: function onChange(event) {
7993
8033
  setHeight(event.target.value);
7994
8034
  }
@@ -8002,20 +8042,24 @@ function SetFeatureHeightDlg$1(props) {
8002
8042
  }
8003
8043
  }),
8004
8044
  label: "Remove spacing between features in y-direction?"
8005
- }), /*#__PURE__*/React__default.createElement(core.Button, {
8045
+ }), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
8006
8046
  variant: "contained",
8007
8047
  color: "primary",
8008
8048
  type: "submit",
8009
- style: {
8010
- marginLeft: 20
8011
- },
8049
+ autoFocus: true,
8012
8050
  disabled: !ok,
8013
8051
  onClick: function onClick() {
8014
8052
  model.setFeatureHeight(height !== '' && !Number.isNaN(+height) ? +height : undefined);
8015
8053
  model.setNoSpacing(noSpacing);
8016
8054
  handleClose();
8017
8055
  }
8018
- }, "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"))));
8019
8063
  }
8020
8064
 
8021
8065
  var SetFeatureHeight = /*#__PURE__*/mobxReact.observer(SetFeatureHeightDlg$1);
@@ -8057,32 +8101,34 @@ function SetMaxHeightDlg$1(props) {
8057
8101
  return /*#__PURE__*/React__default.createElement(core.Dialog, {
8058
8102
  open: true,
8059
8103
  onClose: handleClose
8060
- }, /*#__PURE__*/React__default.createElement(core.DialogTitle, {
8061
- id: "alert-dialog-title"
8062
- }, "Filter options", /*#__PURE__*/React__default.createElement(core.IconButton, {
8104
+ }, /*#__PURE__*/React__default.createElement(core.DialogTitle, null, "Filter options", /*#__PURE__*/React__default.createElement(core.IconButton, {
8063
8105
  "aria-label": "close",
8064
8106
  className: classes.closeButton,
8065
8107
  onClick: handleClose
8066
- }, /*#__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, {
8067
8109
  className: classes.root
8068
- }, /*#__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, {
8069
8111
  value: max,
8070
8112
  onChange: function onChange(event) {
8071
8113
  setMax(event.target.value);
8072
8114
  },
8073
8115
  placeholder: "Enter max height for layout"
8074
- }), /*#__PURE__*/React__default.createElement(core.Button, {
8116
+ }), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
8075
8117
  variant: "contained",
8076
8118
  color: "primary",
8077
8119
  type: "submit",
8078
- style: {
8079
- marginLeft: 20
8080
- },
8120
+ autoFocus: true,
8081
8121
  onClick: function onClick() {
8082
8122
  model.setMaxHeight(max !== '' && !Number.isNaN(+max) ? +max : undefined);
8083
8123
  handleClose();
8084
8124
  }
8085
- }, "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"))));
8086
8132
  }
8087
8133
 
8088
8134
  var SetMaxHeight = /*#__PURE__*/mobxReact.observer(SetMaxHeightDlg$1);
@@ -8094,7 +8140,6 @@ var SetMaxHeight$1 = {
8094
8140
 
8095
8141
  var useStyles$6 = /*#__PURE__*/core.makeStyles(function (theme) {
8096
8142
  return {
8097
- root: {},
8098
8143
  closeButton: {
8099
8144
  position: 'absolute',
8100
8145
  right: theme.spacing(1),
@@ -8148,9 +8193,7 @@ function ColorByTagDlg$2(props) {
8148
8193
  "aria-label": "close",
8149
8194
  className: classes.closeButton,
8150
8195
  onClick: handleClose
8151
- }, /*#__PURE__*/React__default.createElement(CloseIcon, null))), /*#__PURE__*/React__default.createElement(core.DialogContent, null, /*#__PURE__*/React__default.createElement("div", {
8152
- className: classes.root
8153
- }, /*#__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", {
8154
8197
  style: {
8155
8198
  margin: 20
8156
8199
  }
@@ -8160,11 +8203,7 @@ function ColorByTagDlg$2(props) {
8160
8203
  size: 15
8161
8204
  }))) : null, (colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'methylation' ? /*#__PURE__*/React__default.createElement(ModificationTable, {
8162
8205
  modifications: [['methylated', 'red'], ['unmethylated', 'blue']]
8163
- }) : null), /*#__PURE__*/React__default.createElement("div", {
8164
- style: {
8165
- display: 'flex'
8166
- }
8167
- }, /*#__PURE__*/React__default.createElement(core.Button, {
8206
+ }) : null), /*#__PURE__*/React__default.createElement(core.DialogActions, null, /*#__PURE__*/React__default.createElement(core.Button, {
8168
8207
  variant: "contained",
8169
8208
  color: "primary",
8170
8209
  style: {
@@ -8197,7 +8236,7 @@ function ColorByTagDlg$2(props) {
8197
8236
  onClick: function onClick() {
8198
8237
  return handleClose();
8199
8238
  }
8200
- }, "Cancel")))));
8239
+ }, "Cancel"))));
8201
8240
  }
8202
8241
 
8203
8242
  var ColorByModifications = /*#__PURE__*/mobxReact.observer(ColorByTagDlg$2);