@teselagen/ove 0.8.40 → 0.8.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AlignmentView/findAlignmentDifferences.d.ts +53 -0
- package/index.cjs.js +250 -150
- package/index.es.js +250 -150
- package/index.umd.js +250 -150
- package/ove.css +80 -0
- package/package.json +1 -1
- package/src/AlignmentView/AlignmentVisibilityTool.js +9 -11
- package/src/AlignmentView/Minimap.js +21 -3
- package/src/AlignmentView/Mismatches.js +164 -139
- package/src/AlignmentView/findAlignmentDifferences.js +116 -0
- package/src/AlignmentView/findAlignmentDifferences.test.js +208 -0
- package/src/AlignmentView/index.js +18 -2
- package/src/AlignmentView/style.css +80 -0
- package/src/redux/alignments.js +58 -20
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {"mismatch"|"insertion"|"deletion"|"gap"} DifferenceType
|
|
3
|
+
*
|
|
4
|
+
* @typedef {Object} AlignmentDifference
|
|
5
|
+
* @property {number} position - 0-based column index in the aligned sequence
|
|
6
|
+
* @property {DifferenceType} type
|
|
7
|
+
* @property {string[]} bases - bases at this column for each track (template first)
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Group consecutive same-type differences into regions.
|
|
11
|
+
* Mismatches are never grouped — each is its own entry.
|
|
12
|
+
* Insertions, deletions, and gaps that are side-by-side are collapsed into
|
|
13
|
+
* one entry with a `start` and `end` (both inclusive, 0-based).
|
|
14
|
+
*
|
|
15
|
+
* @param {AlignmentDifference[]} differences
|
|
16
|
+
* @returns {Array<AlignmentDifference & { start: number, end: number }>}
|
|
17
|
+
*/
|
|
18
|
+
export function groupConsecutiveDifferences(differences: AlignmentDifference[]): Array<AlignmentDifference & {
|
|
19
|
+
start: number;
|
|
20
|
+
end: number;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Classify alignment columns into difference types relative to the template track.
|
|
24
|
+
*
|
|
25
|
+
* Template is alignedSeqs[0]. Non-template tracks are alignedSeqs[1+].
|
|
26
|
+
*
|
|
27
|
+
* Classification rules (per column):
|
|
28
|
+
* - "gap" : no non-template track is in its aligned region at this position
|
|
29
|
+
* - "insertion" : template has '-', at least one aligned non-template has a non-gap base
|
|
30
|
+
* - "deletion" : template has a non-gap base, at least one aligned non-template has '-'
|
|
31
|
+
* - "mismatch" : no gaps among aligned tracks, unique base set has more than one member
|
|
32
|
+
*
|
|
33
|
+
* Only tracks whose aligned region covers position i participate in classification.
|
|
34
|
+
* This correctly handles multi-read alignments (e.g. Sanger) where reads cover
|
|
35
|
+
* different sub-ranges of the full alignment.
|
|
36
|
+
*
|
|
37
|
+
* @param {string[]} alignedSeqs - Aligned sequence strings, all same length
|
|
38
|
+
* @returns {AlignmentDifference[]}
|
|
39
|
+
*/
|
|
40
|
+
export function findAlignmentDifferences(alignedSeqs: string[]): AlignmentDifference[];
|
|
41
|
+
export default findAlignmentDifferences;
|
|
42
|
+
export type DifferenceType = "mismatch" | "insertion" | "deletion" | "gap";
|
|
43
|
+
export type AlignmentDifference = {
|
|
44
|
+
/**
|
|
45
|
+
* - 0-based column index in the aligned sequence
|
|
46
|
+
*/
|
|
47
|
+
position: number;
|
|
48
|
+
type: DifferenceType;
|
|
49
|
+
/**
|
|
50
|
+
* - bases at this column for each track (template first)
|
|
51
|
+
*/
|
|
52
|
+
bases: string[];
|
|
53
|
+
};
|
package/index.cjs.js
CHANGED
|
@@ -95510,14 +95510,34 @@ function addHighlightedDifferences(alignmentTracks) {
|
|
|
95510
95510
|
track.alignmentData.sequence
|
|
95511
95511
|
);
|
|
95512
95512
|
const mismatches = matchHighlightRanges.filter(({ isMatch }) => !isMatch);
|
|
95513
|
+
const alignedSeq = track.alignmentData.sequence;
|
|
95514
|
+
const seqLen = alignedSeq.length;
|
|
95515
|
+
const startIndex = seqLen - alignedSeq.replace(/^-+/, "").length;
|
|
95516
|
+
const endIndex = alignedSeq.replace(/-+$/, "").length;
|
|
95517
|
+
const gapRanges = [
|
|
95518
|
+
startIndex > 0 && {
|
|
95519
|
+
start: 0,
|
|
95520
|
+
end: startIndex - 1,
|
|
95521
|
+
differenceType: "gap"
|
|
95522
|
+
},
|
|
95523
|
+
endIndex < seqLen && {
|
|
95524
|
+
start: endIndex,
|
|
95525
|
+
end: seqLen - 1,
|
|
95526
|
+
differenceType: "gap"
|
|
95527
|
+
}
|
|
95528
|
+
].filter(Boolean);
|
|
95513
95529
|
return __spreadProps(__spreadValues({}, track), {
|
|
95514
95530
|
sequenceData: sequenceData2,
|
|
95515
95531
|
matchHighlightRanges,
|
|
95516
|
-
additionalSelectionLayers:
|
|
95517
|
-
|
|
95532
|
+
additionalSelectionLayers: [
|
|
95533
|
+
...matchHighlightRanges.filter(({ isMatch }) => !isMatch).map((range2) => __spreadProps(__spreadValues(__spreadValues({}, range2), highlightRangeProps), {
|
|
95518
95534
|
className: "veAlignmentMismatch"
|
|
95519
|
-
})
|
|
95520
|
-
|
|
95535
|
+
})),
|
|
95536
|
+
...gapRanges.map((range2) => __spreadProps(__spreadValues(__spreadValues({}, range2), highlightRangeProps), {
|
|
95537
|
+
className: "veAlignmentMismatch"
|
|
95538
|
+
}))
|
|
95539
|
+
],
|
|
95540
|
+
gapRanges,
|
|
95521
95541
|
mismatches
|
|
95522
95542
|
});
|
|
95523
95543
|
});
|
|
@@ -95651,23 +95671,30 @@ function getRangeMatchesBetweenTemplateAndNonTemplate(tempSeq, nonTempSeq) {
|
|
|
95651
95671
|
const startIndex = seqLength - nonTempSeqWithoutLeadingDashes.length;
|
|
95652
95672
|
const endIndex = seqLength - (seqLength - nonTempSeqWithoutTrailingDashes.length);
|
|
95653
95673
|
for (let index2 = startIndex; index2 < endIndex; index2++) {
|
|
95654
|
-
const
|
|
95655
|
-
const
|
|
95656
|
-
|
|
95657
|
-
|
|
95658
|
-
|
|
95674
|
+
const tempBase = tempSeq[index2].toLowerCase();
|
|
95675
|
+
const nonTempBase = nonTempSeq[index2].toLowerCase();
|
|
95676
|
+
const isMatch = tempBase === nonTempBase;
|
|
95677
|
+
let differenceType = null;
|
|
95678
|
+
if (!isMatch) {
|
|
95679
|
+
if (tempBase === "-") {
|
|
95680
|
+
differenceType = "insertion";
|
|
95681
|
+
} else if (nonTempBase === "-") {
|
|
95682
|
+
differenceType = "deletion";
|
|
95659
95683
|
} else {
|
|
95660
|
-
|
|
95661
|
-
start: index2,
|
|
95662
|
-
end: index2,
|
|
95663
|
-
isMatch
|
|
95664
|
-
});
|
|
95684
|
+
differenceType = "mismatch";
|
|
95665
95685
|
}
|
|
95686
|
+
}
|
|
95687
|
+
const previousRange = ranges[ranges.length - 1];
|
|
95688
|
+
if (previousRange && previousRange.isMatch === isMatch && previousRange.differenceType === differenceType) {
|
|
95689
|
+
previousRange.end++;
|
|
95690
|
+
} else if (previousRange) {
|
|
95691
|
+
ranges.push({ start: index2, end: index2, isMatch, differenceType });
|
|
95666
95692
|
} else {
|
|
95667
95693
|
ranges.push({
|
|
95668
95694
|
start: startIndex,
|
|
95669
95695
|
end: startIndex,
|
|
95670
|
-
isMatch
|
|
95696
|
+
isMatch,
|
|
95697
|
+
differenceType
|
|
95671
95698
|
});
|
|
95672
95699
|
}
|
|
95673
95700
|
}
|
|
@@ -117245,7 +117272,7 @@ function showFileDialog({ multiple = false, onSelect }) {
|
|
|
117245
117272
|
input.click();
|
|
117246
117273
|
}
|
|
117247
117274
|
__name(showFileDialog, "showFileDialog");
|
|
117248
|
-
const version = "0.8.
|
|
117275
|
+
const version = "0.8.41";
|
|
117249
117276
|
const packageJson = {
|
|
117250
117277
|
version
|
|
117251
117278
|
};
|
|
@@ -125114,11 +125141,13 @@ const _Minimap = class _Minimap extends React.Component {
|
|
|
125114
125141
|
dimensions: { width = 200 },
|
|
125115
125142
|
laneHeight,
|
|
125116
125143
|
laneSpacing = 1,
|
|
125117
|
-
isTrackSelected = []
|
|
125144
|
+
isTrackSelected = [],
|
|
125145
|
+
activeFilterType = "all"
|
|
125118
125146
|
} = this.props;
|
|
125119
125147
|
const charWidth2 = this.getCharWidth();
|
|
125120
125148
|
const {
|
|
125121
125149
|
matchHighlightRanges: _matchHighlightRanges,
|
|
125150
|
+
gapRanges = [],
|
|
125122
125151
|
alignmentData: { trimmedRange } = {}
|
|
125123
125152
|
} = alignmentTracks[i];
|
|
125124
125153
|
const matchHighlightRanges = !trimmedRange ? _matchHighlightRanges : flatMap(_matchHighlightRanges, (r2) => {
|
|
@@ -125145,10 +125174,19 @@ const _Minimap = class _Minimap extends React.Component {
|
|
|
125145
125174
|
charWidth2
|
|
125146
125175
|
);
|
|
125147
125176
|
const toAdd = `M${xStart},${y2} L${xStart + width2},${y2} L${xStart + width2},${y2 + height} L${xStart},${y2 + height}`;
|
|
125148
|
-
if (!range2.isMatch) {
|
|
125177
|
+
if (!range2.isMatch && (activeFilterType === "all" || range2.differenceType === activeFilterType)) {
|
|
125149
125178
|
redPath += toAdd;
|
|
125150
125179
|
}
|
|
125151
125180
|
});
|
|
125181
|
+
if (activeFilterType === "gap") {
|
|
125182
|
+
gapRanges.forEach((range2) => {
|
|
125183
|
+
const { xStart, width: width2 } = getXStartAndWidthFromNonCircularRange(
|
|
125184
|
+
range2,
|
|
125185
|
+
charWidth2
|
|
125186
|
+
);
|
|
125187
|
+
redPath += `M${xStart},${y2} L${xStart + width2},${y2} L${xStart + width2},${y2 + height} L${xStart},${y2 + height}`;
|
|
125188
|
+
});
|
|
125189
|
+
}
|
|
125152
125190
|
return /* @__PURE__ */ React.createElement(
|
|
125153
125191
|
"div",
|
|
125154
125192
|
{
|
|
@@ -125178,7 +125216,8 @@ const _Minimap = class _Minimap extends React.Component {
|
|
|
125178
125216
|
"scrollAlignmentView",
|
|
125179
125217
|
"laneHeight",
|
|
125180
125218
|
"laneSpacing",
|
|
125181
|
-
"isTrackSelected"
|
|
125219
|
+
"isTrackSelected",
|
|
125220
|
+
"activeFilterType"
|
|
125182
125221
|
].some((key) => props[key] !== newProps[key]))
|
|
125183
125222
|
return true;
|
|
125184
125223
|
return false;
|
|
@@ -125456,6 +125495,66 @@ function getTrimmedRangesToDisplay({ trimmedRange, seqLen }) {
|
|
|
125456
125495
|
return splitRangeIntoTwoPartsIfItIsCircular(inverted, seqLen);
|
|
125457
125496
|
}
|
|
125458
125497
|
__name(getTrimmedRangesToDisplay, "getTrimmedRangesToDisplay");
|
|
125498
|
+
function groupConsecutiveDifferences(differences) {
|
|
125499
|
+
const grouped = [];
|
|
125500
|
+
for (const diff of differences) {
|
|
125501
|
+
if (diff.type === "mismatch") {
|
|
125502
|
+
grouped.push(__spreadProps(__spreadValues({}, diff), { start: diff.position, end: diff.position }));
|
|
125503
|
+
continue;
|
|
125504
|
+
}
|
|
125505
|
+
const last2 = grouped[grouped.length - 1];
|
|
125506
|
+
if (last2 && last2.type === diff.type && last2.end === diff.position - 1) {
|
|
125507
|
+
grouped[grouped.length - 1] = __spreadProps(__spreadValues({}, last2), { end: diff.position });
|
|
125508
|
+
} else {
|
|
125509
|
+
grouped.push(__spreadProps(__spreadValues({}, diff), { start: diff.position, end: diff.position }));
|
|
125510
|
+
}
|
|
125511
|
+
}
|
|
125512
|
+
return grouped;
|
|
125513
|
+
}
|
|
125514
|
+
__name(groupConsecutiveDifferences, "groupConsecutiveDifferences");
|
|
125515
|
+
function findAlignmentDifferences(alignedSeqs) {
|
|
125516
|
+
var _a2;
|
|
125517
|
+
if (alignedSeqs.length < 2 || !((_a2 = alignedSeqs[0]) == null ? void 0 : _a2.length)) return [];
|
|
125518
|
+
const template = alignedSeqs[0].toLowerCase();
|
|
125519
|
+
const nonTemplates = alignedSeqs.slice(1).map((s2) => s2.toLowerCase());
|
|
125520
|
+
const trackBounds = nonTemplates.map((seq) => {
|
|
125521
|
+
const withoutLeading = seq.replace(/^-+/, "");
|
|
125522
|
+
const withoutTrailing = seq.replace(/-+$/, "");
|
|
125523
|
+
const start2 = seq.length - withoutLeading.length;
|
|
125524
|
+
const end2 = seq.length - (seq.length - withoutTrailing.length);
|
|
125525
|
+
return { start: start2, end: end2 };
|
|
125526
|
+
});
|
|
125527
|
+
const differences = [];
|
|
125528
|
+
for (let i = 0; i < template.length; i++) {
|
|
125529
|
+
const templateBase = template[i];
|
|
125530
|
+
const allNonTemplateBases = nonTemplates.map((seq) => seq[i]);
|
|
125531
|
+
const bases = [templateBase, ...allNonTemplateBases];
|
|
125532
|
+
const alignedIndices = trackBounds.reduce((acc, { start: start2, end: end2 }, idx) => {
|
|
125533
|
+
if (i >= start2 && i < end2) acc.push(idx);
|
|
125534
|
+
return acc;
|
|
125535
|
+
}, []);
|
|
125536
|
+
if (alignedIndices.length === 0) {
|
|
125537
|
+
differences.push({ position: i, type: "gap", bases });
|
|
125538
|
+
continue;
|
|
125539
|
+
}
|
|
125540
|
+
const alignedBases = alignedIndices.map((idx) => allNonTemplateBases[idx]);
|
|
125541
|
+
const templateIsGap = templateBase === "-";
|
|
125542
|
+
const nonTemplateHasBase = alignedBases.some((b3) => b3 !== "-");
|
|
125543
|
+
const nonTemplateHasGap = alignedBases.some((b3) => b3 === "-");
|
|
125544
|
+
if (templateIsGap && nonTemplateHasBase) {
|
|
125545
|
+
differences.push({ position: i, type: "insertion", bases });
|
|
125546
|
+
} else if (!templateIsGap && nonTemplateHasGap) {
|
|
125547
|
+
differences.push({ position: i, type: "deletion", bases });
|
|
125548
|
+
} else if (!templateIsGap) {
|
|
125549
|
+
const uniqueBases = /* @__PURE__ */ new Set([templateBase, ...alignedBases]);
|
|
125550
|
+
if (uniqueBases.size > 1) {
|
|
125551
|
+
differences.push({ position: i, type: "mismatch", bases });
|
|
125552
|
+
}
|
|
125553
|
+
}
|
|
125554
|
+
}
|
|
125555
|
+
return differences;
|
|
125556
|
+
}
|
|
125557
|
+
__name(findAlignmentDifferences, "findAlignmentDifferences");
|
|
125459
125558
|
function scrollToAlignmentSelection() {
|
|
125460
125559
|
const el = document.querySelector(".veCaret");
|
|
125461
125560
|
if (el) {
|
|
@@ -125469,159 +125568,145 @@ function updateCaretPosition({ start: start2, end: end2 }) {
|
|
|
125469
125568
|
}
|
|
125470
125569
|
}
|
|
125471
125570
|
__name(updateCaretPosition, "updateCaretPosition");
|
|
125571
|
+
const FILTER_OPTIONS = [
|
|
125572
|
+
{ value: "all", label: "All" },
|
|
125573
|
+
{ value: "mismatch", label: "Mismatches" },
|
|
125574
|
+
{ value: "insertion", label: "Insertions" },
|
|
125575
|
+
{ value: "deletion", label: "Deletions" },
|
|
125576
|
+
{ value: "gap", label: "Gaps" }
|
|
125577
|
+
];
|
|
125472
125578
|
function FindMismatches(props) {
|
|
125473
|
-
|
|
125579
|
+
var _a2;
|
|
125580
|
+
const { alignmentJson, id: id2, onFilterChange } = props;
|
|
125474
125581
|
const alignedSeqs = React.useMemo(
|
|
125475
125582
|
() => alignmentJson.map((t2) => {
|
|
125476
|
-
var
|
|
125477
|
-
return ((
|
|
125583
|
+
var _a3;
|
|
125584
|
+
return ((_a3 = t2.alignmentData) == null ? void 0 : _a3.sequence) || "";
|
|
125478
125585
|
}),
|
|
125479
125586
|
[alignmentJson]
|
|
125480
125587
|
);
|
|
125481
|
-
const
|
|
125482
|
-
|
|
125483
|
-
|
|
125484
|
-
|
|
125485
|
-
|
|
125486
|
-
|
|
125487
|
-
|
|
125488
|
-
|
|
125489
|
-
|
|
125490
|
-
|
|
125491
|
-
}
|
|
125492
|
-
return
|
|
125493
|
-
}, [
|
|
125588
|
+
const [activeFilter, setActiveFilter] = React.useState("all");
|
|
125589
|
+
const allDifferences = React.useMemo(
|
|
125590
|
+
() => groupConsecutiveDifferences(findAlignmentDifferences(alignedSeqs)),
|
|
125591
|
+
[alignedSeqs]
|
|
125592
|
+
);
|
|
125593
|
+
const countsByType = React.useMemo(() => {
|
|
125594
|
+
const counts = { all: 0, mismatch: 0, insertion: 0, deletion: 0, gap: 0 };
|
|
125595
|
+
allDifferences.forEach((d2) => {
|
|
125596
|
+
counts[d2.type] = (counts[d2.type] || 0) + 1;
|
|
125597
|
+
counts.all++;
|
|
125598
|
+
});
|
|
125599
|
+
return counts;
|
|
125600
|
+
}, [allDifferences]);
|
|
125601
|
+
const differences = React.useMemo(() => {
|
|
125602
|
+
const filtered = activeFilter === "all" ? allDifferences : allDifferences.filter((d2) => d2.type === activeFilter);
|
|
125603
|
+
return [{ position: -1, start: -1, end: -1, bases: [""] }, ...filtered];
|
|
125604
|
+
}, [allDifferences, activeFilter]);
|
|
125494
125605
|
const currentCaretPosition = reactRedux.useSelector(
|
|
125495
125606
|
(state2) => {
|
|
125496
|
-
var
|
|
125497
|
-
return (
|
|
125607
|
+
var _a3;
|
|
125608
|
+
return (_a3 = state2.VectorEditor.__allEditorsOptions.alignments[id2]) == null ? void 0 : _a3.caretPosition;
|
|
125498
125609
|
}
|
|
125499
125610
|
);
|
|
125500
125611
|
const [currentIdx, setCurrentIdx] = React.useState(0);
|
|
125501
|
-
const
|
|
125502
|
-
const
|
|
125503
|
-
const
|
|
125504
|
-
|
|
125505
|
-
(
|
|
125506
|
-
|
|
125507
|
-
|
|
125508
|
-
|
|
125509
|
-
|
|
125510
|
-
}
|
|
125511
|
-
const firstMismatchPos = mismatches[1].position;
|
|
125512
|
-
const lastMismatchPos = mismatches[mismatches.length - 1].position;
|
|
125513
|
-
setDisablePrev(caret <= firstMismatchPos);
|
|
125514
|
-
setDisableNext(caret >= lastMismatchPos);
|
|
125515
|
-
},
|
|
125516
|
-
[mismatches]
|
|
125517
|
-
);
|
|
125612
|
+
const currentDiff = differences[currentIdx];
|
|
125613
|
+
const disablePrev = currentIdx <= 1;
|
|
125614
|
+
const disableNext = currentIdx >= differences.length - 1;
|
|
125615
|
+
React.useEffect(() => {
|
|
125616
|
+
setCurrentIdx(0);
|
|
125617
|
+
}, [activeFilter]);
|
|
125618
|
+
React.useEffect(() => {
|
|
125619
|
+
onFilterChange == null ? void 0 : onFilterChange({ activeFilter });
|
|
125620
|
+
}, [activeFilter, onFilterChange]);
|
|
125518
125621
|
React.useEffect(() => {
|
|
125519
125622
|
if (currentCaretPosition !== -1) {
|
|
125520
|
-
const
|
|
125521
|
-
(
|
|
125623
|
+
const diffIdx = differences.findIndex(
|
|
125624
|
+
(d2, i) => i > 0 && currentCaretPosition >= d2.start && currentCaretPosition <= d2.end + 1
|
|
125522
125625
|
);
|
|
125523
|
-
if (
|
|
125524
|
-
|
|
125525
|
-
setCurrentIdx(mismatchIdx);
|
|
125626
|
+
if (diffIdx !== -1 && diffIdx !== currentIdx) {
|
|
125627
|
+
setCurrentIdx(diffIdx);
|
|
125526
125628
|
}
|
|
125527
125629
|
}
|
|
125528
|
-
}, [currentCaretPosition,
|
|
125529
|
-
const updateView = /* @__PURE__ */ __name((
|
|
125530
|
-
const idx =
|
|
125531
|
-
const
|
|
125532
|
-
handleButtonsState(position2);
|
|
125630
|
+
}, [currentCaretPosition, differences, currentIdx]);
|
|
125631
|
+
const updateView = /* @__PURE__ */ __name((diff) => {
|
|
125632
|
+
const idx = differences.indexOf(diff);
|
|
125633
|
+
const { start: start2, end: end2 } = diff;
|
|
125533
125634
|
setCurrentIdx(idx);
|
|
125534
|
-
updateCaretPosition({ start:
|
|
125635
|
+
updateCaretPosition({ start: start2, end: end2 });
|
|
125535
125636
|
setTimeout(() => {
|
|
125536
125637
|
scrollToAlignmentSelection();
|
|
125537
125638
|
}, 0);
|
|
125538
125639
|
}, "updateView");
|
|
125539
|
-
const
|
|
125540
|
-
|
|
125541
|
-
|
|
125542
|
-
|
|
125543
|
-
|
|
125544
|
-
|
|
125545
|
-
|
|
125546
|
-
|
|
125547
|
-
|
|
125548
|
-
|
|
125549
|
-
|
|
125550
|
-
}, "
|
|
125551
|
-
const
|
|
125552
|
-
|
|
125553
|
-
|
|
125554
|
-
|
|
125555
|
-
|
|
125556
|
-
|
|
125557
|
-
|
|
125558
|
-
|
|
125559
|
-
|
|
125560
|
-
|
|
125561
|
-
|
|
125640
|
+
const prevDifference = /* @__PURE__ */ __name(() => {
|
|
125641
|
+
var _a3, _b2;
|
|
125642
|
+
const pivot = currentCaretPosition >= 0 ? currentCaretPosition : (_b2 = (_a3 = differences[currentIdx]) == null ? void 0 : _a3.start) != null ? _b2 : 0;
|
|
125643
|
+
const prev = [...differences].reverse().find((d2) => d2.start >= 0 && d2.start < pivot);
|
|
125644
|
+
if (prev) updateView(prev);
|
|
125645
|
+
}, "prevDifference");
|
|
125646
|
+
const nextDifference = /* @__PURE__ */ __name(() => {
|
|
125647
|
+
var _a3, _b2;
|
|
125648
|
+
const pivot = currentCaretPosition >= 0 ? currentCaretPosition : (_b2 = (_a3 = differences[currentIdx]) == null ? void 0 : _a3.start) != null ? _b2 : -1;
|
|
125649
|
+
const next = differences.find((d2) => d2.start > pivot && d2.start >= 0);
|
|
125650
|
+
if (next) updateView(next);
|
|
125651
|
+
}, "nextDifference");
|
|
125652
|
+
const noDifferences = differences.length <= 1;
|
|
125653
|
+
const activeOption = FILTER_OPTIONS.find((o2) => o2.value === activeFilter);
|
|
125654
|
+
const activeLabel = (_a2 = activeOption == null ? void 0 : activeOption.label) != null ? _a2 : "Differences";
|
|
125655
|
+
const filterMenu = /* @__PURE__ */ React.createElement(core.Menu, null, FILTER_OPTIONS.map(({ value, label }) => {
|
|
125656
|
+
var _a3;
|
|
125657
|
+
const count2 = (_a3 = countsByType[value]) != null ? _a3 : 0;
|
|
125658
|
+
const isActive2 = activeFilter === value;
|
|
125659
|
+
return /* @__PURE__ */ React.createElement(
|
|
125660
|
+
core.MenuItem,
|
|
125661
|
+
{
|
|
125662
|
+
key: value,
|
|
125663
|
+
active: isActive2,
|
|
125664
|
+
onClick: /* @__PURE__ */ __name(() => setActiveFilter(value), "onClick"),
|
|
125665
|
+
text: /* @__PURE__ */ React.createElement("span", { className: "veDiffMenuItem-inner" }, label, /* @__PURE__ */ React.createElement(core.Tag, { round: true, minimal: true, style: { marginLeft: 6 } }, count2))
|
|
125562
125666
|
}
|
|
125563
|
-
|
|
125564
|
-
}
|
|
125565
|
-
return /* @__PURE__ */ React.createElement(
|
|
125566
|
-
|
|
125667
|
+
);
|
|
125668
|
+
}));
|
|
125669
|
+
return /* @__PURE__ */ React.createElement("div", { className: "veDiffNavigator" }, /* @__PURE__ */ React.createElement(
|
|
125670
|
+
core.Popover,
|
|
125567
125671
|
{
|
|
125568
|
-
|
|
125569
|
-
|
|
125570
|
-
|
|
125571
|
-
|
|
125572
|
-
alignItems: "center",
|
|
125573
|
-
gap: 10
|
|
125574
|
-
}
|
|
125575
|
-
},
|
|
125576
|
-
mismatches.length === 1 ? /* @__PURE__ */ React.createElement("span", { style: { fontStyle: "italic", color: "grey" } }, "no mismatches") : /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React.createElement(
|
|
125577
|
-
"div",
|
|
125578
|
-
{
|
|
125579
|
-
style: {
|
|
125580
|
-
display: "flex",
|
|
125581
|
-
alignItems: "center"
|
|
125582
|
-
}
|
|
125583
|
-
},
|
|
125584
|
-
/* @__PURE__ */ React.createElement("strong", null, "Mismatches"),
|
|
125585
|
-
/* @__PURE__ */ React.createElement("div", { style: { display: "flex", gap: 2 } }, /* @__PURE__ */ React.createElement(
|
|
125586
|
-
core.Button,
|
|
125587
|
-
{
|
|
125588
|
-
intent: "primary",
|
|
125589
|
-
icon: "arrow-left",
|
|
125590
|
-
"data-tip": "Previous Mismatch",
|
|
125591
|
-
onClick: prevMismatch,
|
|
125592
|
-
disabled: disablePrev,
|
|
125593
|
-
small: true,
|
|
125594
|
-
minimal: true
|
|
125595
|
-
}
|
|
125596
|
-
), /* @__PURE__ */ React.createElement(
|
|
125672
|
+
minimal: true,
|
|
125673
|
+
position: core.Position.BOTTOM_LEFT,
|
|
125674
|
+
content: filterMenu,
|
|
125675
|
+
target: /* @__PURE__ */ React.createElement(
|
|
125597
125676
|
core.Button,
|
|
125598
125677
|
{
|
|
125599
|
-
|
|
125600
|
-
|
|
125601
|
-
"data-tip": "Next Mismatch",
|
|
125602
|
-
onClick: nextMismatch,
|
|
125603
|
-
disabled: disableNext,
|
|
125678
|
+
minimal: true,
|
|
125679
|
+
"data-tip": "Filter Difference Type",
|
|
125604
125680
|
small: true,
|
|
125605
|
-
|
|
125606
|
-
|
|
125607
|
-
|
|
125608
|
-
|
|
125609
|
-
|
|
125610
|
-
|
|
125611
|
-
|
|
125612
|
-
|
|
125613
|
-
|
|
125614
|
-
|
|
125615
|
-
|
|
125616
|
-
|
|
125617
|
-
|
|
125618
|
-
|
|
125619
|
-
|
|
125620
|
-
|
|
125621
|
-
|
|
125622
|
-
|
|
125623
|
-
|
|
125624
|
-
|
|
125681
|
+
rightIcon: "caret-down",
|
|
125682
|
+
className: "veDiffFilter-trigger"
|
|
125683
|
+
},
|
|
125684
|
+
activeLabel
|
|
125685
|
+
)
|
|
125686
|
+
}
|
|
125687
|
+
), noDifferences ? /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-empty" }, "no", " ", activeFilter === "all" ? "differences" : activeLabel.toLowerCase()) : /* @__PURE__ */ React.createElement("div", { className: "veDiffNav" }, /* @__PURE__ */ React.createElement(
|
|
125688
|
+
core.Button,
|
|
125689
|
+
{
|
|
125690
|
+
minimal: true,
|
|
125691
|
+
small: true,
|
|
125692
|
+
"data-tip": "Previous Difference",
|
|
125693
|
+
icon: "arrow-left",
|
|
125694
|
+
intent: core.Intent.PRIMARY,
|
|
125695
|
+
onClick: prevDifference,
|
|
125696
|
+
disabled: disablePrev
|
|
125697
|
+
}
|
|
125698
|
+
), /* @__PURE__ */ React.createElement("div", { className: "veDiffNav-center" }, /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-fraction" }, currentIdx, /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-sep" }, "/"), differences.length - 1), (currentDiff == null ? void 0 : currentDiff.start) > -1 && /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-pos" }, ":", currentDiff.start + 1)), /* @__PURE__ */ React.createElement(
|
|
125699
|
+
core.Button,
|
|
125700
|
+
{
|
|
125701
|
+
minimal: true,
|
|
125702
|
+
small: true,
|
|
125703
|
+
"data-tip": "Next Difference",
|
|
125704
|
+
icon: "arrow-right",
|
|
125705
|
+
intent: core.Intent.PRIMARY,
|
|
125706
|
+
onClick: nextDifference,
|
|
125707
|
+
disabled: disableNext
|
|
125708
|
+
}
|
|
125709
|
+
)));
|
|
125625
125710
|
}
|
|
125626
125711
|
__name(FindMismatches, "FindMismatches");
|
|
125627
125712
|
function getGapMap(sequence2) {
|
|
@@ -126310,17 +126395,18 @@ const AlignmentVisibilityTool = pure(/* @__PURE__ */ __name(function AlignmentVi
|
|
|
126310
126395
|
minimal: true,
|
|
126311
126396
|
position: "bottom",
|
|
126312
126397
|
content: /* @__PURE__ */ React.createElement(VisibilityOptions$2, __spreadValues({}, props)),
|
|
126313
|
-
target: /* @__PURE__ */ React.createElement(
|
|
126398
|
+
target: /* @__PURE__ */ React.createElement(
|
|
126314
126399
|
core.Button,
|
|
126315
126400
|
{
|
|
126316
126401
|
className: "tg-alignment-visibility-toggle",
|
|
126317
126402
|
small: true,
|
|
126403
|
+
"data-tip": "Visibility Options",
|
|
126318
126404
|
rightIcon: "caret-down",
|
|
126319
126405
|
intent: core.Intent.PRIMARY,
|
|
126320
126406
|
minimal: true,
|
|
126321
126407
|
icon: "eye-open"
|
|
126322
126408
|
}
|
|
126323
|
-
)
|
|
126409
|
+
)
|
|
126324
126410
|
}
|
|
126325
126411
|
);
|
|
126326
126412
|
}, "AlignmentVisibilityTool"));
|
|
@@ -140108,6 +140194,10 @@ const AlignmentView = /* @__PURE__ */ __name((props) => {
|
|
|
140108
140194
|
const [tempTrimAfter, setTempTrimAfter] = React.useState({});
|
|
140109
140195
|
const [tempTrimmingCaret, setTempTrimmingCaret] = React.useState({});
|
|
140110
140196
|
const [searchMatchLayers, setSearchMatchLayers] = React.useState([]);
|
|
140197
|
+
const [activeFilterType, setActiveFilterType] = React.useState("all");
|
|
140198
|
+
const handleFilterChange = React.useCallback(({ activeFilter }) => {
|
|
140199
|
+
setActiveFilterType(activeFilter);
|
|
140200
|
+
}, []);
|
|
140111
140201
|
const bindOutsideChangeHelper = React.useRef({});
|
|
140112
140202
|
const alignmentHolder = React.useRef(null);
|
|
140113
140203
|
const alignmentHolderTop = React.useRef(null);
|
|
@@ -140833,7 +140923,9 @@ ${seqDataToCopy}\r
|
|
|
140833
140923
|
chromatogramData
|
|
140834
140924
|
}) : linearViewOptions)), {
|
|
140835
140925
|
additionalSelectionLayers: [
|
|
140836
|
-
...additionalSelectionLayers || []
|
|
140926
|
+
...i !== 0 ? (additionalSelectionLayers || []).filter(
|
|
140927
|
+
(layer) => activeFilterType === "all" ? layer.differenceType !== "gap" : layer.differenceType === activeFilterType
|
|
140928
|
+
) : additionalSelectionLayers || [],
|
|
140837
140929
|
...searchMatchLayers || []
|
|
140838
140930
|
],
|
|
140839
140931
|
dimensions: {
|
|
@@ -141492,7 +141584,14 @@ ${seqDataToCopy}\r
|
|
|
141492
141584
|
setSearchMatchLayers
|
|
141493
141585
|
}
|
|
141494
141586
|
),
|
|
141495
|
-
/* @__PURE__ */ React.createElement(
|
|
141587
|
+
/* @__PURE__ */ React.createElement(
|
|
141588
|
+
FindMismatches,
|
|
141589
|
+
{
|
|
141590
|
+
alignmentJson: alignmentTracks,
|
|
141591
|
+
id: id2,
|
|
141592
|
+
onFilterChange: handleFilterChange
|
|
141593
|
+
}
|
|
141594
|
+
),
|
|
141496
141595
|
additionalTopEl,
|
|
141497
141596
|
saveMessage && /* @__PURE__ */ React.createElement(
|
|
141498
141597
|
"div",
|
|
@@ -141593,6 +141692,7 @@ ${seqDataToCopy}\r
|
|
|
141593
141692
|
}
|
|
141594
141693
|
)),
|
|
141595
141694
|
alignmentTracks,
|
|
141695
|
+
activeFilterType,
|
|
141596
141696
|
dimensions: {
|
|
141597
141697
|
width: Math.max(width, 10) || 10
|
|
141598
141698
|
},
|