@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
@@ -1,16 +1,16 @@
1
1
  import Plugin from '@jbrowse/core/Plugin';
2
- import { revcom, featureSpanPx, bpSpanPx, iterMap, getContainingTrack, getSession, getContainingView, isSessionModelWithWidgets, renameRegionsIfNeeded, checkAbortSignal, updateStatus, bytesForRegions } from '@jbrowse/core/util';
2
+ import { revcom, featureSpanPx, bpSpanPx, measureText, iterMap, getContainingTrack, getSession, getContainingView, isSessionModelWithWidgets, renameRegionsIfNeeded, checkAbortSignal, updateStatus, bytesForRegions } from '@jbrowse/core/util';
3
3
  import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType';
4
4
  import { ConfigurationSchema, readConfObject, ConfigurationReference, getConf } from '@jbrowse/core/configuration';
5
5
  import { types, addDisposer, getSnapshot, cast, getEnv } from 'mobx-state-tree';
6
6
  import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
7
7
  import SimpleFeature from '@jbrowse/core/util/simpleFeature';
8
8
  import { ObservableCreate } from '@jbrowse/core/util/rxjs';
9
- import { filter, reduce, toArray } from 'rxjs/operators';
9
+ import { toArray } from 'rxjs/operators';
10
10
  import { createJBrowseTheme, PrerenderedCanvas, ResizeHandle } from '@jbrowse/core/ui';
11
11
  import { getScale, getOrigin, WiggleBaseRenderer, YSCALEBAR_LABEL_OFFSET, WiggleRendering, Tooltip, linearWiggleDisplayModelFactory, LinearWiggleDisplayReactComponent } from '@jbrowse/plugin-wiggle';
12
- import BoxRendererType, { LayoutSession } from '@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType';
13
12
  import Color from 'color';
13
+ import BoxRendererType, { LayoutSession } from '@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType';
14
14
  import { renderToAbstractCanvas } from '@jbrowse/core/util/offscreenCanvasUtils';
15
15
  import { getAdapter } from '@jbrowse/core/data_adapters/dataAdapterCache';
16
16
  import { doesIntersect2 } from '@jbrowse/core/util/range';
@@ -21,6 +21,7 @@ import DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType';
21
21
  import { baseLinearDisplayConfigSchema, linearBasicDisplayConfigSchemaFactory, BaseLinearDisplay, BaseLinearDisplayComponent } from '@jbrowse/plugin-linear-genome-view';
22
22
  import { BaseDisplay, createBaseTrackConfig, createBaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models';
23
23
  import { autorun, when, observable } from 'mobx';
24
+ import { makeStyles, Dialog, DialogTitle, IconButton, DialogContent, Typography as Typography$1, TextField, DialogActions, Button, Link, Paper, FormControlLabel, Checkbox, CircularProgress, FormGroup } from '@material-ui/core';
24
25
  import SerializableFilterChain from '@jbrowse/core/pluggableElementTypes/renderers/util/serializableFilterChain';
25
26
  import { getRpcSessionId, getFileName, makeIndex, makeIndexType } from '@jbrowse/core/util/tracks';
26
27
  import VisibilityIcon from '@material-ui/icons/Visibility';
@@ -38,7 +39,6 @@ import RpcMethodType from '@jbrowse/core/pluggableElementTypes/RpcMethodType';
38
39
  import { IndexedCramFile, CraiIndex } from '@gmod/cram';
39
40
  import { openLocation } from '@jbrowse/core/util/io';
40
41
  import { BamFile, HtsgetFile } from '@gmod/bam';
41
- import { Dialog, DialogTitle, IconButton, DialogContent, Typography as Typography$1, TextField, Button, makeStyles, Link, Paper, FormControlLabel, Checkbox, CircularProgress, FormGroup } from '@material-ui/core';
42
42
  import CloseIcon from '@material-ui/icons/Close';
43
43
  import { FeatureDetails, BaseCard, SimpleValue } from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail';
44
44
 
@@ -1160,62 +1160,80 @@ var runtime_1 = /*#__PURE__*/createCommonjsModule(function (module) {
1160
1160
  });
1161
1161
 
1162
1162
  var _marked = /*#__PURE__*/runtime_1.mark(getNextRefPos);
1163
+ var mdRegex = /*#__PURE__*/new RegExp(/(\d+|\^[a-z]+|[a-z])/gi);
1163
1164
  function parseCigar(cigar) {
1164
1165
  return (cigar || '').split(/([MIDNSHPX=])/);
1165
1166
  }
1166
- function cigarToMismatches(ops, seq, qual) {
1167
- var currOffset = 0;
1168
- var seqOffset = 0;
1167
+ function cigarToMismatches(ops, seq, ref, qual) {
1168
+ var roffset = 0; // reference offset
1169
+
1170
+ var soffset = 0; // seq offset
1171
+
1169
1172
  var mismatches = [];
1173
+ var hasRefAndSeq = ref && seq;
1170
1174
 
1171
- for (var i = 0; i < ops.length - 1; i += 2) {
1175
+ for (var i = 0; i < ops.length; i += 2) {
1172
1176
  var len = +ops[i];
1173
1177
  var op = ops[i + 1];
1174
1178
 
1175
1179
  if (op === 'M' || op === '=' || op === 'E') {
1176
- seqOffset += len;
1180
+ if (hasRefAndSeq) {
1181
+ for (var j = 0; j < len; j++) {
1182
+ if ( // @ts-ignore in the full yarn build of the repo, this says that object is possibly undefined for some reason, ignored
1183
+ seq[soffset + j].toUpperCase() !== ref[roffset + j].toUpperCase()) {
1184
+ mismatches.push({
1185
+ start: roffset + j,
1186
+ type: 'mismatch',
1187
+ base: seq[soffset + j],
1188
+ length: 1
1189
+ });
1190
+ }
1191
+ }
1192
+ }
1193
+
1194
+ soffset += len;
1177
1195
  }
1178
1196
 
1179
1197
  if (op === 'I') {
1180
1198
  mismatches.push({
1181
- start: currOffset,
1199
+ start: roffset,
1182
1200
  type: 'insertion',
1183
1201
  base: "".concat(len),
1184
1202
  length: 0
1185
1203
  });
1186
- seqOffset += len;
1204
+ soffset += len;
1187
1205
  } else if (op === 'D') {
1188
1206
  mismatches.push({
1189
- start: currOffset,
1207
+ start: roffset,
1190
1208
  type: 'deletion',
1191
1209
  base: '*',
1192
1210
  length: len
1193
1211
  });
1194
1212
  } else if (op === 'N') {
1195
1213
  mismatches.push({
1196
- start: currOffset,
1214
+ start: roffset,
1197
1215
  type: 'skip',
1198
1216
  base: 'N',
1199
1217
  length: len
1200
1218
  });
1201
1219
  } else if (op === 'X') {
1202
- var r = seq.slice(seqOffset, seqOffset + len);
1203
- var q = (qual === null || qual === void 0 ? void 0 : qual.slice(seqOffset, seqOffset + len)) || [];
1220
+ var r = seq.slice(soffset, soffset + len);
1221
+ var q = (qual === null || qual === void 0 ? void 0 : qual.slice(soffset, soffset + len)) || [];
1204
1222
 
1205
- for (var j = 0; j < len; j++) {
1223
+ for (var _j = 0; _j < len; _j++) {
1206
1224
  mismatches.push({
1207
- start: currOffset + j,
1225
+ start: roffset + _j,
1208
1226
  type: 'mismatch',
1209
- base: r[j],
1210
- qual: q[j],
1227
+ base: r[_j],
1228
+ qual: q[_j],
1211
1229
  length: 1
1212
1230
  });
1213
1231
  }
1214
1232
 
1215
- seqOffset += len;
1233
+ soffset += len;
1216
1234
  } else if (op === 'H') {
1217
1235
  mismatches.push({
1218
- start: currOffset,
1236
+ start: roffset,
1219
1237
  type: 'hardclip',
1220
1238
  base: "H".concat(len),
1221
1239
  cliplen: len,
@@ -1223,17 +1241,17 @@ function cigarToMismatches(ops, seq, qual) {
1223
1241
  });
1224
1242
  } else if (op === 'S') {
1225
1243
  mismatches.push({
1226
- start: currOffset,
1244
+ start: roffset,
1227
1245
  type: 'softclip',
1228
1246
  base: "S".concat(len),
1229
1247
  cliplen: len,
1230
1248
  length: 1
1231
1249
  });
1232
- seqOffset += len;
1250
+ soffset += len;
1233
1251
  }
1234
1252
 
1235
1253
  if (op !== 'I' && op !== 'S' && op !== 'H') {
1236
- currOffset += len;
1254
+ roffset += len;
1237
1255
  }
1238
1256
  }
1239
1257
 
@@ -1244,7 +1262,7 @@ function cigarToMismatches(ops, seq, qual) {
1244
1262
  * @returns array of mismatches and their positions
1245
1263
  */
1246
1264
 
1247
- function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1265
+ function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
1248
1266
  var mismatchRecords = [];
1249
1267
  var curr = {
1250
1268
  start: 0,
@@ -1277,9 +1295,9 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1277
1295
  var templateOffset = lastTemplateOffset;
1278
1296
  var refOffset = lastRefOffset;
1279
1297
 
1280
- for (var i = lastCigar; i < cigarOps.length && refOffset <= refCoord; i += 2, lastCigar = i) {
1281
- var len = +cigarOps[i];
1282
- var op = cigarOps[i + 1];
1298
+ for (var i = lastCigar; i < ops.length && refOffset <= refCoord; i += 2, lastCigar = i) {
1299
+ var len = +ops[i];
1300
+ var op = ops[i + 1];
1283
1301
 
1284
1302
  if (op === 'S' || op === 'I') {
1285
1303
  templateOffset += len;
@@ -1297,7 +1315,7 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1297
1315
  } // now actually parse the MD string
1298
1316
 
1299
1317
 
1300
- var md = mdstring.match(/(\d+|\^[a-z]+|[a-z])/gi) || [];
1318
+ var md = mdstring.match(mdRegex) || [];
1301
1319
 
1302
1320
  for (var i = 0; i < md.length; i++) {
1303
1321
  var token = md[i];
@@ -1306,11 +1324,7 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1306
1324
  if (!Number.isNaN(num)) {
1307
1325
  curr.start += num;
1308
1326
  } else if (token.startsWith('^')) {
1309
- curr.length = token.length - 1;
1310
- curr.base = '*';
1311
- curr.type = 'deletion';
1312
- curr.seq = token.substring(1);
1313
- nextRecord();
1327
+ curr.start += token.length - 1;
1314
1328
  } else {
1315
1329
  // mismatch
1316
1330
  for (var j = 0; j < token.length; j += 1) {
@@ -1327,9 +1341,9 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1327
1341
  }
1328
1342
  }
1329
1343
 
1330
- var s = cigarOps ? getTemplateCoordLocal(curr.start) : curr.start;
1331
- curr.base = seq ? seq.substr(s, 1) : 'X';
1332
- var qualScore = qual === null || qual === void 0 ? void 0 : qual.slice(s, s + 1)[0];
1344
+ var s = getTemplateCoordLocal(curr.start);
1345
+ curr.base = seq[s] || 'X';
1346
+ var qualScore = qual === null || qual === void 0 ? void 0 : qual[s];
1333
1347
 
1334
1348
  if (qualScore) {
1335
1349
  curr.qual = qualScore;
@@ -1343,103 +1357,20 @@ function mdToMismatches(mdstring, cigarOps, cigarMismatches, seq, qual) {
1343
1357
 
1344
1358
  return mismatchRecords;
1345
1359
  }
1346
- function getTemplateCoord(refCoord, cigarOps) {
1347
- var templateOffset = 0;
1348
- var refOffset = 0;
1349
-
1350
- for (var i = 0; i < cigarOps.length && refOffset <= refCoord; i += 2) {
1351
- var len = +cigarOps[i];
1352
- var op = cigarOps[i + 1];
1353
-
1354
- if (op === 'S' || op === 'I') {
1355
- templateOffset += len;
1356
- } else if (op === 'D' || op === 'P') {
1357
- refOffset += len;
1358
- } else if (op !== 'H') {
1359
- templateOffset += len;
1360
- refOffset += len;
1361
- }
1362
- }
1363
-
1364
- return templateOffset - (refOffset - refCoord);
1365
- }
1366
- function getMismatches(cigarString, mdString, seq, qual) {
1360
+ function getMismatches(cigar, md, seq, ref, qual) {
1367
1361
  var mismatches = [];
1368
- var cigarOps = []; // parse the CIGAR tag if it has one
1362
+ var ops = parseCigar(cigar); // parse the CIGAR tag if it has one
1369
1363
 
1370
- if (cigarString) {
1371
- cigarOps = parseCigar(cigarString);
1372
- mismatches = mismatches.concat(cigarToMismatches(cigarOps, seq, qual));
1364
+ if (cigar) {
1365
+ mismatches = mismatches.concat(cigarToMismatches(ops, seq, ref, qual));
1373
1366
  } // now let's look for CRAM or MD mismatches
1374
1367
 
1375
1368
 
1376
- if (mdString) {
1377
- mismatches = mismatches.concat(mdToMismatches(mdString, cigarOps, mismatches, seq, qual));
1378
- } // uniqify the mismatches
1379
-
1380
-
1381
- var seen = {};
1382
- return mismatches.filter(function (m) {
1383
- var key = "".concat(m.type, ",").concat(m.start, ",").concat(m.length);
1384
- var s = seen[key];
1385
- seen[key] = true;
1386
- return !s;
1387
- });
1388
- } // adapted from minimap2 code static void write_MD_core function
1389
-
1390
- function generateMD(target, query, cigar) {
1391
- var queryOffset = 0;
1392
- var targetOffset = 0;
1393
- var lengthMD = 0;
1394
-
1395
- if (!target) {
1396
- console.warn('no ref supplied to generateMD');
1397
- return '';
1369
+ if (md) {
1370
+ mismatches = mismatches.concat(mdToMismatches(md, ops, mismatches, seq, qual));
1398
1371
  }
1399
1372
 
1400
- var cigarOps = parseCigar(cigar);
1401
- var str = '';
1402
-
1403
- for (var i = 0; i < cigarOps.length; i += 2) {
1404
- var len = +cigarOps[i];
1405
- var op = cigarOps[i + 1];
1406
-
1407
- if (op === 'M' || op === 'X' || op === '=') {
1408
- for (var j = 0; j < len; j++) {
1409
- if (query[queryOffset + j].toLowerCase() !== target[targetOffset + j].toLowerCase()) {
1410
- str += "".concat(lengthMD).concat(target[targetOffset + j].toUpperCase());
1411
- lengthMD = 0;
1412
- } else {
1413
- lengthMD++;
1414
- }
1415
- }
1416
-
1417
- queryOffset += len;
1418
- targetOffset += len;
1419
- } else if (op === 'I') {
1420
- queryOffset += len;
1421
- } else if (op === 'D') {
1422
- var tmp = '';
1423
-
1424
- for (var _j = 0; _j < len; _j++) {
1425
- tmp += target[targetOffset + _j].toUpperCase();
1426
- }
1427
-
1428
- str += "".concat(lengthMD, "^").concat(tmp);
1429
- lengthMD = 0;
1430
- targetOffset += len;
1431
- } else if (op === 'N') {
1432
- targetOffset += len;
1433
- } else if (op === 'S') {
1434
- queryOffset += len;
1435
- }
1436
- }
1437
-
1438
- if (lengthMD > 0) {
1439
- str += lengthMD;
1440
- }
1441
-
1442
- return str;
1373
+ return mismatches;
1443
1374
  } // get relative reference sequence positions for positions given relative to
1444
1375
  // the read sequence
1445
1376
 
@@ -1587,9 +1518,7 @@ var MismatchParser = {
1587
1518
  parseCigar: parseCigar,
1588
1519
  cigarToMismatches: cigarToMismatches,
1589
1520
  mdToMismatches: mdToMismatches,
1590
- getTemplateCoord: getTemplateCoord,
1591
1521
  getMismatches: getMismatches,
1592
- generateMD: generateMD,
1593
1522
  getNextRefPos: getNextRefPos,
1594
1523
  getModificationPositions: getModificationPositions,
1595
1524
  getModificationTypes: getModificationTypes
@@ -1660,10 +1589,6 @@ var configSchema = /*#__PURE__*/types.late(function () {
1660
1589
  }
1661
1590
  }
1662
1591
  }),
1663
- chunkSizeLimit: {
1664
- type: 'number',
1665
- defaultValue: 100000000
1666
- },
1667
1592
  fetchSizeLimit: {
1668
1593
  type: 'number',
1669
1594
  defaultValue: 5000000
@@ -1740,8 +1665,8 @@ var configSchemaFactory = (function (pluginManager) {
1740
1665
  });
1741
1666
  });
1742
1667
 
1743
- // get tag from BAM or CRAM feature, where CRAM uses feature.get('tags') and
1744
1668
  // BAM does not
1669
+
1745
1670
  function getTag(feature, tag) {
1746
1671
  var tags = feature.get('tags');
1747
1672
  return tags ? tags[tag] : feature.get(tag);
@@ -1785,6 +1710,43 @@ var orientationTypes = {
1785
1710
  F1F2: 'RL'
1786
1711
  }
1787
1712
  };
1713
+ function fetchSequence(_x, _x2) {
1714
+ return _fetchSequence.apply(this, arguments);
1715
+ } // has to check underlying C-G (aka CpG) on the reference sequence
1716
+
1717
+ function _fetchSequence() {
1718
+ _fetchSequence = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(region, adapter) {
1719
+ var _feats$;
1720
+
1721
+ var end, originalRefName, refName, feats;
1722
+ return runtime_1.wrap(function _callee$(_context) {
1723
+ while (1) {
1724
+ switch (_context.prev = _context.next) {
1725
+ case 0:
1726
+ end = region.end, originalRefName = region.originalRefName, refName = region.refName;
1727
+ _context.next = 3;
1728
+ return adapter.getFeatures(_objectSpread2(_objectSpread2({}, region), {}, {
1729
+ refName: originalRefName || refName,
1730
+ end: end + 1
1731
+ })).pipe(toArray()).toPromise();
1732
+
1733
+ case 3:
1734
+ feats = _context.sent;
1735
+ return _context.abrupt("return", (_feats$ = feats[0]) === null || _feats$ === void 0 ? void 0 : _feats$.get('seq'));
1736
+
1737
+ case 5:
1738
+ case "end":
1739
+ return _context.stop();
1740
+ }
1741
+ }
1742
+ }, _callee);
1743
+ }));
1744
+ return _fetchSequence.apply(this, arguments);
1745
+ }
1746
+
1747
+ function shouldFetchReferenceSequence(type) {
1748
+ return type === 'methylation';
1749
+ }
1788
1750
 
1789
1751
  function mismatchLen(mismatch) {
1790
1752
  return !isInterbase(mismatch.type) ? mismatch.length : 1;
@@ -1850,8 +1812,8 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1850
1812
  while (1) {
1851
1813
  switch (_context.prev = _context.next) {
1852
1814
  case 0:
1853
- subadapterConfig = readConfObject(this.config, 'subadapter');
1854
- sequenceConf = readConfObject(this.config, ['subadapter', 'sequenceAdapter']);
1815
+ subadapterConfig = this.getConf('subadapter');
1816
+ sequenceConf = this.getConf(['subadapter', 'sequenceAdapter']);
1855
1817
  _context.next = 4;
1856
1818
  return (_this$getSubAdapter = this.getSubAdapter) === null || _this$getSubAdapter === void 0 ? void 0 : _this$getSubAdapter.call(this, subadapterConfig);
1857
1819
 
@@ -1904,6 +1866,47 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1904
1866
 
1905
1867
  return configure;
1906
1868
  }()
1869
+ }, {
1870
+ key: "fetchSequence",
1871
+ value: function () {
1872
+ var _fetchSequence2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(region) {
1873
+ var _yield$this$configure, sequenceAdapter;
1874
+
1875
+ return runtime_1.wrap(function _callee2$(_context2) {
1876
+ while (1) {
1877
+ switch (_context2.prev = _context2.next) {
1878
+ case 0:
1879
+ _context2.next = 2;
1880
+ return this.configure();
1881
+
1882
+ case 2:
1883
+ _yield$this$configure = _context2.sent;
1884
+ sequenceAdapter = _yield$this$configure.sequenceAdapter;
1885
+
1886
+ if (sequenceAdapter) {
1887
+ _context2.next = 6;
1888
+ break;
1889
+ }
1890
+
1891
+ return _context2.abrupt("return", undefined);
1892
+
1893
+ case 6:
1894
+ return _context2.abrupt("return", fetchSequence(region, sequenceAdapter));
1895
+
1896
+ case 7:
1897
+ case "end":
1898
+ return _context2.stop();
1899
+ }
1900
+ }
1901
+ }, _callee2, this);
1902
+ }));
1903
+
1904
+ function fetchSequence$1(_x) {
1905
+ return _fetchSequence2.apply(this, arguments);
1906
+ }
1907
+
1908
+ return fetchSequence$1;
1909
+ }()
1907
1910
  }, {
1908
1911
  key: "getFeatures",
1909
1912
  value: function getFeatures(region) {
@@ -1911,48 +1914,50 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1911
1914
 
1912
1915
  var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1913
1916
  return ObservableCreate( /*#__PURE__*/function () {
1914
- var _ref = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(observer) {
1915
- var _yield$_this$configur, subadapter, stream, filters, _yield$_this$generate, bins, skipmap;
1917
+ var _ref = _asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(observer) {
1918
+ var _yield$_this$configur, subadapter, feats, filters, _yield$_this$generate, bins, skipmap;
1916
1919
 
1917
- return runtime_1.wrap(function _callee2$(_context2) {
1920
+ return runtime_1.wrap(function _callee3$(_context3) {
1918
1921
  while (1) {
1919
- switch (_context2.prev = _context2.next) {
1922
+ switch (_context3.prev = _context3.next) {
1920
1923
  case 0:
1921
- _context2.next = 2;
1924
+ _context3.next = 2;
1922
1925
  return _this.configure();
1923
1926
 
1924
1927
  case 2:
1925
- _yield$_this$configur = _context2.sent;
1928
+ _yield$_this$configur = _context3.sent;
1926
1929
  subadapter = _yield$_this$configur.subadapter;
1927
- stream = subadapter.getFeatures(region, opts);
1930
+ _context3.next = 6;
1931
+ return subadapter.getFeatures(region, opts).pipe(toArray()).toPromise();
1932
+
1933
+ case 6:
1934
+ feats = _context3.sent;
1928
1935
 
1929
1936
  if (opts.filters) {
1930
1937
  filters = opts.filters;
1931
- stream = stream.pipe(filter(function (f) {
1938
+ feats = feats.filter(function (f) {
1932
1939
  return filters.passes(f, opts);
1933
- }));
1940
+ });
1934
1941
  }
1935
1942
 
1936
- _context2.next = 8;
1937
- return _this.generateCoverageBins(stream, region, opts);
1943
+ _context3.next = 10;
1944
+ return _this.generateCoverageBins(feats, region, opts);
1938
1945
 
1939
- case 8:
1940
- _yield$_this$generate = _context2.sent;
1946
+ case 10:
1947
+ _yield$_this$generate = _context3.sent;
1941
1948
  bins = _yield$_this$generate.bins;
1942
1949
  skipmap = _yield$_this$generate.skipmap;
1943
1950
  bins.forEach(function (bin, index) {
1944
- if (bin.total) {
1945
- observer.next(new SimpleFeature({
1946
- id: "".concat(_this.id, "-").concat(region.start, "-").concat(index),
1947
- data: {
1948
- score: bin.total,
1949
- snpinfo: bin,
1950
- start: region.start + index,
1951
- end: region.start + index + 1,
1952
- refName: region.refName
1953
- }
1954
- }));
1955
- }
1951
+ observer.next(new SimpleFeature({
1952
+ id: "".concat(_this.id, "-").concat(region.start, "-").concat(index),
1953
+ data: {
1954
+ score: bin.total,
1955
+ snpinfo: bin,
1956
+ start: region.start + index,
1957
+ end: region.start + index + 1,
1958
+ refName: region.refName
1959
+ }
1960
+ }));
1956
1961
  }); // make fake features from the coverage
1957
1962
 
1958
1963
  Object.entries(skipmap).forEach(function (_ref2) {
@@ -1974,15 +1979,15 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1974
1979
  });
1975
1980
  observer.complete();
1976
1981
 
1977
- case 14:
1982
+ case 16:
1978
1983
  case "end":
1979
- return _context2.stop();
1984
+ return _context3.stop();
1980
1985
  }
1981
1986
  }
1982
- }, _callee2);
1987
+ }, _callee3);
1983
1988
  }));
1984
1989
 
1985
- return function (_x) {
1990
+ return function (_x2) {
1986
1991
  return _ref.apply(this, arguments);
1987
1992
  };
1988
1993
  }(), opts.signal);
@@ -1990,30 +1995,30 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
1990
1995
  }, {
1991
1996
  key: "estimateRegionsStats",
1992
1997
  value: function () {
1993
- var _estimateRegionsStats = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(regions, opts) {
1994
- var _yield$this$configure, subadapter;
1998
+ var _estimateRegionsStats = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee4(regions, opts) {
1999
+ var _yield$this$configure2, subadapter;
1995
2000
 
1996
- return runtime_1.wrap(function _callee3$(_context3) {
2001
+ return runtime_1.wrap(function _callee4$(_context4) {
1997
2002
  while (1) {
1998
- switch (_context3.prev = _context3.next) {
2003
+ switch (_context4.prev = _context4.next) {
1999
2004
  case 0:
2000
- _context3.next = 2;
2005
+ _context4.next = 2;
2001
2006
  return this.configure();
2002
2007
 
2003
2008
  case 2:
2004
- _yield$this$configure = _context3.sent;
2005
- subadapter = _yield$this$configure.subadapter;
2006
- return _context3.abrupt("return", subadapter.estimateRegionsStats(regions, opts));
2009
+ _yield$this$configure2 = _context4.sent;
2010
+ subadapter = _yield$this$configure2.subadapter;
2011
+ return _context4.abrupt("return", subadapter.estimateRegionsStats(regions, opts));
2007
2012
 
2008
2013
  case 5:
2009
2014
  case "end":
2010
- return _context3.stop();
2015
+ return _context4.stop();
2011
2016
  }
2012
2017
  }
2013
- }, _callee3, this);
2018
+ }, _callee4, this);
2014
2019
  }));
2015
2020
 
2016
- function estimateRegionsStats(_x2, _x3) {
2021
+ function estimateRegionsStats(_x3, _x4) {
2017
2022
  return _estimateRegionsStats.apply(this, arguments);
2018
2023
  }
2019
2024
 
@@ -2022,31 +2027,31 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2022
2027
  }, {
2023
2028
  key: "getRefNames",
2024
2029
  value: function () {
2025
- var _getRefNames = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee4() {
2030
+ var _getRefNames = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee5() {
2026
2031
  var opts,
2027
- _yield$this$configure2,
2032
+ _yield$this$configure3,
2028
2033
  subadapter,
2029
- _args4 = arguments;
2034
+ _args5 = arguments;
2030
2035
 
2031
- return runtime_1.wrap(function _callee4$(_context4) {
2036
+ return runtime_1.wrap(function _callee5$(_context5) {
2032
2037
  while (1) {
2033
- switch (_context4.prev = _context4.next) {
2038
+ switch (_context5.prev = _context5.next) {
2034
2039
  case 0:
2035
- opts = _args4.length > 0 && _args4[0] !== undefined ? _args4[0] : {};
2036
- _context4.next = 3;
2040
+ opts = _args5.length > 0 && _args5[0] !== undefined ? _args5[0] : {};
2041
+ _context5.next = 3;
2037
2042
  return this.configure();
2038
2043
 
2039
2044
  case 3:
2040
- _yield$this$configure2 = _context4.sent;
2041
- subadapter = _yield$this$configure2.subadapter;
2042
- return _context4.abrupt("return", subadapter.getRefNames(opts));
2045
+ _yield$this$configure3 = _context5.sent;
2046
+ subadapter = _yield$this$configure3.subadapter;
2047
+ return _context5.abrupt("return", subadapter.getRefNames(opts));
2043
2048
 
2044
2049
  case 6:
2045
2050
  case "end":
2046
- return _context4.stop();
2051
+ return _context5.stop();
2047
2052
  }
2048
2053
  }
2049
- }, _callee4, this);
2054
+ }, _callee5, this);
2050
2055
  }));
2051
2056
 
2052
2057
  function getRefNames() {
@@ -2060,69 +2065,54 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2060
2065
  value: function
2061
2066
  /* { region } */
2062
2067
  freeResources() {}
2063
- /**
2064
- * Generates coverage bins from features which details
2065
- * the reference, mismatches, strands, and coverage info
2066
- * @param features - Features of region to be passed in
2067
- * @param region - Region
2068
- * @param bpPerPx - base pairs per pixel
2069
- * @returns Array of nested frequency tables
2070
- */
2071
-
2072
2068
  }, {
2073
2069
  key: "generateCoverageBins",
2074
2070
  value: function () {
2075
- var _generateCoverageBins = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee5(features, region, opts) {
2076
- var colorBy, _yield$this$configure3, sequenceAdapter, originalRefName, refName, start, end, binMax, skipmap, regionSeq, _yield$sequenceAdapte, _yield$sequenceAdapte2, feat, bins;
2071
+ var _generateCoverageBins = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee6(features, region, opts) {
2072
+ var _opts$colorBy;
2077
2073
 
2078
- return runtime_1.wrap(function _callee5$(_context5) {
2074
+ var colorBy, binMax, skipmap, regionSeq, bins, _loop, i;
2075
+
2076
+ return runtime_1.wrap(function _callee6$(_context6) {
2079
2077
  while (1) {
2080
- switch (_context5.prev = _context5.next) {
2078
+ switch (_context6.prev = _context6.next) {
2081
2079
  case 0:
2082
2080
  colorBy = opts.colorBy;
2083
- _context5.next = 3;
2084
- return this.configure();
2085
-
2086
- case 3:
2087
- _yield$this$configure3 = _context5.sent;
2088
- sequenceAdapter = _yield$this$configure3.sequenceAdapter;
2089
- originalRefName = region.originalRefName, refName = region.refName, start = region.start, end = region.end;
2090
2081
  binMax = Math.ceil(region.end - region.start);
2091
- skipmap = {}; // request an extra +1 on the end to get CpG crossing region boundary
2082
+ skipmap = {};
2092
2083
 
2093
- if (!sequenceAdapter) {
2094
- _context5.next = 15;
2084
+ if (!(features.length && shouldFetchReferenceSequence((_opts$colorBy = opts.colorBy) === null || _opts$colorBy === void 0 ? void 0 : _opts$colorBy.type))) {
2085
+ _context6.next = 9;
2095
2086
  break;
2096
2087
  }
2097
2088
 
2098
- _context5.next = 11;
2099
- return sequenceAdapter.getFeatures({
2100
- refName: originalRefName || refName,
2101
- start: start,
2102
- end: end + 1,
2103
- assemblyName: region.assemblyName
2104
- }).pipe(toArray()).toPromise();
2089
+ _context6.next = 6;
2090
+ return this.fetchSequence(region);
2105
2091
 
2106
- case 11:
2107
- _yield$sequenceAdapte = _context5.sent;
2108
- _yield$sequenceAdapte2 = _slicedToArray(_yield$sequenceAdapte, 1);
2109
- feat = _yield$sequenceAdapte2[0];
2110
- regionSeq = feat === null || feat === void 0 ? void 0 : feat.get('seq');
2092
+ case 6:
2093
+ _context6.t0 = _context6.sent;
2094
+ _context6.next = 10;
2095
+ break;
2111
2096
 
2112
- case 15:
2113
- _context5.next = 17;
2114
- return features.pipe(reduce(function (bins, feature) {
2115
- var cigar = feature.get('CIGAR');
2097
+ case 9:
2098
+ _context6.t0 = undefined;
2099
+
2100
+ case 10:
2101
+ regionSeq = _context6.t0;
2102
+ bins = [];
2103
+
2104
+ _loop = function _loop(i) {
2105
+ var feature = features[i];
2106
+ var ops = parseCigar(feature.get('CIGAR'));
2116
2107
  var fstart = feature.get('start');
2117
2108
  var fend = feature.get('end');
2118
2109
  var fstrand = feature.get('strand');
2119
- var cigarOps = parseCigar(cigar);
2120
2110
 
2121
2111
  for (var j = fstart; j < fend; j++) {
2122
- var i = j - region.start;
2112
+ var _i = j - region.start;
2123
2113
 
2124
- if (i >= 0 && i < binMax) {
2125
- var bin = bins[i] || {
2114
+ if (_i >= 0 && _i < binMax) {
2115
+ var bin = bins[_i] || {
2126
2116
  total: 0,
2127
2117
  lowqual: {},
2128
2118
  cov: {},
@@ -2130,32 +2120,25 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2130
2120
  noncov: {},
2131
2121
  ref: {}
2132
2122
  };
2133
- bin.total++;
2134
- inc(bin, fstrand, 'ref', 'ref');
2135
- bins[i] = bin;
2123
+
2124
+ if (j !== fend) {
2125
+ bin.total++;
2126
+ inc(bin, fstrand, 'ref', 'ref');
2127
+ }
2128
+
2129
+ bins[_i] = bin;
2136
2130
  }
2137
2131
  }
2138
2132
 
2139
2133
  if ((colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'modifications') {
2140
2134
  var seq = feature.get('seq');
2141
2135
  var mm = getTagAlt(feature, 'MM', 'Mm') || '';
2142
- var ml = getTagAlt(feature, 'ML', 'Ml') || [];
2143
- var probabilities = ml ? (typeof ml === 'string' ? ml.split(',').map(function (e) {
2144
- return +e;
2145
- }) : ml).map(function (e) {
2146
- return e / 255;
2147
- }) : getTagAlt(feature, 'MP', 'Mp').split('').map(function (s) {
2148
- return s.charCodeAt(0) - 33;
2149
- }).map(function (elt) {
2150
- return Math.min(1, elt / 50);
2151
- });
2152
- var probIndex = 0;
2153
2136
  getModificationPositions(mm, seq, fstrand).forEach(function (_ref4) {
2154
2137
  var type = _ref4.type,
2155
2138
  positions = _ref4.positions;
2156
2139
  var mod = "mod_".concat(type);
2157
2140
 
2158
- var _iterator = _createForOfIteratorHelper(getNextRefPos(cigarOps, positions)),
2141
+ var _iterator = _createForOfIteratorHelper(getNextRefPos(ops, positions)),
2159
2142
  _step;
2160
2143
 
2161
2144
  try {
@@ -2165,15 +2148,8 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2165
2148
 
2166
2149
  if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
2167
2150
  var _bin = bins[epos];
2168
-
2169
- if (probabilities[probIndex] > 0.5) {
2170
- inc(_bin, fstrand, 'cov', mod);
2171
- } else {
2172
- inc(_bin, fstrand, 'lowqual', mod);
2173
- }
2151
+ inc(_bin, fstrand, 'cov', mod);
2174
2152
  }
2175
-
2176
- probIndex++;
2177
2153
  }
2178
2154
  } catch (err) {
2179
2155
  _iterator.e(err);
@@ -2199,7 +2175,7 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2199
2175
 
2200
2176
  // we are processing methylation
2201
2177
  if (type === 'm') {
2202
- var _iterator2 = _createForOfIteratorHelper(getNextRefPos(cigarOps, positions)),
2178
+ var _iterator2 = _createForOfIteratorHelper(getNextRefPos(ops, positions)),
2203
2179
  _step2;
2204
2180
 
2205
2181
  try {
@@ -2220,19 +2196,18 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2220
2196
  });
2221
2197
 
2222
2198
  for (var _j = fstart; _j < fend; _j++) {
2223
- var _i = _j - region.start;
2199
+ var _i2 = _j - region.start;
2224
2200
 
2225
- if (_i >= 0 && _i < bins.length - 1) {
2226
- var l1 = regionSeq[_i].toLowerCase();
2201
+ if (_i2 >= 0 && _i2 < bins.length - 1) {
2202
+ var l1 = regionSeq[_i2].toLowerCase();
2227
2203
 
2228
- var l2 = regionSeq[_i + 1].toLowerCase();
2204
+ var l2 = regionSeq[_i2 + 1].toLowerCase();
2229
2205
 
2230
- var _bin2 = bins[_i];
2231
- var bin1 = bins[_i + 1]; // color
2206
+ var _bin2 = bins[_i2];
2207
+ var bin1 = bins[_i2 + 1]; // color
2232
2208
 
2233
- // color
2234
2209
  if (l1 === 'c' && l2 === 'g') {
2235
- if (methBins[_i] || methBins[_i + 1]) {
2210
+ if (methBins[_i2] || methBins[_i2 + 1]) {
2236
2211
  inc(_bin2, fstrand, 'cov', 'meth');
2237
2212
  inc(bin1, fstrand, 'cov', 'meth');
2238
2213
  dec(_bin2, fstrand, 'ref', 'ref');
@@ -2251,8 +2226,8 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2251
2226
  var mismatches = feature.get('mismatches');
2252
2227
 
2253
2228
  if (mismatches) {
2254
- for (var _i2 = 0; _i2 < mismatches.length; _i2++) {
2255
- var mismatch = mismatches[_i2];
2229
+ for (var _i3 = 0; _i3 < mismatches.length; _i3++) {
2230
+ var mismatch = mismatches[_i3];
2256
2231
  var mstart = fstart + mismatch.start;
2257
2232
 
2258
2233
  for (var _j2 = mstart; _j2 < mstart + mismatchLen(mismatch); _j2++) {
@@ -2304,26 +2279,26 @@ var SNPCoverageAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
2304
2279
  });
2305
2280
  }
2306
2281
  }
2282
+ };
2307
2283
 
2308
- return bins;
2309
- }, [])).toPromise();
2284
+ for (i = 0; i < features.length; i++) {
2285
+ _loop(i);
2286
+ }
2310
2287
 
2311
- case 17:
2312
- bins = _context5.sent;
2313
- return _context5.abrupt("return", {
2288
+ return _context6.abrupt("return", {
2314
2289
  bins: bins,
2315
2290
  skipmap: skipmap
2316
2291
  });
2317
2292
 
2318
- case 19:
2293
+ case 15:
2319
2294
  case "end":
2320
- return _context5.stop();
2295
+ return _context6.stop();
2321
2296
  }
2322
2297
  }
2323
- }, _callee5, this);
2298
+ }, _callee6, this);
2324
2299
  }));
2325
2300
 
2326
- function generateCoverageBins(_x4, _x5, _x6) {
2301
+ function generateCoverageBins(_x5, _x6, _x7) {
2327
2302
  return _generateCoverageBins.apply(this, arguments);
2328
2303
  }
2329
2304
 
@@ -2371,7 +2346,7 @@ var ConfigSchema = /*#__PURE__*/ConfigurationSchema('SNPCoverageRenderer', {
2371
2346
  indicatorThreshold: {
2372
2347
  type: 'number',
2373
2348
  description: 'the proportion of reads containing a insertion/clip indicator',
2374
- defaultValue: 0.3
2349
+ defaultValue: 0.4
2375
2350
  },
2376
2351
  drawArcs: {
2377
2352
  type: 'boolean',
@@ -2412,12 +2387,13 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2412
2387
  regions = props.regions,
2413
2388
  bpPerPx = props.bpPerPx,
2414
2389
  displayCrossHatches = props.displayCrossHatches,
2415
- modificationTagMap = props.modificationTagMap,
2390
+ _props$modificationTa = props.modificationTagMap,
2391
+ modificationTagMap = _props$modificationTa === void 0 ? {} : _props$modificationTa,
2416
2392
  scaleOpts = props.scaleOpts,
2417
2393
  unadjustedHeight = props.height,
2418
2394
  configTheme = props.theme,
2419
2395
  cfg = props.config,
2420
- values = props.ticks.values;
2396
+ ticks = props.ticks;
2421
2397
  var theme = createJBrowseTheme(configTheme);
2422
2398
 
2423
2399
  var _regions = _slicedToArray(regions, 1),
@@ -2429,17 +2405,23 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2429
2405
 
2430
2406
  var offset = YSCALEBAR_LABEL_OFFSET;
2431
2407
  var height = unadjustedHeight - offset * 2;
2408
+ var domain = scaleOpts.domain;
2409
+
2410
+ if (!domain) {
2411
+ return;
2412
+ }
2432
2413
 
2433
2414
  var opts = _objectSpread2(_objectSpread2({}, scaleOpts), {}, {
2434
2415
  range: [0, height]
2435
2416
  });
2436
2417
 
2437
- var viewScale = getScale(opts);
2438
- var snpViewScale = getScale(_objectSpread2(_objectSpread2({}, opts), {}, {
2418
+ var viewScale = getScale(opts); // clipping and insertion indicators, uses a smaller height/2 scale
2419
+
2420
+ var indicatorViewScale = getScale(_objectSpread2(_objectSpread2({}, opts), {}, {
2421
+ range: [0, height / 2],
2439
2422
  scaleType: 'linear'
2440
2423
  }));
2441
2424
  var originY = getOrigin(scaleOpts.scaleType);
2442
- var snpOriginY = getOrigin('linear');
2443
2425
  var indicatorThreshold = readConfObject(cfg, 'indicatorThreshold');
2444
2426
  var drawInterbaseCounts = readConfObject(cfg, 'drawInterbaseCounts');
2445
2427
  var drawArcs = readConfObject(cfg, 'drawArcs');
@@ -2451,15 +2433,14 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2451
2433
 
2452
2434
  var toHeight = function toHeight(n) {
2453
2435
  return toY(originY) - toY(n);
2454
- }; // this is always linear scale, even when plotted on top of log scale
2455
-
2436
+ };
2456
2437
 
2457
- var snpToY = function snpToY(n) {
2458
- return height - (snpViewScale(n) || 0) + offset;
2438
+ var indicatorToY = function indicatorToY(n) {
2439
+ return height - (indicatorViewScale(n) || 0) + offset;
2459
2440
  };
2460
2441
 
2461
- var snpToHeight = function snpToHeight(n) {
2462
- return snpToY(snpOriginY) - snpToY(n);
2442
+ var indicatorToHeight = function indicatorToHeight(n) {
2443
+ return indicatorToY(getOrigin('linear')) - indicatorToY(n);
2463
2444
  };
2464
2445
 
2465
2446
  var colorForBase = {
@@ -2487,7 +2468,10 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2487
2468
  // bpPerPx First pass: draw the gray background
2488
2469
 
2489
2470
  ctx.fillStyle = colorForBase.total;
2490
- coverage.forEach(function (feature) {
2471
+
2472
+ for (var i = 0; i < coverage.length; i++) {
2473
+ var feature = coverage[i];
2474
+
2491
2475
  var _featureSpanPx = featureSpanPx(feature, region, bpPerPx),
2492
2476
  _featureSpanPx2 = _slicedToArray(_featureSpanPx, 2),
2493
2477
  leftPx = _featureSpanPx2[0],
@@ -2496,96 +2480,104 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2496
2480
  var w = rightPx - leftPx + 0.3;
2497
2481
  var score = feature.get('score');
2498
2482
  ctx.fillRect(leftPx, toY(score), w, toHeight(score));
2499
- });
2500
- ctx.fillStyle = 'grey';
2501
- ctx.beginPath();
2502
- ctx.lineTo(0, 0);
2503
- ctx.moveTo(0, width);
2504
- ctx.stroke(); // Second pass: draw the SNP data, and add a minimum feature width of 1px
2483
+ } // Keep track of previous total which we will use it to draw the interbase
2484
+ // indicator (if there is a sudden clip, there will be no read coverage but
2485
+ // there will be "clip" coverage) at that position beyond the read. if the
2486
+ // clip is right at a block boundary then prevTotal will not be available,
2487
+ // so this is a best attempt to plot interbase indicator at the "cliffs"
2488
+
2489
+
2490
+ var prevTotal = 0; // extraHorizontallyFlippedOffset is used to draw interbase items, which
2491
+ // are located to the left when forward and right when reversed
2492
+
2493
+ var extraHorizontallyFlippedOffset = region.reversed ? 1 / bpPerPx : 0; // Second pass: draw the SNP data, and add a minimum feature width of 1px
2505
2494
  // which can be wider than the actual bpPerPx This reduces overdrawing of
2506
2495
  // the grey background over the SNPs
2507
2496
 
2508
- coverage.forEach(function (feature) {
2509
- var _featureSpanPx3 = featureSpanPx(feature, region, bpPerPx),
2497
+ for (var _i = 0; _i < coverage.length; _i++) {
2498
+ var _feature = coverage[_i];
2499
+
2500
+ var _featureSpanPx3 = featureSpanPx(_feature, region, bpPerPx),
2510
2501
  _featureSpanPx4 = _slicedToArray(_featureSpanPx3, 2),
2511
- leftPx = _featureSpanPx4[0],
2512
- rightPx = _featureSpanPx4[1];
2502
+ _leftPx = _featureSpanPx4[0],
2503
+ _rightPx = _featureSpanPx4[1];
2504
+
2505
+ var _score = _feature.get('score');
2506
+
2507
+ var snpinfo = _feature.get('snpinfo');
2508
+
2509
+ var _w = Math.max(_rightPx - _leftPx + 0.3, 1);
2513
2510
 
2514
- var snpinfo = feature.get('snpinfo');
2515
- var w = Math.max(rightPx - leftPx + 0.3, 1);
2516
2511
  var totalScore = snpinfo.total;
2517
- Object.entries(snpinfo.cov).sort(function (_ref, _ref2) {
2518
- var _ref3 = _slicedToArray(_ref, 1),
2519
- a = _ref3[0];
2512
+ var keys = Object.keys(snpinfo.cov).sort();
2513
+ var curr = 0;
2520
2514
 
2521
- var _ref4 = _slicedToArray(_ref2, 1),
2522
- b = _ref4[0];
2515
+ for (var _i2 = 0; _i2 < keys.length; _i2++) {
2516
+ var base = keys[_i2];
2517
+ var total = snpinfo.cov[base].total;
2518
+ ctx.fillStyle = colorForBase[base] || modificationTagMap[base.replace('mod_', '')] || '#888';
2523
2519
 
2524
- if (a < b) {
2525
- return -1;
2526
- }
2520
+ var _height = toHeight(_score);
2527
2521
 
2528
- if (a > b) {
2529
- return 1;
2530
- }
2522
+ var bottom = toY(_score) + _height;
2523
+
2524
+ ctx.fillRect(_leftPx, bottom - (total + curr) / _score * _height, _w, total / _score * _height);
2525
+ curr += total;
2526
+ }
2531
2527
 
2532
- return 0;
2533
- }).reduce(function (curr, _ref5) {
2534
- var _ref6 = _slicedToArray(_ref5, 2),
2535
- base = _ref6[0],
2536
- total = _ref6[1].total;
2537
-
2538
- ctx.fillStyle = colorForBase[base] || modificationTagMap[base.replace('mod_', '')] || 'red';
2539
- ctx.fillRect(leftPx, snpToY(total + curr), w, snpToHeight(total));
2540
- return curr + total;
2541
- }, 0);
2542
- var interbaseEvents = Object.entries(snpinfo.noncov);
2528
+ var interbaseEvents = Object.keys(snpinfo.noncov);
2543
2529
  var indicatorHeight = 4.5;
2544
2530
 
2545
2531
  if (drawInterbaseCounts) {
2546
- interbaseEvents.reduce(function (curr, _ref7) {
2547
- var _ref8 = _slicedToArray(_ref7, 2),
2548
- base = _ref8[0],
2549
- total = _ref8[1].total;
2550
-
2551
- ctx.fillStyle = colorForBase[base];
2552
- ctx.fillRect(leftPx - 0.6, indicatorHeight + snpToHeight(curr), 1.2, snpToHeight(total));
2553
- return curr + total;
2554
- }, 0);
2532
+ var _curr = 0;
2533
+
2534
+ for (var _i3 = 0; _i3 < interbaseEvents.length; _i3++) {
2535
+ var _base = interbaseEvents[_i3];
2536
+ var _total = snpinfo.noncov[_base].total;
2537
+ ctx.fillStyle = colorForBase[_base];
2538
+ ctx.fillRect(_leftPx - 0.6 + extraHorizontallyFlippedOffset, indicatorHeight + indicatorToHeight(_curr), 1.2, indicatorToHeight(_total));
2539
+ _curr += _total;
2540
+ }
2555
2541
  }
2556
2542
 
2557
2543
  if (drawIndicators) {
2558
2544
  var accum = 0;
2559
2545
  var max = 0;
2560
2546
  var maxBase = '';
2561
- interbaseEvents.forEach(function (_ref9) {
2562
- var _ref10 = _slicedToArray(_ref9, 2),
2563
- base = _ref10[0],
2564
- total = _ref10[1].total;
2565
2547
 
2566
- accum += total;
2548
+ for (var _i4 = 0; _i4 < interbaseEvents.length; _i4++) {
2549
+ var _base2 = interbaseEvents[_i4];
2550
+ var _total2 = snpinfo.noncov[_base2].total;
2551
+ accum += _total2;
2567
2552
 
2568
- if (total > max) {
2569
- max = total;
2570
- maxBase = base;
2553
+ if (_total2 > max) {
2554
+ max = _total2;
2555
+ maxBase = _base2;
2571
2556
  }
2572
- }); // avoid drawing a bunch of indicators if coverage is very low e.g.
2573
- // less than 7
2557
+ } // avoid drawing a bunch of indicators if coverage is very low e.g.
2558
+ // less than 7, uses the prev total in the case of the "cliff"
2559
+
2560
+
2561
+ var indicatorComparatorScore = Math.max(totalScore, prevTotal);
2574
2562
 
2575
- if (accum > totalScore * indicatorThreshold && totalScore > 7) {
2563
+ if (accum > indicatorComparatorScore * indicatorThreshold && indicatorComparatorScore > 7) {
2576
2564
  ctx.fillStyle = colorForBase[maxBase];
2577
2565
  ctx.beginPath();
2578
- ctx.moveTo(leftPx - 3, 0);
2579
- ctx.lineTo(leftPx + 3, 0);
2580
- ctx.lineTo(leftPx, indicatorHeight);
2566
+ var l = _leftPx + extraHorizontallyFlippedOffset;
2567
+ ctx.moveTo(l - 3.5, 0);
2568
+ ctx.lineTo(l + 3.5, 0);
2569
+ ctx.lineTo(l, indicatorHeight);
2581
2570
  ctx.fill();
2582
2571
  }
2583
2572
  }
2584
- });
2585
- ctx.globalAlpha = 0.7;
2573
+
2574
+ prevTotal = totalScore;
2575
+ }
2586
2576
 
2587
2577
  if (drawArcs) {
2588
- skips.forEach(function (f) {
2578
+ for (var _i5 = 0; _i5 < skips.length; _i5++) {
2579
+ var f = skips[_i5];
2580
+
2589
2581
  var _bpSpanPx = bpSpanPx(f.get('start'), f.get('end'), region, bpPerPx),
2590
2582
  _bpSpanPx2 = _slicedToArray(_bpSpanPx, 2),
2591
2583
  left = _bpSpanPx2[0],
@@ -2594,9 +2586,9 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2594
2586
  ctx.beginPath();
2595
2587
  var str = f.get('strand');
2596
2588
  var xs = f.get('xs');
2597
- var pos = 'rgb(255,200,200)';
2598
- var neg = 'rgb(200,200,255)';
2599
- var neutral = 'rgb(200,200,200)';
2589
+ var pos = 'rgba(255,200,200,0.7)';
2590
+ var neg = 'rgba(200,200,255,0.7)';
2591
+ var neutral = 'rgba(200,200,200,0.7)';
2600
2592
 
2601
2593
  if (xs === '+') {
2602
2594
  ctx.strokeStyle = pos;
@@ -2614,13 +2606,13 @@ var SNPCoverageRenderer = /*#__PURE__*/function (_WiggleBaseRenderer) {
2614
2606
  ctx.moveTo(left, height - offset * 2);
2615
2607
  ctx.bezierCurveTo(left, 0, right, 0, right, height - offset * 2);
2616
2608
  ctx.stroke();
2617
- });
2609
+ }
2618
2610
  }
2619
2611
 
2620
2612
  if (displayCrossHatches) {
2621
2613
  ctx.lineWidth = 1;
2622
2614
  ctx.strokeStyle = 'rgba(140,140,140,0.8)';
2623
- values.forEach(function (tick) {
2615
+ ticks.values.forEach(function (tick) {
2624
2616
  ctx.beginPath();
2625
2617
  ctx.moveTo(0, Math.round(toY(tick)));
2626
2618
  ctx.lineTo(width, Math.round(toY(tick)));
@@ -2803,6 +2795,16 @@ function getColorBaseMap(theme) {
2803
2795
  };
2804
2796
  }
2805
2797
 
2798
+ function getContrastBaseMap(theme) {
2799
+ return Object.fromEntries(Object.entries(getColorBaseMap(theme)).map(function (_ref) {
2800
+ var _ref2 = _slicedToArray(_ref, 2),
2801
+ key = _ref2[0],
2802
+ value = _ref2[1];
2803
+
2804
+ return [key, theme.palette.getContrastText(value)];
2805
+ }));
2806
+ }
2807
+
2806
2808
  var alignmentColoring = {
2807
2809
  color_fwd_strand_not_proper: '#ECC8C8',
2808
2810
  color_rev_strand_not_proper: '#BEBED8',
@@ -2855,14 +2857,14 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
2855
2857
  }
2856
2858
  }, {
2857
2859
  key: "layoutFeature",
2858
- value: function layoutFeature(_ref) {
2859
- var feature = _ref.feature,
2860
- layout = _ref.layout,
2861
- bpPerPx = _ref.bpPerPx,
2862
- region = _ref.region,
2863
- showSoftClip = _ref.showSoftClip,
2864
- heightPx = _ref.heightPx,
2865
- displayMode = _ref.displayMode;
2860
+ value: function layoutFeature(_ref3) {
2861
+ var feature = _ref3.feature,
2862
+ layout = _ref3.layout,
2863
+ bpPerPx = _ref3.bpPerPx,
2864
+ region = _ref3.region,
2865
+ showSoftClip = _ref3.showSoftClip,
2866
+ heightPx = _ref3.heightPx,
2867
+ displayMode = _ref3.displayMode;
2866
2868
  var expansionBefore = 0;
2867
2869
  var expansionAfter = 0; // Expand the start and end of feature when softclipping enabled
2868
2870
 
@@ -2982,6 +2984,56 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
2982
2984
 
2983
2985
  return strand === 1 ? 'color_fwd_strand' : 'color_rev_strand';
2984
2986
  }
2987
+ }, {
2988
+ key: "colorByPerBaseLettering",
2989
+ value: function colorByPerBaseLettering(ctx, feat, _config, region, bpPerPx, props) {
2990
+ var colorForBase = props.colorForBase,
2991
+ contrastForBase = props.contrastForBase,
2992
+ charWidth = props.charWidth,
2993
+ charHeight = props.charHeight;
2994
+ var heightLim = charHeight - 2;
2995
+ var feature = feat.feature,
2996
+ topPx = feat.topPx,
2997
+ heightPx = feat.heightPx;
2998
+ var seq = feature.get('seq');
2999
+ var cigarOps = parseCigar(feature.get('CIGAR'));
3000
+ var widthPx = 1 / bpPerPx;
3001
+ var start = feature.get('start');
3002
+ var soffset = 0; // sequence offset
3003
+
3004
+ var roffset = 0; // reference offset
3005
+
3006
+ for (var i = 0; i < cigarOps.length; i += 2) {
3007
+ var len = +cigarOps[i];
3008
+ var op = cigarOps[i + 1];
3009
+
3010
+ if (op === 'S' || op === 'I') {
3011
+ soffset += len;
3012
+ } else if (op === 'D' || op === 'N') {
3013
+ roffset += len;
3014
+ } else if (op === 'M' || op === 'X' || op === '=') {
3015
+ for (var m = 0; m < len; m++) {
3016
+ var letter = seq[soffset + m];
3017
+ ctx.fillStyle = colorForBase[letter];
3018
+
3019
+ var _bpSpanPx3 = bpSpanPx(start + roffset + m, start + roffset + m + 1, region, bpPerPx),
3020
+ _bpSpanPx4 = _slicedToArray(_bpSpanPx3, 1),
3021
+ leftPx = _bpSpanPx4[0];
3022
+
3023
+ ctx.fillRect(leftPx, topPx, widthPx + 0.5, heightPx);
3024
+
3025
+ if (widthPx >= charWidth && heightPx >= heightLim) {
3026
+ // normal SNP coloring
3027
+ ctx.fillStyle = contrastForBase[letter];
3028
+ ctx.fillText(letter, leftPx + (widthPx - charWidth) / 2 + 1, topPx + heightPx);
3029
+ }
3030
+ }
3031
+
3032
+ soffset += len;
3033
+ roffset += len;
3034
+ }
3035
+ }
3036
+ }
2985
3037
  }, {
2986
3038
  key: "colorByPerBaseQuality",
2987
3039
  value: function colorByPerBaseQuality(ctx, feat, _config, region, bpPerPx) {
@@ -2995,28 +3047,32 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
2995
3047
  var cigarOps = parseCigar(feature.get('CIGAR'));
2996
3048
  var width = 1 / bpPerPx;
2997
3049
  var start = feature.get('start');
3050
+ var soffset = 0; // sequence offset
2998
3051
 
2999
- for (var i = 0, j = 0, k = 0; k < scores.length; i += 2, k++) {
3052
+ var roffset = 0; // reference offset
3053
+
3054
+ for (var i = 0; i < cigarOps.length; i += 2) {
3000
3055
  var len = +cigarOps[i];
3001
3056
  var op = cigarOps[i + 1];
3002
3057
 
3003
3058
  if (op === 'S' || op === 'I') {
3004
- k += len;
3059
+ soffset += len;
3005
3060
  } else if (op === 'D' || op === 'N') {
3006
- j += len;
3061
+ roffset += len;
3007
3062
  } else if (op === 'M' || op === 'X' || op === '=') {
3008
3063
  for (var m = 0; m < len; m++) {
3009
- var score = scores[k + m];
3064
+ var score = scores[soffset + m];
3010
3065
  ctx.fillStyle = "hsl(".concat(score === 255 ? 150 : score * 1.5, ",55%,50%)");
3011
3066
 
3012
- var _bpSpanPx3 = bpSpanPx(start + j + m, start + j + m + 1, region, bpPerPx),
3013
- _bpSpanPx4 = _slicedToArray(_bpSpanPx3, 1),
3014
- leftPx = _bpSpanPx4[0];
3067
+ var _bpSpanPx5 = bpSpanPx(start + roffset + m, start + roffset + m + 1, region, bpPerPx),
3068
+ _bpSpanPx6 = _slicedToArray(_bpSpanPx5, 1),
3069
+ leftPx = _bpSpanPx6[0];
3015
3070
 
3016
3071
  ctx.fillRect(leftPx, topPx, width + 0.5, heightPx);
3017
3072
  }
3018
3073
 
3019
- j += len;
3074
+ soffset += len;
3075
+ roffset += len;
3020
3076
  }
3021
3077
  }
3022
3078
  } // ML stores probabilities as array of numerics and MP is scaled phred scores
@@ -3057,9 +3113,11 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3057
3113
  var modifications = getModificationPositions(mm, seq, strand); // probIndex applies across multiple modifications e.g.
3058
3114
 
3059
3115
  var probIndex = 0;
3060
- modifications.forEach(function (_ref2) {
3061
- var type = _ref2.type,
3062
- positions = _ref2.positions;
3116
+
3117
+ for (var i = 0; i < modifications.length; i++) {
3118
+ var _modifications$i = modifications[i],
3119
+ type = _modifications$i.type,
3120
+ positions = _modifications$i.positions;
3063
3121
  var col = modificationTagMap[type] || 'black';
3064
3122
  var base = Color(col);
3065
3123
 
@@ -3071,10 +3129,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3071
3129
  var readPos = _step.value;
3072
3130
 
3073
3131
  if (readPos >= 0 && start + readPos < end) {
3074
- var _bpSpanPx5 = bpSpanPx(start + readPos, start + readPos + 1, region, bpPerPx),
3075
- _bpSpanPx6 = _slicedToArray(_bpSpanPx5, 2),
3076
- leftPx = _bpSpanPx6[0],
3077
- rightPx = _bpSpanPx6[1]; // give it a little boost of 0.1 to not make them fully
3132
+ var _bpSpanPx7 = bpSpanPx(start + readPos, start + readPos + 1, region, bpPerPx),
3133
+ _bpSpanPx8 = _slicedToArray(_bpSpanPx7, 2),
3134
+ leftPx = _bpSpanPx8[0],
3135
+ rightPx = _bpSpanPx8[1]; // give it a little boost of 0.1 to not make them fully
3078
3136
  // invisible to avoid confusion
3079
3137
 
3080
3138
 
@@ -3089,10 +3147,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3089
3147
  } finally {
3090
3148
  _iterator.f();
3091
3149
  }
3092
- });
3150
+ }
3093
3151
  } // Color by methylation is slightly modified version of color by
3094
- // modifications
3095
- //
3152
+ // modifications that focuses on CpG sites, with non-methylated CpG colored
3153
+ // blue
3096
3154
 
3097
3155
  }, {
3098
3156
  key: "colorByMethylation",
@@ -3116,9 +3174,12 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3116
3174
  var rstart = region.start,
3117
3175
  rend = region.end;
3118
3176
  var methBins = new Array(rend - rstart).fill(0);
3119
- getModificationPositions(mm, seq, strand).forEach(function (_ref3) {
3120
- var type = _ref3.type,
3121
- positions = _ref3.positions;
3177
+ var modifications = getModificationPositions(mm, seq, strand);
3178
+
3179
+ for (var i = 0; i < modifications.length; i++) {
3180
+ var _modifications$i2 = modifications[i],
3181
+ type = _modifications$i2.type,
3182
+ positions = _modifications$i2.positions;
3122
3183
 
3123
3184
  if (type === 'm' && positions) {
3124
3185
  var _iterator2 = _createForOfIteratorHelper(getNextRefPos(cigarOps, positions)),
@@ -3139,25 +3200,27 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3139
3200
  _iterator2.f();
3140
3201
  }
3141
3202
  }
3142
- });
3203
+ }
3143
3204
 
3144
3205
  for (var j = fstart; j < fend; j++) {
3145
- var i = j - rstart;
3206
+ var _i = j - rstart;
3207
+
3208
+ if (_i >= 0 && _i < methBins.length) {
3209
+ var l1 = regionSequence[_i].toLowerCase();
3210
+
3211
+ var l2 = regionSequence[_i + 1].toLowerCase(); // if we are zoomed out, display just a block over the cpg
3146
3212
 
3147
- if (i >= 0 && i < methBins.length) {
3148
- var l1 = regionSequence[i].toLowerCase();
3149
- var l2 = regionSequence[i + 1].toLowerCase(); // if we are zoomed out, display just a block over the cpg
3150
3213
 
3151
3214
  if (bpPerPx > 2) {
3152
3215
  if (l1 === 'c' && l2 === 'g') {
3153
- var s = rstart + i;
3216
+ var s = rstart + _i;
3154
3217
 
3155
- var _bpSpanPx7 = bpSpanPx(s, s + 2, region, bpPerPx),
3156
- _bpSpanPx8 = _slicedToArray(_bpSpanPx7, 2),
3157
- leftPx = _bpSpanPx8[0],
3158
- rightPx = _bpSpanPx8[1];
3218
+ var _bpSpanPx9 = bpSpanPx(s, s + 2, region, bpPerPx),
3219
+ _bpSpanPx10 = _slicedToArray(_bpSpanPx9, 2),
3220
+ leftPx = _bpSpanPx10[0],
3221
+ rightPx = _bpSpanPx10[1];
3159
3222
 
3160
- if (methBins[i] || methBins[i + 1]) {
3223
+ if (methBins[_i] || methBins[_i + 1]) {
3161
3224
  ctx.fillStyle = 'red';
3162
3225
  } else {
3163
3226
  ctx.fillStyle = 'blue';
@@ -3169,14 +3232,14 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3169
3232
  else {
3170
3233
  // color
3171
3234
  if (l1 === 'c' && l2 === 'g') {
3172
- var _s = rstart + i;
3235
+ var _s = rstart + _i;
3173
3236
 
3174
- var _bpSpanPx9 = bpSpanPx(_s, _s + 1, region, bpPerPx),
3175
- _bpSpanPx10 = _slicedToArray(_bpSpanPx9, 2),
3176
- _leftPx = _bpSpanPx10[0],
3177
- _rightPx = _bpSpanPx10[1];
3237
+ var _bpSpanPx11 = bpSpanPx(_s, _s + 1, region, bpPerPx),
3238
+ _bpSpanPx12 = _slicedToArray(_bpSpanPx11, 2),
3239
+ _leftPx = _bpSpanPx12[0],
3240
+ _rightPx = _bpSpanPx12[1];
3178
3241
 
3179
- if (methBins[i]) {
3242
+ if (methBins[_i]) {
3180
3243
  ctx.fillStyle = 'red';
3181
3244
  } else {
3182
3245
  ctx.fillStyle = 'blue';
@@ -3184,12 +3247,12 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3184
3247
 
3185
3248
  ctx.fillRect(_leftPx, topPx, _rightPx - _leftPx + 0.5, heightPx);
3186
3249
 
3187
- var _bpSpanPx11 = bpSpanPx(_s + 1, _s + 2, region, bpPerPx),
3188
- _bpSpanPx12 = _slicedToArray(_bpSpanPx11, 2),
3189
- leftPx2 = _bpSpanPx12[0],
3190
- rightPx2 = _bpSpanPx12[1];
3250
+ var _bpSpanPx13 = bpSpanPx(_s + 1, _s + 2, region, bpPerPx),
3251
+ _bpSpanPx14 = _slicedToArray(_bpSpanPx13, 2),
3252
+ leftPx2 = _bpSpanPx14[0],
3253
+ rightPx2 = _bpSpanPx14[1];
3191
3254
 
3192
- if (methBins[i + 1]) {
3255
+ if (methBins[_i + 1]) {
3193
3256
  ctx.fillStyle = 'red';
3194
3257
  } else {
3195
3258
  ctx.fillStyle = 'blue';
@@ -3213,10 +3276,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3213
3276
  var _regions = _slicedToArray(regions, 1),
3214
3277
  region = _regions[0];
3215
3278
 
3216
- var _bpSpanPx13 = bpSpanPx(feature.get('start'), feature.get('end'), region, bpPerPx),
3217
- _bpSpanPx14 = _slicedToArray(_bpSpanPx13, 2),
3218
- leftPx = _bpSpanPx14[0],
3219
- rightPx = _bpSpanPx14[1];
3279
+ var _bpSpanPx15 = bpSpanPx(feature.get('start'), feature.get('end'), region, bpPerPx),
3280
+ _bpSpanPx16 = _slicedToArray(_bpSpanPx15, 2),
3281
+ leftPx = _bpSpanPx16[0],
3282
+ rightPx = _bpSpanPx16[1];
3220
3283
 
3221
3284
  var flip = region.reversed ? -1 : 1;
3222
3285
  var strand = feature.get('strand') * flip;
@@ -3254,7 +3317,11 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3254
3317
  regions = props.regions,
3255
3318
  colorBy = props.colorBy,
3256
3319
  _props$colorTagMap = props.colorTagMap,
3257
- colorTagMap = _props$colorTagMap === void 0 ? {} : _props$colorTagMap;
3320
+ colorTagMap = _props$colorTagMap === void 0 ? {} : _props$colorTagMap,
3321
+ colorForBase = props.colorForBase,
3322
+ contrastForBase = props.contrastForBase,
3323
+ charWidth = props.charWidth,
3324
+ charHeight = props.charHeight;
3258
3325
 
3259
3326
  var _ref4 = colorBy || {},
3260
3327
  _ref4$tag = _ref4.tag,
@@ -3321,6 +3388,21 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3321
3388
  case 'insertSizeAndPairOrientation':
3322
3389
  break;
3323
3390
 
3391
+ case 'modifications':
3392
+ case 'methylation':
3393
+ // this coloring is similar to igv.js, and is helpful to color negative
3394
+ // strand reads differently because their c-g will be flipped (e.g. g-c
3395
+ // read right to left)
3396
+ var flags = feature.get('flags');
3397
+
3398
+ if (flags & 16) {
3399
+ ctx.fillStyle = '#c8dcc8';
3400
+ } else {
3401
+ ctx.fillStyle = '#c8c8c8';
3402
+ }
3403
+
3404
+ break;
3405
+
3324
3406
  case 'normal':
3325
3407
  default:
3326
3408
  if (defaultColor) {
@@ -3343,6 +3425,15 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3343
3425
  this.colorByPerBaseQuality(ctx, feat, config, region, bpPerPx);
3344
3426
  break;
3345
3427
 
3428
+ case 'perBaseLettering':
3429
+ this.colorByPerBaseLettering(ctx, feat, config, region, bpPerPx, {
3430
+ colorForBase: colorForBase,
3431
+ contrastForBase: contrastForBase,
3432
+ charWidth: charWidth,
3433
+ charHeight: charHeight
3434
+ });
3435
+ break;
3436
+
3346
3437
  case 'modifications':
3347
3438
  this.colorByModifications(ctx, feat, config, region, bpPerPx, props);
3348
3439
  break;
@@ -3354,8 +3445,8 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3354
3445
  }
3355
3446
  }, {
3356
3447
  key: "drawMismatches",
3357
- value: function drawMismatches(ctx, feat, props, theme, colorForBase, opts) {
3358
- var minWidth = opts.minSubfeatureWidth,
3448
+ value: function drawMismatches(ctx, feat, props, opts) {
3449
+ var minSubfeatureWidth = opts.minSubfeatureWidth,
3359
3450
  largeInsertionIndicatorScale = opts.largeInsertionIndicatorScale,
3360
3451
  mismatchAlpha = opts.mismatchAlpha,
3361
3452
  _opts$drawSNPs = opts.drawSNPs,
@@ -3363,7 +3454,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3363
3454
  _opts$drawIndels = opts.drawIndels,
3364
3455
  drawIndels = _opts$drawIndels === void 0 ? true : _opts$drawIndels,
3365
3456
  charWidth = opts.charWidth,
3366
- charHeight = opts.charHeight;
3457
+ charHeight = opts.charHeight,
3458
+ colorForBase = opts.colorForBase,
3459
+ contrastForBase = opts.contrastForBase;
3367
3460
  var bpPerPx = props.bpPerPx,
3368
3461
  regions = props.regions;
3369
3462
  var heightPx = feat.heightPx,
@@ -3375,7 +3468,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3375
3468
 
3376
3469
  var start = feature.get('start');
3377
3470
  var pxPerBp = Math.min(1 / bpPerPx, 2);
3378
- var w = Math.max(minWidth, pxPerBp);
3471
+ var w = Math.max(minSubfeatureWidth, pxPerBp);
3379
3472
  var mismatches = feature.get('mismatches');
3380
3473
  var heightLim = charHeight - 2;
3381
3474
 
@@ -3387,22 +3480,25 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3387
3480
  }
3388
3481
 
3389
3482
  return color;
3390
- } // two pass rendering: first pass, draw all the mismatches except wide
3391
- // insertion markers
3483
+ } // extraHorizontallyFlippedOffset is used to draw interbase items, which
3484
+ // are located to the left when forward and right when reversed
3392
3485
 
3393
3486
 
3487
+ var extraHorizontallyFlippedOffset = region.reversed ? 1 / bpPerPx + 1 : -1; // two pass rendering: first pass, draw all the mismatches except wide
3488
+ // insertion markers
3489
+
3394
3490
  for (var i = 0; i < mismatches.length; i += 1) {
3395
3491
  var mismatch = mismatches[i];
3396
3492
  var mstart = start + mismatch.start;
3397
3493
  var mlen = mismatch.length;
3398
3494
  var mbase = mismatch.base;
3399
3495
 
3400
- var _bpSpanPx15 = bpSpanPx(mstart, mstart + mlen, region, bpPerPx),
3401
- _bpSpanPx16 = _slicedToArray(_bpSpanPx15, 2),
3402
- leftPx = _bpSpanPx16[0],
3403
- rightPx = _bpSpanPx16[1];
3496
+ var _bpSpanPx17 = bpSpanPx(mstart, mstart + mlen, region, bpPerPx),
3497
+ _bpSpanPx18 = _slicedToArray(_bpSpanPx17, 2),
3498
+ leftPx = _bpSpanPx18[0],
3499
+ rightPx = _bpSpanPx18[1];
3404
3500
 
3405
- var widthPx = Math.max(minWidth, Math.abs(leftPx - rightPx));
3501
+ var widthPx = Math.max(minSubfeatureWidth, Math.abs(leftPx - rightPx));
3406
3502
 
3407
3503
  if (mismatch.type === 'mismatch' && drawSNPs) {
3408
3504
  var baseColor = colorForBase[mismatch.base] || '#888';
@@ -3411,7 +3507,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3411
3507
 
3412
3508
  if (widthPx >= charWidth && heightPx >= heightLim) {
3413
3509
  // normal SNP coloring
3414
- ctx.fillStyle = getAlphaColor(theme.palette.getContrastText(baseColor), mismatch);
3510
+ ctx.fillStyle = getAlphaColor(contrastForBase[mismatch.base], mismatch);
3415
3511
  ctx.fillText(mbase, leftPx + (widthPx - charWidth) / 2 + 1, topPx + heightPx);
3416
3512
  }
3417
3513
  } else if (mismatch.type === 'deletion' && drawIndels) {
@@ -3419,40 +3515,38 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3419
3515
  ctx.fillStyle = _baseColor;
3420
3516
  ctx.fillRect(leftPx, topPx, widthPx, heightPx);
3421
3517
  var txt = "".concat(mismatch.length);
3422
- var rect = ctx.measureText(txt);
3518
+ var rwidth = measureText(txt, 10);
3423
3519
 
3424
- if (widthPx >= rect.width && heightPx >= heightLim) {
3425
- ctx.fillStyle = theme.palette.getContrastText(_baseColor);
3426
- ctx.fillText(txt, leftPx + (rightPx - leftPx) / 2 - rect.width / 2, topPx + heightPx);
3520
+ if (widthPx >= rwidth && heightPx >= heightLim) {
3521
+ ctx.fillStyle = contrastForBase.deletion;
3522
+ ctx.fillText(txt, (leftPx + rightPx) / 2 - rwidth / 2, topPx + heightPx);
3427
3523
  }
3428
3524
  } else if (mismatch.type === 'insertion' && drawIndels) {
3429
3525
  ctx.fillStyle = 'purple';
3430
- var pos = leftPx - 1;
3526
+ var pos = leftPx + extraHorizontallyFlippedOffset;
3431
3527
  var len = +mismatch.base || mismatch.length;
3528
+ var insW = Math.max(minSubfeatureWidth, Math.min(1.2, 1 / bpPerPx));
3432
3529
 
3433
3530
  if (len < 10) {
3434
- ctx.fillRect(pos, topPx, w, heightPx);
3435
-
3436
- if (1 / bpPerPx >= charWidth) {
3437
- ctx.fillRect(pos - w, topPx, w * 3, 1);
3438
- ctx.fillRect(pos - w, topPx + heightPx - 1, w * 3, 1);
3439
- }
3531
+ ctx.fillRect(pos, topPx, insW, heightPx);
3440
3532
 
3441
3533
  if (1 / bpPerPx >= charWidth && heightPx >= heightLim) {
3442
- ctx.fillText("(".concat(mismatch.base, ")"), leftPx + 2, topPx + heightPx);
3534
+ ctx.fillRect(pos - insW, topPx, insW * 3, 1);
3535
+ ctx.fillRect(pos - insW, topPx + heightPx - 1, insW * 3, 1);
3536
+ ctx.fillText("(".concat(mismatch.base, ")"), pos + 3, topPx + heightPx);
3443
3537
  }
3444
3538
  }
3445
3539
  } else if (mismatch.type === 'hardclip' || mismatch.type === 'softclip') {
3446
3540
  ctx.fillStyle = mismatch.type === 'hardclip' ? 'red' : 'blue';
3447
3541
 
3448
- var _pos = leftPx - 1;
3542
+ var _pos = leftPx + extraHorizontallyFlippedOffset;
3449
3543
 
3450
- ctx.fillRect(_pos, topPx + 1, w, heightPx - 2);
3451
- ctx.fillRect(_pos - w, topPx, w * 3, 1);
3452
- ctx.fillRect(_pos - w, topPx + heightPx - 1, w * 3, 1);
3544
+ ctx.fillRect(_pos, topPx, w, heightPx);
3453
3545
 
3454
- if (widthPx >= charWidth && heightPx >= heightLim) {
3455
- ctx.fillText("(".concat(mismatch.base, ")"), leftPx + 2, topPx + heightPx);
3546
+ if (1 / bpPerPx >= charWidth && heightPx >= heightLim) {
3547
+ ctx.fillRect(_pos - w, topPx, w * 3, 1);
3548
+ ctx.fillRect(_pos - w, topPx + heightPx - 1, w * 3, 1);
3549
+ ctx.fillText("(".concat(mismatch.base, ")"), _pos + 3, topPx + heightPx);
3456
3550
  }
3457
3551
  } else if (mismatch.type === 'skip') {
3458
3552
  // fix to avoid bad rendering note that this was also related to chrome
@@ -3470,16 +3564,16 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3470
3564
 
3471
3565
 
3472
3566
  if (drawIndels) {
3473
- for (var _i = 0; _i < mismatches.length; _i += 1) {
3474
- var _mismatch = mismatches[_i];
3567
+ for (var _i2 = 0; _i2 < mismatches.length; _i2 += 1) {
3568
+ var _mismatch = mismatches[_i2];
3475
3569
 
3476
3570
  var _mstart = start + _mismatch.start;
3477
3571
 
3478
3572
  var _mlen = _mismatch.length;
3479
3573
 
3480
- var _bpSpanPx17 = bpSpanPx(_mstart, _mstart + _mlen, region, bpPerPx),
3481
- _bpSpanPx18 = _slicedToArray(_bpSpanPx17, 1),
3482
- _leftPx2 = _bpSpanPx18[0];
3574
+ var _bpSpanPx19 = bpSpanPx(_mstart, _mstart + _mlen, region, bpPerPx),
3575
+ _bpSpanPx20 = _slicedToArray(_bpSpanPx19, 1),
3576
+ _leftPx2 = _bpSpanPx20[0];
3483
3577
 
3484
3578
  var _len = +_mismatch.base || _mismatch.length;
3485
3579
 
@@ -3490,13 +3584,12 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3490
3584
  ctx.fillStyle = 'purple';
3491
3585
  ctx.fillRect(_leftPx2 - 1, topPx, 2, heightPx);
3492
3586
  } else if (heightPx > charHeight) {
3493
- var _rect = ctx.measureText(_txt);
3494
-
3587
+ var rect = ctx.measureText(_txt);
3495
3588
  var padding = 5;
3496
3589
  ctx.fillStyle = 'purple';
3497
- ctx.fillRect(_leftPx2 - _rect.width / 2 - padding, topPx, _rect.width + 2 * padding, heightPx);
3590
+ ctx.fillRect(_leftPx2 - rect.width / 2 - padding, topPx, rect.width + 2 * padding, heightPx);
3498
3591
  ctx.fillStyle = 'white';
3499
- ctx.fillText(_txt, _leftPx2 - _rect.width / 2, topPx + heightPx);
3592
+ ctx.fillText(_txt, _leftPx2 - rect.width / 2, topPx + heightPx);
3500
3593
  } else {
3501
3594
  var _padding = 2;
3502
3595
  ctx.fillStyle = 'purple';
@@ -3539,7 +3632,8 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3539
3632
  return mismatch.type === 'softclip';
3540
3633
  }).forEach(function (mismatch) {
3541
3634
  var softClipLength = mismatch.cliplen || 0;
3542
- var softClipStart = mismatch.start === 0 ? feature.get('start') - softClipLength : feature.get('start') + mismatch.start;
3635
+ var s = feature.get('start');
3636
+ var softClipStart = mismatch.start === 0 ? s - softClipLength : s + mismatch.start;
3543
3637
 
3544
3638
  for (var k = 0; k < softClipLength; k += 1) {
3545
3639
  var base = seq.charAt(k + mismatch.start); // If softclip length+start is longer than sequence, no need to
@@ -3549,10 +3643,10 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3549
3643
  return;
3550
3644
  }
3551
3645
 
3552
- var _bpSpanPx19 = bpSpanPx(softClipStart + k, softClipStart + k + 1, region, bpPerPx),
3553
- _bpSpanPx20 = _slicedToArray(_bpSpanPx19, 2),
3554
- softClipLeftPx = _bpSpanPx20[0],
3555
- softClipRightPx = _bpSpanPx20[1];
3646
+ var _bpSpanPx21 = bpSpanPx(softClipStart + k, softClipStart + k + 1, region, bpPerPx),
3647
+ _bpSpanPx22 = _slicedToArray(_bpSpanPx21, 2),
3648
+ softClipLeftPx = _bpSpanPx22[0],
3649
+ softClipRightPx = _bpSpanPx22[1];
3556
3650
 
3557
3651
  var softClipWidthPx = Math.max(minFeatWidth, Math.abs(softClipLeftPx - softClipRightPx)); // Black accounts for IUPAC ambiguity code bases such as N that
3558
3652
  // show in soft clipping
@@ -3575,7 +3669,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3575
3669
  var _makeImageData = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee(ctx, layoutRecords, props) {
3576
3670
  var _this2 = this;
3577
3671
 
3578
- var layout, config, showSoftClip, colorBy, configTheme, mismatchAlpha, minSubfeatureWidth, insertScale, defaultColor, theme, colorForBase, _this$getCharWidthHei2, charWidth, charHeight;
3672
+ var layout, config, showSoftClip, colorBy, configTheme, mismatchAlpha, minSubfeatureWidth, insertScale, defaultColor, theme, colorForBase, contrastForBase, _this$getCharWidthHei2, charWidth, charHeight;
3579
3673
 
3580
3674
  return runtime_1.wrap(function _callee$(_context) {
3581
3675
  while (1) {
@@ -3588,23 +3682,24 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3588
3682
  defaultColor = readConfObject(config, 'color') === '#f0f';
3589
3683
  theme = createJBrowseTheme(configTheme);
3590
3684
  colorForBase = getColorBaseMap(theme);
3685
+ contrastForBase = getContrastBaseMap(theme);
3591
3686
 
3592
3687
  if (layout) {
3593
- _context.next = 9;
3688
+ _context.next = 10;
3594
3689
  break;
3595
3690
  }
3596
3691
 
3597
3692
  throw new Error("layout required");
3598
3693
 
3599
- case 9:
3694
+ case 10:
3600
3695
  if (layout.addRect) {
3601
- _context.next = 11;
3696
+ _context.next = 12;
3602
3697
  break;
3603
3698
  }
3604
3699
 
3605
3700
  throw new Error('invalid layout object');
3606
3701
 
3607
- case 11:
3702
+ case 12:
3608
3703
  ctx.font = 'bold 10px Courier New,monospace';
3609
3704
  _this$getCharWidthHei2 = this.getCharWidthHeight(ctx), charWidth = _this$getCharWidthHei2.charWidth, charHeight = _this$getCharWidthHei2.charHeight;
3610
3705
  layoutRecords.forEach(function (feat) {
@@ -3613,17 +3708,23 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3613
3708
  }
3614
3709
 
3615
3710
  _this2.drawAlignmentRect(ctx, feat, _objectSpread2(_objectSpread2({}, props), {}, {
3616
- defaultColor: defaultColor
3711
+ defaultColor: defaultColor,
3712
+ colorForBase: colorForBase,
3713
+ contrastForBase: contrastForBase,
3714
+ charWidth: charWidth,
3715
+ charHeight: charHeight
3617
3716
  }));
3618
3717
 
3619
- _this2.drawMismatches(ctx, feat, props, theme, colorForBase, {
3718
+ _this2.drawMismatches(ctx, feat, props, {
3620
3719
  mismatchAlpha: mismatchAlpha,
3621
3720
  drawSNPs: shouldDrawMismatches(colorBy === null || colorBy === void 0 ? void 0 : colorBy.type),
3622
3721
  drawIndels: shouldDrawMismatches(colorBy === null || colorBy === void 0 ? void 0 : colorBy.type),
3623
3722
  largeInsertionIndicatorScale: insertScale,
3624
3723
  minSubfeatureWidth: minSubfeatureWidth,
3625
3724
  charWidth: charWidth,
3626
- charHeight: charHeight
3725
+ charHeight: charHeight,
3726
+ colorForBase: colorForBase,
3727
+ contrastForBase: contrastForBase
3627
3728
  });
3628
3729
 
3629
3730
  if (showSoftClip) {
@@ -3631,7 +3732,7 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3631
3732
  }
3632
3733
  });
3633
3734
 
3634
- case 14:
3735
+ case 15:
3635
3736
  case "end":
3636
3737
  return _context.stop();
3637
3738
  }
@@ -3688,57 +3789,98 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3688
3789
  return layoutRecords;
3689
3790
  }
3690
3791
  }, {
3691
- key: "render",
3792
+ key: "fetchSequence",
3692
3793
  value: function () {
3693
- var _render = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(renderProps) {
3694
- var _this4 = this;
3695
-
3696
- 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;
3794
+ var _fetchSequence2 = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee2(renderProps) {
3795
+ var sessionId, regions, adapterConfig, sequenceAdapter, _yield$getAdapter, dataAdapter, _regions5, region;
3697
3796
 
3698
3797
  return runtime_1.wrap(function _callee2$(_context2) {
3699
3798
  while (1) {
3700
3799
  switch (_context2.prev = _context2.next) {
3701
3800
  case 0:
3702
- sessionId = renderProps.sessionId, bpPerPx = renderProps.bpPerPx, regions = renderProps.regions, adapterConfig = renderProps.adapterConfig;
3801
+ sessionId = renderProps.sessionId, regions = renderProps.regions, adapterConfig = renderProps.adapterConfig;
3703
3802
  sequenceAdapter = adapterConfig.sequenceAdapter;
3704
- _context2.next = 4;
3705
- return this.getFeatures(renderProps);
3803
+
3804
+ if (sequenceAdapter) {
3805
+ _context2.next = 4;
3806
+ break;
3807
+ }
3808
+
3809
+ return _context2.abrupt("return", undefined);
3706
3810
 
3707
3811
  case 4:
3708
- features = _context2.sent;
3812
+ _context2.next = 6;
3813
+ return getAdapter(this.pluginManager, sessionId, sequenceAdapter);
3814
+
3815
+ case 6:
3816
+ _yield$getAdapter = _context2.sent;
3817
+ dataAdapter = _yield$getAdapter.dataAdapter;
3818
+ _regions5 = _slicedToArray(regions, 1), region = _regions5[0];
3819
+ return _context2.abrupt("return", fetchSequence(region, dataAdapter));
3820
+
3821
+ case 10:
3822
+ case "end":
3823
+ return _context2.stop();
3824
+ }
3825
+ }
3826
+ }, _callee2, this);
3827
+ }));
3828
+
3829
+ function fetchSequence$1(_x4) {
3830
+ return _fetchSequence2.apply(this, arguments);
3831
+ }
3832
+
3833
+ return fetchSequence$1;
3834
+ }()
3835
+ }, {
3836
+ key: "render",
3837
+ value: function () {
3838
+ var _render = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee3(renderProps) {
3839
+ var _renderProps$colorBy,
3840
+ _this4 = this;
3841
+
3842
+ var features, layout, regions, bpPerPx, layoutRecords, _regions6, region, regionSequence, end, start, width, height, res, results;
3843
+
3844
+ return runtime_1.wrap(function _callee3$(_context3) {
3845
+ while (1) {
3846
+ switch (_context3.prev = _context3.next) {
3847
+ case 0:
3848
+ _context3.next = 2;
3849
+ return this.getFeatures(renderProps);
3850
+
3851
+ case 2:
3852
+ features = _context3.sent;
3709
3853
  layout = this.createLayoutInWorker(renderProps);
3854
+ regions = renderProps.regions, bpPerPx = renderProps.bpPerPx;
3710
3855
  layoutRecords = this.layoutFeats(_objectSpread2(_objectSpread2({}, renderProps), {}, {
3711
3856
  features: features,
3712
3857
  layout: layout
3713
3858
  }));
3714
- _regions5 = _slicedToArray(regions, 1), region = _regions5[0];
3715
- end = region.end, start = region.start, originalRefName = region.originalRefName, refName = region.refName;
3859
+ _regions6 = _slicedToArray(regions, 1), region = _regions6[0]; // only need reference sequence if there are features and only for some
3860
+ // cases
3716
3861
 
3717
- if (!sequenceAdapter) {
3718
- _context2.next = 18;
3862
+ if (!(features.size && shouldFetchReferenceSequence((_renderProps$colorBy = renderProps.colorBy) === null || _renderProps$colorBy === void 0 ? void 0 : _renderProps$colorBy.type))) {
3863
+ _context3.next = 13;
3719
3864
  break;
3720
3865
  }
3721
3866
 
3722
- _context2.next = 12;
3723
- return getAdapter(this.pluginManager, sessionId, sequenceAdapter);
3867
+ _context3.next = 10;
3868
+ return this.fetchSequence(renderProps);
3724
3869
 
3725
- case 12:
3726
- _yield$getAdapter = _context2.sent;
3727
- dataAdapter = _yield$getAdapter.dataAdapter;
3728
- _context2.next = 16;
3729
- return dataAdapter.getFeatures(_objectSpread2(_objectSpread2({}, region), {}, {
3730
- refName: originalRefName || refName,
3731
- end: region.end + 1
3732
- })).pipe(toArray()).toPromise();
3870
+ case 10:
3871
+ _context3.t0 = _context3.sent;
3872
+ _context3.next = 14;
3873
+ break;
3733
3874
 
3734
- case 16:
3735
- feats = _context2.sent;
3736
- regionSequence = (_feats$ = feats[0]) === null || _feats$ === void 0 ? void 0 : _feats$.get('seq');
3875
+ case 13:
3876
+ _context3.t0 = undefined;
3737
3877
 
3738
- case 18:
3878
+ case 14:
3879
+ regionSequence = _context3.t0;
3880
+ end = region.end, start = region.start;
3739
3881
  width = (end - start) / bpPerPx;
3740
3882
  height = Math.max(layout.getTotalHeight(), 1);
3741
- _context2.next = 22;
3883
+ _context3.next = 20;
3742
3884
  return renderToAbstractCanvas(width, height, renderProps, function (ctx) {
3743
3885
  return _this4.makeImageData(ctx, layoutRecords, _objectSpread2(_objectSpread2({}, renderProps), {}, {
3744
3886
  layout: layout,
@@ -3747,9 +3889,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3747
3889
  }));
3748
3890
  });
3749
3891
 
3750
- case 22:
3751
- res = _context2.sent;
3752
- _context2.next = 25;
3892
+ case 20:
3893
+ res = _context3.sent;
3894
+ _context3.next = 23;
3753
3895
  return _get(_getPrototypeOf(PileupRenderer.prototype), "render", this).call(this, _objectSpread2(_objectSpread2(_objectSpread2({}, renderProps), res), {}, {
3754
3896
  features: features,
3755
3897
  layout: layout,
@@ -3757,9 +3899,9 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3757
3899
  width: width
3758
3900
  }));
3759
3901
 
3760
- case 25:
3761
- results = _context2.sent;
3762
- return _context2.abrupt("return", _objectSpread2(_objectSpread2(_objectSpread2({}, results), res), {}, {
3902
+ case 23:
3903
+ results = _context3.sent;
3904
+ return _context3.abrupt("return", _objectSpread2(_objectSpread2(_objectSpread2({}, results), res), {}, {
3763
3905
  features: features,
3764
3906
  layout: layout,
3765
3907
  height: height,
@@ -3767,15 +3909,15 @@ var PileupRenderer = /*#__PURE__*/function (_BoxRendererType) {
3767
3909
  maxHeightReached: layout.maxHeightReached
3768
3910
  }));
3769
3911
 
3770
- case 27:
3912
+ case 25:
3771
3913
  case "end":
3772
- return _context2.stop();
3914
+ return _context3.stop();
3773
3915
  }
3774
3916
  }
3775
- }, _callee2, this);
3917
+ }, _callee3, this);
3776
3918
  }));
3777
3919
 
3778
- function render(_x4) {
3920
+ function render(_x5) {
3779
3921
  return _render.apply(this, arguments);
3780
3922
  }
3781
3923
 
@@ -3935,10 +4077,15 @@ function PileupRendering(props) {
3935
4077
 
3936
4078
  var offsetX = 0;
3937
4079
  var offsetY = 0;
4080
+ var canvas = highlightOverlayCanvas.current;
4081
+
4082
+ if (canvas) {
4083
+ var _canvas$getBoundingCl = canvas.getBoundingClientRect(),
4084
+ left = _canvas$getBoundingCl.left,
4085
+ top = _canvas$getBoundingCl.top;
3938
4086
 
3939
- if (highlightOverlayCanvas.current) {
3940
- offsetX = highlightOverlayCanvas.current.getBoundingClientRect().left;
3941
- offsetY = highlightOverlayCanvas.current.getBoundingClientRect().top;
4087
+ offsetX = left;
4088
+ offsetY = top;
3942
4089
  }
3943
4090
 
3944
4091
  offsetX = event.clientX - offsetX;
@@ -4322,45 +4469,51 @@ var stateModelFactory = function stateModelFactory(pluginManager, configSchema)
4322
4469
  });
4323
4470
  };
4324
4471
 
4472
+ var useStyles = /*#__PURE__*/makeStyles(function () {
4473
+ return {
4474
+ resizeHandle: {
4475
+ height: 2,
4476
+ position: 'absolute',
4477
+ zIndex: 2
4478
+ }
4479
+ };
4480
+ });
4481
+
4325
4482
  function AlignmentsDisplay(_ref) {
4326
4483
  var model = _ref.model;
4327
4484
  var PileupDisplay = model.PileupDisplay,
4328
4485
  SNPCoverageDisplay = model.SNPCoverageDisplay,
4329
4486
  showPileup = model.showPileup,
4330
4487
  showCoverage = model.showCoverage;
4488
+ var classes = useStyles();
4489
+ var top = SNPCoverageDisplay.height;
4331
4490
  return /*#__PURE__*/React.createElement("div", {
4332
4491
  "data-testid": "display-".concat(getConf(model, 'displayId')),
4333
4492
  style: {
4334
4493
  position: 'relative'
4335
4494
  }
4336
- }, /*#__PURE__*/React.createElement("div", {
4495
+ }, showCoverage ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
4337
4496
  "data-testid": "Blockset-snpcoverage"
4338
- }, showCoverage ? /*#__PURE__*/React.createElement(SNPCoverageDisplay.RenderingComponent, {
4497
+ }, /*#__PURE__*/React.createElement(SNPCoverageDisplay.RenderingComponent, {
4339
4498
  model: SNPCoverageDisplay
4340
- }) : null), /*#__PURE__*/React.createElement(ResizeHandle, {
4499
+ })), /*#__PURE__*/React.createElement(ResizeHandle, {
4341
4500
  onDrag: function onDrag(delta) {
4342
- if (SNPCoverageDisplay) {
4343
- SNPCoverageDisplay.setHeight(SNPCoverageDisplay.height + delta);
4344
- return delta;
4345
- }
4346
-
4347
- return 0;
4501
+ SNPCoverageDisplay.setHeight(SNPCoverageDisplay.height + delta);
4502
+ return delta;
4348
4503
  },
4504
+ className: classes.resizeHandle,
4349
4505
  style: {
4350
- position: 'absolute',
4351
- top: showCoverage ? SNPCoverageDisplay.height + 2 : 0,
4352
- height: 3
4506
+ top: top
4353
4507
  }
4354
- }), /*#__PURE__*/React.createElement("div", {
4508
+ })) : null, showPileup ? /*#__PURE__*/React.createElement("div", {
4355
4509
  "data-testid": "Blockset-pileup",
4356
4510
  style: {
4357
4511
  position: 'absolute',
4358
- top: showCoverage ? SNPCoverageDisplay.height + 5 : 0,
4359
- height: 3
4512
+ top: showCoverage ? SNPCoverageDisplay.height : 0
4360
4513
  }
4361
- }, showPileup ? /*#__PURE__*/React.createElement(PileupDisplay.RenderingComponent, {
4514
+ }, /*#__PURE__*/React.createElement(PileupDisplay.RenderingComponent, {
4362
4515
  model: PileupDisplay
4363
- }) : null));
4516
+ })) : null);
4364
4517
  }
4365
4518
 
4366
4519
  var ReactComponent$1 = /*#__PURE__*/observer(AlignmentsDisplay);
@@ -4409,10 +4562,10 @@ function SNPCoverageConfigFactory(pluginManager) {
4409
4562
  description: 'draw upside down',
4410
4563
  defaultValue: false
4411
4564
  },
4412
- headroom: {
4413
- type: 'number',
4414
- description: 'round the upper value of the domain scale to the nearest N',
4415
- defaultValue: 0
4565
+ multiTicks: {
4566
+ type: 'boolean',
4567
+ description: 'Display multiple values for the ticks',
4568
+ defaultValue: false
4416
4569
  },
4417
4570
  renderers: ConfigurationSchema('RenderersConfiguration', {
4418
4571
  SNPCoverageRenderer: SNPCoverageRendererConfigSchema
@@ -4432,10 +4585,10 @@ var TooltipContents = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
4432
4585
  var start = feature.get('start');
4433
4586
  var end = feature.get('end');
4434
4587
  var name = feature.get('refName');
4588
+ var info = feature.get('snpinfo');
4435
4589
  var loc = [name, start === end ? en(start) : "".concat(en(start), "..").concat(en(end))].filter(function (f) {
4436
4590
  return !!f;
4437
4591
  }).join(':');
4438
- var info = feature.get('snpinfo');
4439
4592
  var total = info === null || info === void 0 ? void 0 : info.total;
4440
4593
  return /*#__PURE__*/React.createElement("div", {
4441
4594
  ref: ref
@@ -4452,7 +4605,7 @@ var TooltipContents = /*#__PURE__*/React.forwardRef(function (_ref, ref) {
4452
4605
  var strands = score.strands;
4453
4606
  return /*#__PURE__*/React.createElement("tr", {
4454
4607
  key: base
4455
- }, /*#__PURE__*/React.createElement("td", null, base.toUpperCase()), /*#__PURE__*/React.createElement("td", null, score.total), /*#__PURE__*/React.createElement("td", null, base === 'total' || base === 'skip' ? '---' : "".concat(Math.floor(score.total / total * 100), "%")), /*#__PURE__*/React.createElement("td", null, strands['-1'] ? "".concat(strands['-1'], "(-)") : '', strands['1'] ? "".concat(strands['1'], "(+)") : ''), /*#__PURE__*/React.createElement("td", null, key));
4608
+ }, /*#__PURE__*/React.createElement("td", null, base.toUpperCase()), /*#__PURE__*/React.createElement("td", null, score.total), /*#__PURE__*/React.createElement("td", null, base === 'total' || base === 'skip' ? '---' : "".concat(Math.floor(score.total / (total || score.total || 1) * 100), "%")), /*#__PURE__*/React.createElement("td", null, strands['-1'] ? "".concat(strands['-1'], "(-)") : '', strands['1'] ? "".concat(strands['1'], "(+)") : ''), /*#__PURE__*/React.createElement("td", null, key));
4456
4609
  });
4457
4610
  }))));
4458
4611
  });
@@ -5293,6 +5446,13 @@ var stateModelFactory$2 = function stateModelFactory(configSchema) {
5293
5446
  type: 'perBaseQuality'
5294
5447
  });
5295
5448
  }
5449
+ }, {
5450
+ label: 'Per-base lettering',
5451
+ onClick: function onClick() {
5452
+ self.setColorScheme({
5453
+ type: 'perBaseLettering'
5454
+ });
5455
+ }
5296
5456
  }, {
5297
5457
  label: 'Modifications or methylation',
5298
5458
  onClick: function onClick() {
@@ -5756,12 +5916,14 @@ var AlignmentsPlugin = /*#__PURE__*/function (_Plugin) {
5756
5916
  }(Plugin);
5757
5917
 
5758
5918
  var CramSlightlyLazyFeature = /*#__PURE__*/function () {
5919
+ // uses parameter properties to automatically create fields on the class
5920
+ // https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties
5759
5921
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5760
- function CramSlightlyLazyFeature(record, store) {
5922
+ function CramSlightlyLazyFeature(record, _store) {
5761
5923
  _classCallCheck(this, CramSlightlyLazyFeature);
5762
5924
 
5763
5925
  this.record = record;
5764
- this._store = store;
5926
+ this._store = _store;
5765
5927
  }
5766
5928
 
5767
5929
  _createClass(CramSlightlyLazyFeature, [{
@@ -6004,7 +6166,7 @@ var CramSlightlyLazyFeature = /*#__PURE__*/function () {
6004
6166
  value: function tags() {
6005
6167
  var properties = Object.getOwnPropertyNames(CramSlightlyLazyFeature.prototype);
6006
6168
  return properties.filter(function (prop) {
6007
- return prop.startsWith('_get_') && prop !== '_get_mismatches' && prop !== '_get_skips_and_dels' && prop !== '_get_cram_read_features';
6169
+ return prop.startsWith('_get_') && prop !== '_get_mismatches' && prop !== '_get_cram_read_features';
6008
6170
  }).map(function (methodName) {
6009
6171
  return methodName.replace('_get_', '');
6010
6172
  });
@@ -6168,11 +6330,6 @@ var CramSlightlyLazyFeature = /*#__PURE__*/function () {
6168
6330
  });
6169
6331
  return mismatches;
6170
6332
  }
6171
- }, {
6172
- key: "_get_skips_and_dels",
6173
- value: function _get_skips_and_dels() {
6174
- return this._get_mismatches();
6175
- }
6176
6333
  }]);
6177
6334
 
6178
6335
  return CramSlightlyLazyFeature;
@@ -6766,6 +6923,8 @@ var CramAdapter$1 = {
6766
6923
  };
6767
6924
 
6768
6925
  var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6926
+ // uses parameter properties to automatically create fields on the class
6927
+ // https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties
6769
6928
  function BamSlightlyLazyFeature(record, adapter, ref) {
6770
6929
  _classCallCheck(this, BamSlightlyLazyFeature);
6771
6930
 
@@ -6832,18 +6991,6 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6832
6991
  value: function _get_seq() {
6833
6992
  return this.record.getReadBases();
6834
6993
  }
6835
- }, {
6836
- key: "_get_MD",
6837
- value: function _get_MD() {
6838
- var md = this.record.get('MD');
6839
- var seq = this.get('seq');
6840
-
6841
- if (!md && seq && this.ref) {
6842
- return generateMD(this.ref, this.record.getReadBases(), this.get('CIGAR'));
6843
- }
6844
-
6845
- return md;
6846
- }
6847
6994
  }, {
6848
6995
  key: "qualRaw",
6849
6996
  value: function qualRaw() {
@@ -6857,7 +7004,7 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6857
7004
  value: function tags() {
6858
7005
  var properties = Object.getOwnPropertyNames(BamSlightlyLazyFeature.prototype);
6859
7006
  return _toConsumableArray(new Set(properties.filter(function (prop) {
6860
- 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';
7007
+ return prop.startsWith('_get_') && prop !== '_get_mismatches' && prop !== '_get_tags' && prop !== '_get_next_seq_id' && prop !== '_get_seq_id';
6861
7008
  }).map(function (methodName) {
6862
7009
  return methodName.replace('_get_', '');
6863
7010
  }).concat(this.record._tags())));
@@ -6913,61 +7060,10 @@ var BamSlightlyLazyFeature = /*#__PURE__*/function () {
6913
7060
  uniqueId: this.id()
6914
7061
  });
6915
7062
  }
6916
- }, {
6917
- key: "_get_skips_and_dels",
6918
- value: function _get_skips_and_dels() {
6919
- var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
6920
- cigarAttributeName: 'CIGAR'
6921
- };
6922
- var cigarAttributeName = opts.cigarAttributeName;
6923
- var mismatches = [];
6924
- var cigarOps = []; // parse the CIGAR tag if it has one
6925
-
6926
- var cigarString = this.get(cigarAttributeName);
6927
-
6928
- if (cigarString) {
6929
- cigarOps = parseCigar(cigarString);
6930
- mismatches = mismatches.concat(cigarToMismatches(cigarOps, this.get('seq'), this.qualRaw()));
6931
- }
6932
-
6933
- return mismatches;
6934
- }
6935
7063
  }, {
6936
7064
  key: "_get_mismatches",
6937
7065
  value: function _get_mismatches() {
6938
- var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
6939
- _ref$cigarAttributeNa = _ref.cigarAttributeName,
6940
- cigarAttributeName = _ref$cigarAttributeNa === void 0 ? 'CIGAR' : _ref$cigarAttributeNa,
6941
- _ref$mdAttributeName = _ref.mdAttributeName,
6942
- mdAttributeName = _ref$mdAttributeName === void 0 ? 'MD' : _ref$mdAttributeName;
6943
-
6944
- var mismatches = [];
6945
- var cigarOps = []; // parse the CIGAR tag if it has one
6946
-
6947
- var cigarString = this.get(cigarAttributeName);
6948
- var seq = this.get('seq');
6949
- var qual = this.qualRaw();
6950
-
6951
- if (cigarString) {
6952
- cigarOps = parseCigar(cigarString);
6953
- mismatches = mismatches.concat(cigarToMismatches(cigarOps, seq, qual));
6954
- } // now let's look for CRAM or MD mismatches
6955
-
6956
-
6957
- var mdString = this.get(mdAttributeName);
6958
-
6959
- if (mdString) {
6960
- mismatches = mismatches.concat(mdToMismatches(mdString, cigarOps, mismatches, seq, qual));
6961
- } // uniqify the mismatches
6962
-
6963
-
6964
- var seen = {};
6965
- return mismatches.filter(function (m) {
6966
- var key = "".concat(m.type, ",").concat(m.start, ",").concat(m.length);
6967
- var s = seen[key];
6968
- seen[key] = true;
6969
- return !s;
6970
- });
7066
+ return getMismatches(this.get('CIGAR'), this.get('MD'), this.get('seq'), this.ref, this.qualRaw());
6971
7067
  }
6972
7068
  }, {
6973
7069
  key: "_get_clipPos",
@@ -6997,7 +7093,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
6997
7093
  // configure method allows derived classes to override this behavior
6998
7094
  function () {
6999
7095
  var _configure = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee() {
7000
- var bamLocation, location, indexType, chunkSizeLimit, bam, adapterConfig;
7096
+ var bamLocation, location, indexType, bam, adapterConfig;
7001
7097
  return runtime_1.wrap(function _callee$(_context) {
7002
7098
  while (1) {
7003
7099
  switch (_context.prev = _context.next) {
@@ -7006,13 +7102,16 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7006
7102
  bamLocation = readConfObject(this.config, 'bamLocation');
7007
7103
  location = readConfObject(this.config, ['index', 'location']);
7008
7104
  indexType = readConfObject(this.config, ['index', 'indexType']);
7009
- chunkSizeLimit = readConfObject(this.config, 'chunkSizeLimit');
7010
7105
  bam = new BamFile({
7011
7106
  bamFilehandle: openLocation(bamLocation, this.pluginManager),
7012
7107
  csiFilehandle: indexType === 'CSI' ? openLocation(location, this.pluginManager) : undefined,
7013
7108
  baiFilehandle: indexType !== 'CSI' ? openLocation(location, this.pluginManager) : undefined,
7014
- chunkSizeLimit: chunkSizeLimit,
7015
- fetchSizeLimit: 100000000
7109
+ // chunkSizeLimit and fetchSizeLimit are more troublesome than
7110
+ // helpful, and have given overly large values on the ultra long
7111
+ // nanopore reads even with 500MB limits, so disabled with infinity
7112
+ chunkSizeLimit: Infinity,
7113
+ fetchSizeLimit: Infinity,
7114
+ yieldThreadTime: Infinity
7016
7115
  });
7017
7116
  adapterConfig = readConfObject(this.config, 'sequenceAdapter');
7018
7117
 
@@ -7224,7 +7323,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7224
7323
  key: "seqFetch",
7225
7324
  value: function () {
7226
7325
  var _seqFetch = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/runtime_1.mark(function _callee7(refName, start, end) {
7227
- var _yield$this$configure3, sequenceAdapter, refSeqStore, features, seqChunks, trimmed, sequence;
7326
+ var _yield$this$configure3, sequenceAdapter, refSeqStore, features, seqChunks, sequence;
7228
7327
 
7229
7328
  return runtime_1.wrap(function _callee7$(_context7) {
7230
7329
  while (1) {
@@ -7265,7 +7364,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7265
7364
 
7266
7365
  case 12:
7267
7366
  seqChunks = _context7.sent;
7268
- trimmed = [];
7367
+ sequence = '';
7269
7368
  seqChunks.sort(function (a, b) {
7270
7369
  return a.get('start') - b.get('start');
7271
7370
  }).forEach(function (chunk) {
@@ -7275,21 +7374,20 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7275
7374
  var trimEnd = Math.min(end - chunkStart, chunkEnd - chunkStart);
7276
7375
  var trimLength = trimEnd - trimStart;
7277
7376
  var chunkSeq = chunk.get('seq') || chunk.get('residues');
7278
- trimmed.push(chunkSeq.substr(trimStart, trimLength));
7377
+ sequence += chunkSeq.substr(trimStart, trimLength);
7279
7378
  });
7280
- sequence = trimmed.join('');
7281
7379
 
7282
7380
  if (!(sequence.length !== end - start)) {
7283
- _context7.next = 18;
7381
+ _context7.next = 17;
7284
7382
  break;
7285
7383
  }
7286
7384
 
7287
7385
  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()));
7288
7386
 
7289
- case 18:
7387
+ case 17:
7290
7388
  return _context7.abrupt("return", sequence);
7291
7389
 
7292
- case 19:
7390
+ case 18:
7293
7391
  case "end":
7294
7392
  return _context7.stop();
7295
7393
  }
@@ -7357,7 +7455,7 @@ var BamAdapter = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
7357
7455
  record = _step.value;
7358
7456
  ref = void 0;
7359
7457
 
7360
- if (record.get('md')) {
7458
+ if (record.get('MD')) {
7361
7459
  _context8.next = 21;
7362
7460
  break;
7363
7461
  }
@@ -7552,7 +7650,7 @@ var HtsgetBamAdapter$1 = {
7552
7650
  'default': HtsgetBamAdapter
7553
7651
  };
7554
7652
 
7555
- var useStyles = /*#__PURE__*/makeStyles(function (theme) {
7653
+ var useStyles$1 = /*#__PURE__*/makeStyles(function (theme) {
7556
7654
  return {
7557
7655
  root: {
7558
7656
  width: 300
@@ -7567,7 +7665,7 @@ var useStyles = /*#__PURE__*/makeStyles(function (theme) {
7567
7665
  });
7568
7666
 
7569
7667
  function ColorByTagDlg$1(props) {
7570
- var classes = useStyles();
7668
+ var classes = useStyles$1();
7571
7669
  var model = props.model,
7572
7670
  handleClose = props.handleClose;
7573
7671
 
@@ -7588,14 +7686,12 @@ function ColorByTagDlg$1(props) {
7588
7686
  style: {
7589
7687
  overflowX: 'hidden'
7590
7688
  }
7591
- }, /*#__PURE__*/React.createElement("div", {
7592
- className: classes.root
7593
7689
  }, /*#__PURE__*/React.createElement(Typography$1, null, "Enter tag to color by: "), /*#__PURE__*/React.createElement(Typography$1, {
7594
7690
  color: "textSecondary"
7595
7691
  }, "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.createElement(TextField, {
7596
7692
  value: tag,
7597
7693
  onChange: function onChange(event) {
7598
- setTag(event.target.value);
7694
+ return setTag(event.target.value);
7599
7695
  },
7600
7696
  placeholder: "Enter tag name",
7601
7697
  inputProps: {
@@ -7606,12 +7702,9 @@ function ColorByTagDlg$1(props) {
7606
7702
  helperText: tag.length === 2 && !validTag ? 'Not a valid tag' : '',
7607
7703
  autoComplete: "off",
7608
7704
  "data-testid": "color-tag-name"
7609
- }), /*#__PURE__*/React.createElement(Button, {
7705
+ }), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button, {
7610
7706
  variant: "contained",
7611
7707
  color: "primary",
7612
- style: {
7613
- marginLeft: 20
7614
- },
7615
7708
  onClick: function onClick() {
7616
7709
  model.setColorScheme({
7617
7710
  type: 'tag',
@@ -7620,7 +7713,11 @@ function ColorByTagDlg$1(props) {
7620
7713
  handleClose();
7621
7714
  },
7622
7715
  disabled: !validTag
7623
- }, "Submit"))));
7716
+ }, "Submit"), /*#__PURE__*/React.createElement(Button, {
7717
+ variant: "contained",
7718
+ color: "secondary",
7719
+ onClick: handleClose
7720
+ }, "Cancel"))));
7624
7721
  }
7625
7722
 
7626
7723
  var ColorByTag = /*#__PURE__*/observer(ColorByTagDlg$1);
@@ -7630,11 +7727,8 @@ var ColorByTag$1 = {
7630
7727
  'default': ColorByTag
7631
7728
  };
7632
7729
 
7633
- var useStyles$1 = /*#__PURE__*/makeStyles(function (theme) {
7730
+ var useStyles$2 = /*#__PURE__*/makeStyles(function (theme) {
7634
7731
  return {
7635
- root: {
7636
- width: 500
7637
- },
7638
7732
  paper: {
7639
7733
  padding: theme.spacing(2),
7640
7734
  margin: theme.spacing(2)
@@ -7688,7 +7782,7 @@ function FilterByTagDlg$1(props) {
7688
7782
 
7689
7783
  var model = props.model,
7690
7784
  handleClose = props.handleClose;
7691
- var classes = useStyles$1();
7785
+ var classes = useStyles$2();
7692
7786
  var filterBy = model.filterBy;
7693
7787
 
7694
7788
  var _useState = useState(filterBy === null || filterBy === void 0 ? void 0 : filterBy.flagInclude),
@@ -7727,9 +7821,7 @@ function FilterByTagDlg$1(props) {
7727
7821
  onClick: handleClose
7728
7822
  }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement(Typography$1, null, "Set filter bitmask options. Refer to ", /*#__PURE__*/React.createElement(Link, {
7729
7823
  href: site
7730
- }, site), ' ', "for details"), /*#__PURE__*/React.createElement("div", {
7731
- className: classes.root
7732
- }, /*#__PURE__*/React.createElement(Paper, {
7824
+ }, site), ' ', "for details"), /*#__PURE__*/React.createElement(Paper, {
7733
7825
  className: classes.paper,
7734
7826
  variant: "outlined"
7735
7827
  }, /*#__PURE__*/React.createElement("div", {
@@ -7784,9 +7876,11 @@ function FilterByTagDlg$1(props) {
7784
7876
  'data-testid': 'color-tag-readname-input'
7785
7877
  },
7786
7878
  "data-testid": "color-tag-readname"
7787
- })), /*#__PURE__*/React.createElement(Button, {
7879
+ })), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button, {
7788
7880
  variant: "contained",
7789
7881
  color: "primary",
7882
+ autoFocus: true,
7883
+ type: "submit",
7790
7884
  onClick: function onClick() {
7791
7885
  model.setFilterBy({
7792
7886
  flagInclude: flagInclude,
@@ -7799,7 +7893,13 @@ function FilterByTagDlg$1(props) {
7799
7893
  });
7800
7894
  handleClose();
7801
7895
  }
7802
- }, "Submit"))));
7896
+ }, "Submit"), /*#__PURE__*/React.createElement(Button, {
7897
+ variant: "contained",
7898
+ color: "secondary",
7899
+ onClick: function onClick() {
7900
+ return handleClose();
7901
+ }
7902
+ }, "Cancel"))));
7803
7903
  }
7804
7904
 
7805
7905
  var FilterByTag = /*#__PURE__*/observer(FilterByTagDlg$1);
@@ -7809,7 +7909,7 @@ var FilterByTag$1 = {
7809
7909
  'default': FilterByTag
7810
7910
  };
7811
7911
 
7812
- var useStyles$2 = /*#__PURE__*/makeStyles(function (theme) {
7912
+ var useStyles$3 = /*#__PURE__*/makeStyles(function (theme) {
7813
7913
  return {
7814
7914
  root: {
7815
7915
  margin: 0,
@@ -7825,7 +7925,7 @@ var useStyles$2 = /*#__PURE__*/makeStyles(function (theme) {
7825
7925
  });
7826
7926
 
7827
7927
  function SortByTagDlg$1(props) {
7828
- var classes = useStyles$2();
7928
+ var classes = useStyles$3();
7829
7929
  var model = props.model,
7830
7930
  handleClose = props.handleClose;
7831
7931
 
@@ -7842,12 +7942,12 @@ function SortByTagDlg$1(props) {
7842
7942
  "aria-label": "close",
7843
7943
  className: classes.closeButton,
7844
7944
  onClick: handleClose
7845
- }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Typography$1, null, "Set the tag to sort by"), /*#__PURE__*/React.createElement(Typography$1, {
7945
+ }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement(Typography$1, null, "Set the tag to sort by"), /*#__PURE__*/React.createElement(Typography$1, {
7846
7946
  color: "textSecondary"
7847
7947
  }, "Examples: HP for haplotype, RG for read group, etc."), /*#__PURE__*/React.createElement(TextField, {
7848
7948
  value: tag,
7849
7949
  onChange: function onChange(event) {
7850
- setTag(event.target.value);
7950
+ return setTag(event.target.value);
7851
7951
  },
7852
7952
  placeholder: "Enter tag name",
7853
7953
  inputProps: {
@@ -7858,14 +7958,22 @@ function SortByTagDlg$1(props) {
7858
7958
  helperText: tag.length === 2 && !validTag ? 'Not a valid tag' : '',
7859
7959
  autoComplete: "off",
7860
7960
  "data-testid": "sort-tag-name"
7861
- }), /*#__PURE__*/React.createElement(Button, {
7961
+ }), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button, {
7862
7962
  variant: "contained",
7863
7963
  color: "primary",
7964
+ type: "submit",
7965
+ autoFocus: true,
7864
7966
  onClick: function onClick() {
7865
7967
  model.setSortedBy('tag', tag);
7866
7968
  handleClose();
7867
7969
  }
7868
- }, "Submit"))));
7970
+ }, "Submit"), /*#__PURE__*/React.createElement(Button, {
7971
+ variant: "contained",
7972
+ color: "secondary",
7973
+ onClick: function onClick() {
7974
+ return handleClose();
7975
+ }
7976
+ }, "Cancel"))));
7869
7977
  }
7870
7978
 
7871
7979
  var SortByTag = /*#__PURE__*/observer(SortByTagDlg$1);
@@ -7875,11 +7983,8 @@ var SortByTag$1 = {
7875
7983
  'default': SortByTag
7876
7984
  };
7877
7985
 
7878
- var useStyles$3 = /*#__PURE__*/makeStyles(function (theme) {
7986
+ var useStyles$4 = /*#__PURE__*/makeStyles(function (theme) {
7879
7987
  return {
7880
- root: {
7881
- margin: theme.spacing(4)
7882
- },
7883
7988
  closeButton: {
7884
7989
  position: 'absolute',
7885
7990
  right: theme.spacing(1),
@@ -7890,7 +7995,7 @@ var useStyles$3 = /*#__PURE__*/makeStyles(function (theme) {
7890
7995
  });
7891
7996
 
7892
7997
  function SetFeatureHeightDlg$1(props) {
7893
- var classes = useStyles$3();
7998
+ var classes = useStyles$4();
7894
7999
  var model = props.model,
7895
8000
  handleClose = props.handleClose;
7896
8001
  var featureHeightSetting = model.featureHeightSetting,
@@ -7913,10 +8018,9 @@ function SetFeatureHeightDlg$1(props) {
7913
8018
  }, /*#__PURE__*/React.createElement(DialogTitle, null, "Set feature height", /*#__PURE__*/React.createElement(IconButton, {
7914
8019
  className: classes.closeButton,
7915
8020
  onClick: handleClose
7916
- }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement(Typography$1, 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.createElement("div", {
7917
- className: classes.root
7918
- }, /*#__PURE__*/React.createElement(Typography$1, null, "Enter feature height: "), /*#__PURE__*/React.createElement(TextField, {
8021
+ }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement(Typography$1, 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.createElement(TextField, {
7919
8022
  value: height,
8023
+ helperText: "Feature height",
7920
8024
  onChange: function onChange(event) {
7921
8025
  setHeight(event.target.value);
7922
8026
  }
@@ -7930,20 +8034,24 @@ function SetFeatureHeightDlg$1(props) {
7930
8034
  }
7931
8035
  }),
7932
8036
  label: "Remove spacing between features in y-direction?"
7933
- }), /*#__PURE__*/React.createElement(Button, {
8037
+ }), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button, {
7934
8038
  variant: "contained",
7935
8039
  color: "primary",
7936
8040
  type: "submit",
7937
- style: {
7938
- marginLeft: 20
7939
- },
8041
+ autoFocus: true,
7940
8042
  disabled: !ok,
7941
8043
  onClick: function onClick() {
7942
8044
  model.setFeatureHeight(height !== '' && !Number.isNaN(+height) ? +height : undefined);
7943
8045
  model.setNoSpacing(noSpacing);
7944
8046
  handleClose();
7945
8047
  }
7946
- }, "Submit"))));
8048
+ }, "Submit"), /*#__PURE__*/React.createElement(Button, {
8049
+ variant: "contained",
8050
+ color: "secondary",
8051
+ onClick: function onClick() {
8052
+ return handleClose();
8053
+ }
8054
+ }, "Cancel"))));
7947
8055
  }
7948
8056
 
7949
8057
  var SetFeatureHeight = /*#__PURE__*/observer(SetFeatureHeightDlg$1);
@@ -7953,7 +8061,7 @@ var SetFeatureHeight$1 = {
7953
8061
  'default': SetFeatureHeight
7954
8062
  };
7955
8063
 
7956
- var useStyles$4 = /*#__PURE__*/makeStyles(function (theme) {
8064
+ var useStyles$5 = /*#__PURE__*/makeStyles(function (theme) {
7957
8065
  return {
7958
8066
  root: {
7959
8067
  width: 500
@@ -7973,7 +8081,7 @@ var useStyles$4 = /*#__PURE__*/makeStyles(function (theme) {
7973
8081
  function SetMaxHeightDlg$1(props) {
7974
8082
  var model = props.model,
7975
8083
  handleClose = props.handleClose;
7976
- var classes = useStyles$4();
8084
+ var classes = useStyles$5();
7977
8085
  var _model$maxHeight = model.maxHeight,
7978
8086
  maxHeight = _model$maxHeight === void 0 ? '' : _model$maxHeight;
7979
8087
 
@@ -7985,32 +8093,34 @@ function SetMaxHeightDlg$1(props) {
7985
8093
  return /*#__PURE__*/React.createElement(Dialog, {
7986
8094
  open: true,
7987
8095
  onClose: handleClose
7988
- }, /*#__PURE__*/React.createElement(DialogTitle, {
7989
- id: "alert-dialog-title"
7990
- }, "Filter options", /*#__PURE__*/React.createElement(IconButton, {
8096
+ }, /*#__PURE__*/React.createElement(DialogTitle, null, "Filter options", /*#__PURE__*/React.createElement(IconButton, {
7991
8097
  "aria-label": "close",
7992
8098
  className: classes.closeButton,
7993
8099
  onClick: handleClose
7994
- }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement("div", {
8100
+ }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, {
7995
8101
  className: classes.root
7996
- }, /*#__PURE__*/React.createElement(Typography$1, null, "Set max height for the track"), /*#__PURE__*/React.createElement(TextField, {
8102
+ }, /*#__PURE__*/React.createElement(Typography$1, null, "Set max height for the track. For example, you can increase this if the layout says \"Max height reached\""), /*#__PURE__*/React.createElement(TextField, {
7997
8103
  value: max,
7998
8104
  onChange: function onChange(event) {
7999
8105
  setMax(event.target.value);
8000
8106
  },
8001
8107
  placeholder: "Enter max height for layout"
8002
- }), /*#__PURE__*/React.createElement(Button, {
8108
+ }), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button, {
8003
8109
  variant: "contained",
8004
8110
  color: "primary",
8005
8111
  type: "submit",
8006
- style: {
8007
- marginLeft: 20
8008
- },
8112
+ autoFocus: true,
8009
8113
  onClick: function onClick() {
8010
8114
  model.setMaxHeight(max !== '' && !Number.isNaN(+max) ? +max : undefined);
8011
8115
  handleClose();
8012
8116
  }
8013
- }, "Submit"))));
8117
+ }, "Submit"), /*#__PURE__*/React.createElement(Button, {
8118
+ variant: "contained",
8119
+ color: "secondary",
8120
+ onClick: function onClick() {
8121
+ return handleClose();
8122
+ }
8123
+ }, "Cancel"))));
8014
8124
  }
8015
8125
 
8016
8126
  var SetMaxHeight = /*#__PURE__*/observer(SetMaxHeightDlg$1);
@@ -8020,9 +8130,8 @@ var SetMaxHeight$1 = {
8020
8130
  'default': SetMaxHeight
8021
8131
  };
8022
8132
 
8023
- var useStyles$5 = /*#__PURE__*/makeStyles(function (theme) {
8133
+ var useStyles$6 = /*#__PURE__*/makeStyles(function (theme) {
8024
8134
  return {
8025
- root: {},
8026
8135
  closeButton: {
8027
8136
  position: 'absolute',
8028
8137
  right: theme.spacing(1),
@@ -8041,7 +8150,7 @@ var useStyles$5 = /*#__PURE__*/makeStyles(function (theme) {
8041
8150
 
8042
8151
  function ModificationTable(_ref) {
8043
8152
  var modifications = _ref.modifications;
8044
- var classes = useStyles$5();
8153
+ var classes = useStyles$6();
8045
8154
  return /*#__PURE__*/React.createElement("table", {
8046
8155
  className: classes.table
8047
8156
  }, /*#__PURE__*/React.createElement("tbody", null, modifications.map(function (_ref2) {
@@ -8061,7 +8170,7 @@ function ModificationTable(_ref) {
8061
8170
  }
8062
8171
 
8063
8172
  function ColorByTagDlg$2(props) {
8064
- var classes = useStyles$5();
8173
+ var classes = useStyles$6();
8065
8174
  var model = props.model,
8066
8175
  handleClose = props.handleClose;
8067
8176
  var colorBy = model.colorBy,
@@ -8076,9 +8185,7 @@ function ColorByTagDlg$2(props) {
8076
8185
  "aria-label": "close",
8077
8186
  className: classes.closeButton,
8078
8187
  onClick: handleClose
8079
- }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement("div", {
8080
- className: classes.root
8081
- }, /*#__PURE__*/React.createElement(Typography$1, 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.createElement(Typography$1, null, "Note: you can revisit this dialog to see the current mapping of colors to modification type for the modification coloring mode"), /*#__PURE__*/React.createElement("div", {
8188
+ }, /*#__PURE__*/React.createElement(CloseIcon, null))), /*#__PURE__*/React.createElement(DialogContent, null, /*#__PURE__*/React.createElement(Typography$1, 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.createElement(Typography$1, null, "Note: you can revisit this dialog to see the current mapping of colors to modification type for the modification coloring mode"), /*#__PURE__*/React.createElement("div", {
8082
8189
  style: {
8083
8190
  margin: 20
8084
8191
  }
@@ -8088,11 +8195,7 @@ function ColorByTagDlg$2(props) {
8088
8195
  size: 15
8089
8196
  }))) : null, (colorBy === null || colorBy === void 0 ? void 0 : colorBy.type) === 'methylation' ? /*#__PURE__*/React.createElement(ModificationTable, {
8090
8197
  modifications: [['methylated', 'red'], ['unmethylated', 'blue']]
8091
- }) : null), /*#__PURE__*/React.createElement("div", {
8092
- style: {
8093
- display: 'flex'
8094
- }
8095
- }, /*#__PURE__*/React.createElement(Button, {
8198
+ }) : null), /*#__PURE__*/React.createElement(DialogActions, null, /*#__PURE__*/React.createElement(Button, {
8096
8199
  variant: "contained",
8097
8200
  color: "primary",
8098
8201
  style: {
@@ -8125,7 +8228,7 @@ function ColorByTagDlg$2(props) {
8125
8228
  onClick: function onClick() {
8126
8229
  return handleClose();
8127
8230
  }
8128
- }, "Cancel")))));
8231
+ }, "Cancel"))));
8129
8232
  }
8130
8233
 
8131
8234
  var ColorByModifications = /*#__PURE__*/observer(ColorByTagDlg$2);
@@ -8135,7 +8238,7 @@ var ColorByModifications$1 = {
8135
8238
  'default': ColorByModifications
8136
8239
  };
8137
8240
 
8138
- var useStyles$6 = /*#__PURE__*/makeStyles(function () {
8241
+ var useStyles$7 = /*#__PURE__*/makeStyles(function () {
8139
8242
  return {
8140
8243
  compact: {
8141
8244
  paddingRight: 0,
@@ -8147,7 +8250,7 @@ var useStyles$6 = /*#__PURE__*/makeStyles(function () {
8147
8250
  var omit = ['clipPos', 'flags']; // eslint-disable-next-line @typescript-eslint/no-explicit-any
8148
8251
 
8149
8252
  function AlignmentFlags(props) {
8150
- var classes = useStyles$6();
8253
+ var classes = useStyles$7();
8151
8254
  var feature = props.feature;
8152
8255
  var flags = feature.flags;
8153
8256
  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'];
@@ -8249,10 +8352,15 @@ function SupplementaryAlignments(props) {
8249
8352
  onClick: function onClick() {
8250
8353
  var view = model.view;
8251
8354
 
8252
- if (view) {
8253
- view.navToLocString(locString);
8254
- } else {
8255
- session.notify('No view associated with this feature detail panel anymore', 'warning');
8355
+ try {
8356
+ if (view) {
8357
+ view.navToLocString(locString);
8358
+ } else {
8359
+ throw new Error('No view associated with this view anymore');
8360
+ }
8361
+ } catch (e) {
8362
+ console.error(e);
8363
+ session.notify("".concat(e));
8256
8364
  }
8257
8365
  },
8258
8366
  href: "#"
@@ -8269,10 +8377,15 @@ function PairLink(_ref2) {
8269
8377
  onClick: function onClick() {
8270
8378
  var view = model.view;
8271
8379
 
8272
- if (view) {
8273
- view.navToLocString(locString);
8274
- } else {
8275
- session.notify('No view associated with this feature detail panel anymore', 'warning');
8380
+ try {
8381
+ if (view) {
8382
+ view.navToLocString(locString);
8383
+ } else {
8384
+ session.notify('No view associated with this feature detail panel anymore', 'warning');
8385
+ }
8386
+ } catch (e) {
8387
+ console.error(e);
8388
+ session.notify("".concat(e));
8276
8389
  }
8277
8390
  },
8278
8391
  href: "#"