@teselagen/sequence-utils 0.3.41 → 0.3.42-beta.1
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/DNAComplementMap.d.ts +1 -1
- package/README.md +2 -8
- package/addGapsToSeqReads.d.ts +16 -3
- package/adjustAnnotationsToInsert.d.ts +2 -1
- package/adjustBpsToReplaceOrInsert.d.ts +2 -1
- package/aliasedEnzymesByName.d.ts +37 -1
- package/aminoAcidToDegenerateDnaMap.d.ts +1 -31
- package/aminoAcidToDegenerateRnaMap.d.ts +1 -1
- package/annotateSingleSeq.d.ts +5 -4
- package/annotationTypes.d.ts +2 -2
- package/autoAnnotate.d.ts +17 -8
- package/bioData.d.ts +10 -58
- package/calculateEndStability.d.ts +1 -1
- package/calculateNebTa.d.ts +6 -1
- package/calculateNebTm.d.ts +6 -4
- package/calculatePercentGC.d.ts +1 -1
- package/calculateSantaLuciaTm.d.ts +28 -114
- package/calculateTm.d.ts +13 -1
- package/computeDigestFragments.d.ts +30 -24
- package/condensePairwiseAlignmentDifferences.d.ts +1 -1
- package/convertAACaretPositionOrRangeToDna.d.ts +2 -1
- package/convertDnaCaretPositionOrRangeToAA.d.ts +2 -1
- package/cutSequenceByRestrictionEnzyme.d.ts +2 -1
- package/defaultEnzymesByName.d.ts +2 -1
- package/degenerateDnaToAminoAcidMap.d.ts +1 -1
- package/degenerateRnaToAminoAcidMap.d.ts +1 -1
- package/deleteSequenceDataAtRange.d.ts +2 -1
- package/diffUtils.d.ts +9 -7
- package/doesEnzymeChopOutsideOfRecognitionSite.d.ts +2 -1
- package/featureTypesAndColors.d.ts +19 -6
- package/filterSequenceString.d.ts +14 -10
- package/findApproxMatches.d.ts +7 -1
- package/findNearestRangeOfSequenceOverlapToPosition.d.ts +2 -1
- package/findOrfsInPlasmid.d.ts +2 -11
- package/findSequenceMatches.d.ts +11 -1
- package/generateAnnotations.d.ts +2 -1
- package/generateSequenceData.d.ts +8 -13
- package/getAllInsertionsInSeqReads.d.ts +11 -1
- package/getAminoAcidDataForEachBaseOfDna.d.ts +6 -5
- package/getAminoAcidFromSequenceTriplet.d.ts +1 -1
- package/getAminoAcidStringFromSequenceString.d.ts +3 -1
- package/getCodonRangeForAASliver.d.ts +3 -4
- package/getComplementAminoAcidStringFromSequenceString.d.ts +1 -1
- package/getComplementSequenceAndAnnotations.d.ts +5 -1
- package/getComplementSequenceString.d.ts +1 -1
- package/getCutsiteType.d.ts +2 -1
- package/getCutsitesFromSequence.d.ts +2 -1
- package/getDegenerateDnaStringFromAAString.d.ts +1 -1
- package/getDegenerateRnaStringFromAAString.d.ts +1 -1
- package/getDigestFragmentsForCutsites.d.ts +4 -1
- package/getDigestFragmentsForRestrictionEnzymes.d.ts +8 -1
- package/getInsertBetweenVals.d.ts +2 -1
- package/getLeftAndRightOfSequenceInRangeGivenPosition.d.ts +2 -1
- package/getOrfsFromSequence.d.ts +17 -11
- package/getOverlapBetweenTwoSequences.d.ts +2 -1
- package/getPossiblePartsFromSequenceAndEnzymes.d.ts +18 -1
- package/getReverseAminoAcidStringFromSequenceString.d.ts +1 -1
- package/getReverseComplementAminoAcidStringFromSequenceString.d.ts +1 -1
- package/getReverseComplementAnnotation.d.ts +11 -1
- package/getReverseComplementSequenceAndAnnotations.d.ts +5 -1
- package/getReverseComplementSequenceString.d.ts +1 -1
- package/getReverseSequenceString.d.ts +1 -1
- package/getSequenceDataBetweenRange.d.ts +9 -1
- package/getVirtualDigest.d.ts +11 -10
- package/guessIfSequenceIsDnaAndNotProtein.d.ts +5 -1
- package/index.cjs +762 -495
- package/index.d.ts +9 -5
- package/index.js +763 -496
- package/index.umd.cjs +762 -495
- package/insertGapsIntoRefSeq.d.ts +2 -1
- package/insertSequenceDataAtPositionOrRange.d.ts +10 -1
- package/isEnzymeType2S.d.ts +2 -1
- package/mapAnnotationsToRows.d.ts +9 -1
- package/package.json +9 -6
- package/prepareCircularViewData.d.ts +2 -1
- package/prepareRowData.d.ts +7 -3
- package/proteinAlphabet.d.ts +1 -1
- package/rotateBpsToPosition.d.ts +1 -1
- package/rotateSequenceDataToPosition.d.ts +3 -1
- package/shiftAnnotationsByLen.d.ts +4 -3
- package/src/{addGapsToSeqReads.js → addGapsToSeqReads.ts} +33 -14
- package/src/{adjustAnnotationsToInsert.js → adjustAnnotationsToInsert.ts} +6 -5
- package/src/{adjustBpsToReplaceOrInsert.js → adjustBpsToReplaceOrInsert.ts} +31 -8
- package/src/{aliasedEnzymesByName.js → aliasedEnzymesByName.ts} +4 -1
- package/src/{aminoAcidToDegenerateDnaMap.js → aminoAcidToDegenerateDnaMap.ts} +1 -1
- package/src/{annotateSingleSeq.js → annotateSingleSeq.ts} +11 -3
- package/src/autoAnnotate.test.js +0 -1
- package/src/{autoAnnotate.js → autoAnnotate.ts} +69 -24
- package/src/{bioData.js → bioData.ts} +2 -2
- package/src/{calculateEndStability.js → calculateEndStability.ts} +21 -16
- package/src/{calculateNebTa.js → calculateNebTa.ts} +20 -8
- package/src/{calculateNebTm.js → calculateNebTm.ts} +15 -9
- package/src/{calculatePercentGC.js → calculatePercentGC.ts} +1 -1
- package/src/{calculateSantaLuciaTm.js → calculateSantaLuciaTm.ts} +29 -22
- package/src/{calculateTm.js → calculateTm.ts} +50 -59
- package/src/{computeDigestFragments.js → computeDigestFragments.ts} +92 -36
- package/src/{condensePairwiseAlignmentDifferences.js → condensePairwiseAlignmentDifferences.ts} +4 -4
- package/src/{convertAACaretPositionOrRangeToDna.js → convertAACaretPositionOrRangeToDna.ts} +8 -4
- package/src/{convertDnaCaretPositionOrRangeToAA.js → convertDnaCaretPositionOrRangeToAA.ts} +8 -4
- package/src/cutSequenceByRestrictionEnzyme.ts +345 -0
- package/src/{defaultEnzymesByName.js → defaultEnzymesByName.ts} +2 -1
- package/src/deleteSequenceDataAtRange.ts +13 -0
- package/src/diffUtils.ts +80 -0
- package/src/doesEnzymeChopOutsideOfRecognitionSite.ts +16 -0
- package/src/{featureTypesAndColors.js → featureTypesAndColors.ts} +29 -14
- package/src/{filterSequenceString.js → filterSequenceString.ts} +51 -21
- package/src/{findApproxMatches.js → findApproxMatches.ts} +14 -6
- package/src/{findNearestRangeOfSequenceOverlapToPosition.js → findNearestRangeOfSequenceOverlapToPosition.ts} +13 -9
- package/src/{findOrfsInPlasmid.js → findOrfsInPlasmid.ts} +8 -7
- package/src/{findSequenceMatches.js → findSequenceMatches.ts} +31 -13
- package/src/{generateAnnotations.js → generateAnnotations.ts} +14 -9
- package/src/{generateSequenceData.js → generateSequenceData.ts} +19 -13
- package/src/{getAllInsertionsInSeqReads.js → getAllInsertionsInSeqReads.ts} +19 -2
- package/src/{getAminoAcidDataForEachBaseOfDna.js → getAminoAcidDataForEachBaseOfDna.ts} +36 -30
- package/src/{getAminoAcidFromSequenceTriplet.js → getAminoAcidFromSequenceTriplet.ts} +9 -4
- package/src/{getAminoAcidStringFromSequenceString.js → getAminoAcidStringFromSequenceString.ts} +14 -7
- package/src/{getCodonRangeForAASliver.js → getCodonRangeForAASliver.ts} +16 -6
- package/src/{getComplementAminoAcidStringFromSequenceString.js → getComplementAminoAcidStringFromSequenceString.ts} +5 -3
- package/src/{getComplementSequenceAndAnnotations.js → getComplementSequenceAndAnnotations.ts} +8 -6
- package/src/{getComplementSequenceString.js → getComplementSequenceString.ts} +5 -2
- package/src/getCutsiteType.ts +18 -0
- package/src/getCutsitesFromSequence.ts +22 -0
- package/src/getDegenerateDnaStringFromAAString.ts +15 -0
- package/src/getDegenerateRnaStringFromAAString.ts +15 -0
- package/src/{getDigestFragmentsForCutsites.js → getDigestFragmentsForCutsites.ts} +32 -14
- package/src/getDigestFragmentsForRestrictionEnzymes.ts +50 -0
- package/src/{getInsertBetweenVals.js → getInsertBetweenVals.ts} +8 -5
- package/src/{getLeftAndRightOfSequenceInRangeGivenPosition.js → getLeftAndRightOfSequenceInRangeGivenPosition.ts} +11 -10
- package/src/{getMassOfAaString.js → getMassOfAaString.ts} +4 -2
- package/src/{getOrfsFromSequence.js → getOrfsFromSequence.ts} +27 -7
- package/src/{getOverlapBetweenTwoSequences.js → getOverlapBetweenTwoSequences.ts} +4 -4
- package/src/{getPossiblePartsFromSequenceAndEnzymes.js → getPossiblePartsFromSequenceAndEnzymes.ts} +52 -25
- package/src/{getReverseAminoAcidStringFromSequenceString.js → getReverseAminoAcidStringFromSequenceString.ts} +4 -2
- package/src/{getReverseComplementAminoAcidStringFromSequenceString.js → getReverseComplementAminoAcidStringFromSequenceString.ts} +2 -2
- package/src/{getReverseComplementAnnotation.js → getReverseComplementAnnotation.ts} +4 -2
- package/src/getReverseComplementSequenceAndAnnotations.ts +45 -0
- package/src/{getReverseComplementSequenceString.js → getReverseComplementSequenceString.ts} +4 -4
- package/src/{getReverseSequenceString.js → getReverseSequenceString.ts} +1 -1
- package/src/getSequenceDataBetweenRange.test.js +6 -3
- package/src/{getSequenceDataBetweenRange.js → getSequenceDataBetweenRange.ts} +44 -29
- package/src/{getVirtualDigest.js → getVirtualDigest.ts} +20 -9
- package/src/{guessIfSequenceIsDnaAndNotProtein.js → guessIfSequenceIsDnaAndNotProtein.ts} +11 -5
- package/src/{index.test.js → index.test.ts} +9 -5
- package/src/{index.js → index.ts} +1 -0
- package/src/{insertGapsIntoRefSeq.js → insertGapsIntoRefSeq.ts} +7 -2
- package/src/{insertSequenceDataAtPositionOrRange.js → insertSequenceDataAtPositionOrRange.ts} +130 -56
- package/src/isEnzymeType2S.ts +5 -0
- package/src/mapAnnotationsToRows.ts +256 -0
- package/src/prepareCircularViewData.ts +24 -0
- package/src/{prepareRowData.js → prepareRowData.ts} +27 -8
- package/src/prepareRowData_output1.json +1 -0
- package/src/rotateBpsToPosition.ts +12 -0
- package/src/{rotateSequenceDataToPosition.js → rotateSequenceDataToPosition.ts} +11 -8
- package/src/{shiftAnnotationsByLen.js → shiftAnnotationsByLen.ts} +12 -5
- package/src/{threeLetterSequenceStringToAminoAcidMap.js → threeLetterSequenceStringToAminoAcidMap.ts} +29 -9
- package/src/{tidyUpAnnotation.js → tidyUpAnnotation.ts} +40 -18
- package/src/{tidyUpSequenceData.js → tidyUpSequenceData.ts} +83 -39
- package/src/types.ts +98 -0
- package/threeLetterSequenceStringToAminoAcidMap.d.ts +11 -921
- package/tidyUpAnnotation.d.ts +13 -11
- package/tidyUpSequenceData.d.ts +18 -1
- package/types.d.ts +96 -0
- package/addGapsToSeqReads.test.d.ts +0 -1
- package/adjustBpsToReplaceOrInsert.test.d.ts +0 -1
- package/aminoAcidToDnaRna.test.d.ts +0 -1
- package/annotateSingleSeq.test.d.ts +0 -1
- package/autoAnnotate.test.d.ts +0 -1
- package/calculateEndStability.test.d.ts +0 -1
- package/calculateNebTa.test.d.ts +0 -1
- package/calculateNebTm.test.d.ts +0 -1
- package/calculatePercentGC.test.d.ts +0 -1
- package/calculateSantaLuciaTm.test.d.ts +0 -1
- package/calculateTm.test.d.ts +0 -1
- package/computeDigestFragments.test.d.ts +0 -1
- package/condensePairwiseAlignmentDifferences.test.d.ts +0 -1
- package/convertAACaretPositionOrRangeToDna.test.d.ts +0 -1
- package/convertDnaCaretPositionOrRangeToAA.test.d.ts +0 -1
- package/cutSequenceByRestrictionEnzyme.test.d.ts +0 -1
- package/deleteSequenceDataAtRange.test.d.ts +0 -1
- package/diffUtils.test.d.ts +0 -1
- package/doesEnzymeChopOutsideOfRecognitionSite.test.d.ts +0 -1
- package/featureTypesAndColors.test.d.ts +0 -1
- package/filterSequenceString.test.d.ts +0 -1
- package/findApproxMatches.test.d.ts +0 -1
- package/findNearestRangeOfSequenceOverlapToPosition.test.d.ts +0 -1
- package/findSequenceMatches.test.d.ts +0 -1
- package/generateSequenceData.test.d.ts +0 -1
- package/getAllInsertionsInSeqReads.test.d.ts +0 -1
- package/getAminoAcidDataForEachBaseOfDna.test.d.ts +0 -1
- package/getAminoAcidStringFromSequenceString.test.d.ts +0 -1
- package/getComplementSequenceString.test.d.ts +0 -1
- package/getDigestFragmentsForRestrictionEnzymes.test.d.ts +0 -1
- package/getInsertBetweenVals.test.d.ts +0 -1
- package/getLeftAndRightOfSequenceInRangeGivenPosition.test.d.ts +0 -1
- package/getMassofAaString.test.d.ts +0 -1
- package/getOrfsFromSequence.test.d.ts +0 -1
- package/getOverlapBetweenTwoSequences.test.d.ts +0 -1
- package/getPossiblePartsFromSequenceAndEnzymes.test.d.ts +0 -1
- package/getReverseAminoAcidStringFromSequenceString.test.d.ts +0 -1
- package/getReverseComplementAnnotation.test.d.ts +0 -1
- package/getReverseComplementSequenceAndAnnotations.test.d.ts +0 -1
- package/getReverseComplementSequenceString.test.d.ts +0 -1
- package/getReverseSequenceString.test.d.ts +0 -1
- package/getSequenceDataBetweenRange.test.d.ts +0 -1
- package/getVirtualDigest.test.d.ts +0 -1
- package/guessIfSequenceIsDnaAndNotProtein.test.d.ts +0 -1
- package/index.test.d.ts +0 -1
- package/insertGapsIntoRefSeq.test.d.ts +0 -1
- package/insertSequenceDataAtPosition.test.d.ts +0 -1
- package/insertSequenceDataAtPositionOrRange.test.d.ts +0 -1
- package/mapAnnotationsToRows.test.d.ts +0 -1
- package/prepareCircularViewData.test.d.ts +0 -1
- package/prepareRowData.test.d.ts +0 -1
- package/rotateBpsToPosition.test.d.ts +0 -1
- package/rotateSequenceDataToPosition.test.d.ts +0 -1
- package/src/cutSequenceByRestrictionEnzyme.js +0 -301
- package/src/deleteSequenceDataAtRange.js +0 -5
- package/src/diffUtils.js +0 -63
- package/src/doesEnzymeChopOutsideOfRecognitionSite.js +0 -10
- package/src/getCutsiteType.js +0 -10
- package/src/getCutsitesFromSequence.js +0 -17
- package/src/getDegenerateDnaStringFromAAString.js +0 -8
- package/src/getDegenerateRnaStringFromAAString.js +0 -8
- package/src/getDigestFragmentsForRestrictionEnzymes.js +0 -27
- package/src/getReverseComplementSequenceAndAnnotations.js +0 -40
- package/src/isEnzymeType2S.js +0 -3
- package/src/mapAnnotationsToRows.js +0 -174
- package/src/prepareCircularViewData.js +0 -17
- package/src/rotateBpsToPosition.js +0 -9
- package/tidyUpSequenceData.test.d.ts +0 -1
- /package/src/{DNAComplementMap.js → DNAComplementMap.ts} +0 -0
- /package/src/{aminoAcidToDegenerateRnaMap.js → aminoAcidToDegenerateRnaMap.ts} +0 -0
- /package/src/{annotationTypes.js → annotationTypes.ts} +0 -0
- /package/src/{degenerateDnaToAminoAcidMap.js → degenerateDnaToAminoAcidMap.ts} +0 -0
- /package/src/{degenerateRnaToAminoAcidMap.js → degenerateRnaToAminoAcidMap.ts} +0 -0
- /package/src/{insertSequenceDataAtPosition.js → insertSequenceDataAtPosition.ts} +0 -0
- /package/src/{proteinAlphabet.js → proteinAlphabet.ts} +0 -0
package/src/{insertSequenceDataAtPositionOrRange.js → insertSequenceDataAtPositionOrRange.ts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getRangeLength } from "@teselagen/range-utils";
|
|
1
|
+
import { getRangeLength, Range } from "@teselagen/range-utils";
|
|
2
2
|
import { map, cloneDeep } from "lodash-es";
|
|
3
3
|
import convertDnaCaretPositionOrRangeToAa from "./convertDnaCaretPositionOrRangeToAA";
|
|
4
4
|
import rotateSequenceDataToPosition from "./rotateSequenceDataToPosition";
|
|
@@ -7,13 +7,21 @@ import tidyUpSequenceData from "./tidyUpSequenceData";
|
|
|
7
7
|
import { modifiableTypes } from "./annotationTypes";
|
|
8
8
|
import adjustBpsToReplaceOrInsert from "./adjustBpsToReplaceOrInsert";
|
|
9
9
|
import adjustAnnotationsToInsert from "./adjustAnnotationsToInsert";
|
|
10
|
+
import { Annotation, ChromatogramData, SequenceData } from "./types";
|
|
11
|
+
|
|
12
|
+
interface InsertSequenceDataOptions {
|
|
13
|
+
maintainOriginSplit?: boolean;
|
|
14
|
+
doNotRemoveInvalidChars?: boolean;
|
|
15
|
+
topLevelSeqData?: SequenceData;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
10
18
|
|
|
11
19
|
export default function insertSequenceDataAtPositionOrRange(
|
|
12
|
-
_sequenceDataToInsert,
|
|
13
|
-
_existingSequenceData,
|
|
14
|
-
caretPositionOrRange,
|
|
15
|
-
options = {}
|
|
16
|
-
) {
|
|
20
|
+
_sequenceDataToInsert: SequenceData,
|
|
21
|
+
_existingSequenceData: SequenceData,
|
|
22
|
+
caretPositionOrRange: number | Range,
|
|
23
|
+
options: InsertSequenceDataOptions = {}
|
|
24
|
+
): SequenceData {
|
|
17
25
|
//maintainOriginSplit means that if you're inserting around the origin with n bps selected before the origin
|
|
18
26
|
//when inserting new seq, n bps of the new seq should go in before the origin and the rest should be
|
|
19
27
|
//inserted at the sequence start
|
|
@@ -31,13 +39,21 @@ export default function insertSequenceDataAtPositionOrRange(
|
|
|
31
39
|
sequenceDataToInsert.isProtein && sequenceDataToInsert.proteinSequence
|
|
32
40
|
? sequenceDataToInsert.proteinSequence.length * 3
|
|
33
41
|
: sequenceDataToInsert.sequence.length;
|
|
34
|
-
let caretPosition =
|
|
42
|
+
let caretPosition =
|
|
43
|
+
typeof caretPositionOrRange === "number"
|
|
44
|
+
? caretPositionOrRange
|
|
45
|
+
: caretPositionOrRange.start;
|
|
35
46
|
|
|
36
47
|
const isInsertSameLengthAsSelection =
|
|
48
|
+
typeof caretPositionOrRange !== "number" &&
|
|
37
49
|
sequenceDataToInsert.sequence.length ===
|
|
38
|
-
|
|
50
|
+
getRangeLength(
|
|
51
|
+
caretPositionOrRange,
|
|
52
|
+
existingSequenceData.sequence.length
|
|
53
|
+
);
|
|
39
54
|
|
|
40
55
|
if (
|
|
56
|
+
typeof caretPositionOrRange !== "number" &&
|
|
41
57
|
caretPositionOrRange.start > -1 &&
|
|
42
58
|
getRangeLength(
|
|
43
59
|
caretPositionOrRange,
|
|
@@ -45,12 +61,18 @@ export default function insertSequenceDataAtPositionOrRange(
|
|
|
45
61
|
) === existingSequenceData.sequence.length
|
|
46
62
|
) {
|
|
47
63
|
//handle the case where we're deleting everything!
|
|
64
|
+
const emptyAnnotations = modifiableTypes.reduce(
|
|
65
|
+
(acc, type) => {
|
|
66
|
+
acc[type] = [];
|
|
67
|
+
return acc;
|
|
68
|
+
},
|
|
69
|
+
{} as Record<string, Annotation[]>
|
|
70
|
+
);
|
|
71
|
+
|
|
48
72
|
existingSequenceData = tidyUpSequenceData(
|
|
49
73
|
{
|
|
50
74
|
...existingSequenceData,
|
|
51
|
-
...
|
|
52
|
-
return (acc[type] = []);
|
|
53
|
-
}, {}),
|
|
75
|
+
...emptyAnnotations,
|
|
54
76
|
sequence: "",
|
|
55
77
|
doNotRemoveInvalidChars: true,
|
|
56
78
|
proteinSequence: "",
|
|
@@ -64,7 +86,10 @@ export default function insertSequenceDataAtPositionOrRange(
|
|
|
64
86
|
newSequenceData.chromatogramData.baseTraces
|
|
65
87
|
) {
|
|
66
88
|
//handle chromatogramData updates
|
|
67
|
-
if (
|
|
89
|
+
if (
|
|
90
|
+
typeof caretPositionOrRange !== "number" &&
|
|
91
|
+
caretPositionOrRange.start > -1
|
|
92
|
+
) {
|
|
68
93
|
if (caretPositionOrRange.start > caretPositionOrRange.end) {
|
|
69
94
|
newSequenceData.chromatogramData = trimChromatogram({
|
|
70
95
|
chromatogramData: newSequenceData.chromatogramData,
|
|
@@ -74,14 +99,16 @@ export default function insertSequenceDataAtPositionOrRange(
|
|
|
74
99
|
},
|
|
75
100
|
justBaseCalls: isInsertSameLengthAsSelection
|
|
76
101
|
});
|
|
77
|
-
newSequenceData.chromatogramData
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
if (newSequenceData.chromatogramData) {
|
|
103
|
+
newSequenceData.chromatogramData = trimChromatogram({
|
|
104
|
+
chromatogramData: newSequenceData.chromatogramData,
|
|
105
|
+
range: {
|
|
106
|
+
start: 0,
|
|
107
|
+
end: caretPositionOrRange.end
|
|
108
|
+
},
|
|
109
|
+
justBaseCalls: isInsertSameLengthAsSelection
|
|
110
|
+
});
|
|
111
|
+
}
|
|
85
112
|
} else {
|
|
86
113
|
newSequenceData.chromatogramData = trimChromatogram({
|
|
87
114
|
chromatogramData: newSequenceData.chromatogramData,
|
|
@@ -93,13 +120,14 @@ export default function insertSequenceDataAtPositionOrRange(
|
|
|
93
120
|
});
|
|
94
121
|
}
|
|
95
122
|
}
|
|
96
|
-
if (sequenceDataToInsert.sequence) {
|
|
123
|
+
if (sequenceDataToInsert.sequence && newSequenceData.chromatogramData) {
|
|
97
124
|
insertIntoChromatogram({
|
|
98
125
|
chromatogramData: newSequenceData.chromatogramData,
|
|
99
126
|
caretPosition:
|
|
127
|
+
typeof caretPositionOrRange !== "number" &&
|
|
100
128
|
caretPositionOrRange.start > -1
|
|
101
129
|
? caretPositionOrRange.start
|
|
102
|
-
: caretPositionOrRange,
|
|
130
|
+
: (caretPositionOrRange as number),
|
|
103
131
|
seqToInsert: sequenceDataToInsert.sequence,
|
|
104
132
|
justBaseCalls: isInsertSameLengthAsSelection
|
|
105
133
|
});
|
|
@@ -114,18 +142,25 @@ export default function insertSequenceDataAtPositionOrRange(
|
|
|
114
142
|
);
|
|
115
143
|
newSequenceData.size = newSequenceData.sequence.length;
|
|
116
144
|
newSequenceData.proteinSequence = adjustBpsToReplaceOrInsert(
|
|
117
|
-
existingSequenceData.proteinSequence,
|
|
118
|
-
sequenceDataToInsert.proteinSequence,
|
|
145
|
+
existingSequenceData.proteinSequence || "",
|
|
146
|
+
sequenceDataToInsert.proteinSequence || "",
|
|
119
147
|
convertDnaCaretPositionOrRangeToAa(caretPositionOrRange)
|
|
120
148
|
);
|
|
121
|
-
newSequenceData.proteinSize = newSequenceData.proteinSequence.length;
|
|
149
|
+
newSequenceData.proteinSize = (newSequenceData.proteinSequence || "").length;
|
|
122
150
|
|
|
123
151
|
//handle the insert
|
|
124
152
|
modifiableTypes.forEach(annotationType => {
|
|
125
|
-
let existingAnnotations = existingSequenceData[
|
|
153
|
+
let existingAnnotations = existingSequenceData[
|
|
154
|
+
annotationType
|
|
155
|
+
] as Annotation[];
|
|
156
|
+
if (!existingAnnotations) return;
|
|
157
|
+
|
|
126
158
|
//update the annotations:
|
|
127
159
|
//handle the delete if necessary
|
|
128
|
-
if (
|
|
160
|
+
if (
|
|
161
|
+
typeof caretPositionOrRange !== "number" &&
|
|
162
|
+
caretPositionOrRange.start > -1
|
|
163
|
+
) {
|
|
129
164
|
//we have a range! so let's delete it!
|
|
130
165
|
const range = caretPositionOrRange;
|
|
131
166
|
caretPosition = range.start > range.end ? 0 : range.start;
|
|
@@ -138,25 +173,35 @@ export default function insertSequenceDataAtPositionOrRange(
|
|
|
138
173
|
}
|
|
139
174
|
//first clear the newSequenceData's annotations
|
|
140
175
|
newSequenceData[annotationType] = [];
|
|
176
|
+
const annotationsToInsert = sequenceDataToInsert[
|
|
177
|
+
annotationType
|
|
178
|
+
] as Annotation[];
|
|
141
179
|
//in two steps adjust the annotations to the insert
|
|
142
|
-
newSequenceData[annotationType]
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
)
|
|
155
|
-
|
|
180
|
+
if (newSequenceData[annotationType]) {
|
|
181
|
+
// Explicitly cast to unknown array inside concat to avoid TS errors with specific Annotation types if they diverge slightly,
|
|
182
|
+
// though strictly they should be Annotation[]
|
|
183
|
+
(newSequenceData[annotationType] as Annotation[]) = (
|
|
184
|
+
newSequenceData[annotationType] as Annotation[]
|
|
185
|
+
).concat(
|
|
186
|
+
adjustAnnotationsToInsert(
|
|
187
|
+
existingAnnotations,
|
|
188
|
+
caretPosition,
|
|
189
|
+
insertLength
|
|
190
|
+
)
|
|
191
|
+
);
|
|
192
|
+
if (annotationsToInsert) {
|
|
193
|
+
(newSequenceData[annotationType] as Annotation[]) = (
|
|
194
|
+
newSequenceData[annotationType] as Annotation[]
|
|
195
|
+
).concat(
|
|
196
|
+
adjustAnnotationsToInsert(annotationsToInsert, 0, caretPosition)
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
156
200
|
});
|
|
201
|
+
|
|
157
202
|
if (
|
|
158
203
|
maintainOriginSplit &&
|
|
159
|
-
caretPositionOrRange &&
|
|
204
|
+
typeof caretPositionOrRange !== "number" &&
|
|
160
205
|
caretPositionOrRange.start > caretPositionOrRange.end
|
|
161
206
|
) {
|
|
162
207
|
//we're replacing around the origin and maintainOriginSplit=true
|
|
@@ -171,7 +216,11 @@ export default function insertSequenceDataAtPositionOrRange(
|
|
|
171
216
|
return newSequenceData;
|
|
172
217
|
}
|
|
173
218
|
|
|
174
|
-
function adjustAnnotationsToDelete(
|
|
219
|
+
function adjustAnnotationsToDelete(
|
|
220
|
+
annotationsToBeAdjusted: Annotation[],
|
|
221
|
+
range: Range,
|
|
222
|
+
maxLength: number
|
|
223
|
+
): Annotation[] {
|
|
175
224
|
return map(annotationsToBeAdjusted, annotation => {
|
|
176
225
|
const newRange = adjustRangeToDeletionOfAnotherRange(
|
|
177
226
|
annotation,
|
|
@@ -183,6 +232,10 @@ function adjustAnnotationsToDelete(annotationsToBeAdjusted, range, maxLength) {
|
|
|
183
232
|
annotation.locations
|
|
184
233
|
.map(loc => adjustRangeToDeletionOfAnotherRange(loc, range, maxLength))
|
|
185
234
|
.filter(range => !!range);
|
|
235
|
+
|
|
236
|
+
// Check if newRange is valid (start/end exist) before returning
|
|
237
|
+
if (!newRange) return null;
|
|
238
|
+
|
|
186
239
|
if (newLocations && newLocations.length) {
|
|
187
240
|
return {
|
|
188
241
|
...newRange,
|
|
@@ -193,7 +246,7 @@ function adjustAnnotationsToDelete(annotationsToBeAdjusted, range, maxLength) {
|
|
|
193
246
|
} else {
|
|
194
247
|
return newRange;
|
|
195
248
|
}
|
|
196
|
-
}).filter(range => !!range); //filter any fully deleted ranges
|
|
249
|
+
}).filter((range): range is Annotation => !!range); //filter any fully deleted ranges
|
|
197
250
|
}
|
|
198
251
|
|
|
199
252
|
function insertIntoChromatogram({
|
|
@@ -201,22 +254,28 @@ function insertIntoChromatogram({
|
|
|
201
254
|
caretPosition,
|
|
202
255
|
seqToInsert,
|
|
203
256
|
justBaseCalls
|
|
204
|
-
}
|
|
257
|
+
}: {
|
|
258
|
+
chromatogramData: ChromatogramData;
|
|
259
|
+
caretPosition: number;
|
|
260
|
+
seqToInsert: string;
|
|
261
|
+
justBaseCalls?: boolean;
|
|
262
|
+
}): ChromatogramData | void {
|
|
205
263
|
if (!seqToInsert.length) return;
|
|
206
264
|
|
|
207
|
-
chromatogramData.baseCalls
|
|
208
|
-
chromatogramData.baseCalls.splice(
|
|
265
|
+
if (chromatogramData.baseCalls) {
|
|
266
|
+
(chromatogramData.baseCalls as unknown[]).splice(
|
|
209
267
|
caretPosition,
|
|
210
268
|
0,
|
|
211
269
|
...seqToInsert.split("")
|
|
212
270
|
);
|
|
271
|
+
}
|
|
213
272
|
if (justBaseCalls) {
|
|
214
273
|
//return early if just base calls
|
|
215
274
|
return chromatogramData;
|
|
216
275
|
}
|
|
217
276
|
|
|
218
|
-
const baseTracesToInsert = [];
|
|
219
|
-
const qualNumsToInsert = [];
|
|
277
|
+
const baseTracesToInsert: unknown[] = [];
|
|
278
|
+
const qualNumsToInsert: number[] = [];
|
|
220
279
|
|
|
221
280
|
for (let index = 0; index < seqToInsert.length; index++) {
|
|
222
281
|
qualNumsToInsert.push(0);
|
|
@@ -229,10 +288,20 @@ function insertIntoChromatogram({
|
|
|
229
288
|
});
|
|
230
289
|
}
|
|
231
290
|
|
|
232
|
-
chromatogramData.baseTraces
|
|
233
|
-
chromatogramData.baseTraces.splice(
|
|
234
|
-
|
|
235
|
-
|
|
291
|
+
if (chromatogramData.baseTraces) {
|
|
292
|
+
(chromatogramData.baseTraces as unknown[]).splice(
|
|
293
|
+
caretPosition,
|
|
294
|
+
0,
|
|
295
|
+
...baseTracesToInsert
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
if (chromatogramData.qualNums) {
|
|
299
|
+
(chromatogramData.qualNums as unknown[]).splice(
|
|
300
|
+
caretPosition,
|
|
301
|
+
0,
|
|
302
|
+
...qualNumsToInsert
|
|
303
|
+
);
|
|
304
|
+
}
|
|
236
305
|
|
|
237
306
|
return chromatogramData;
|
|
238
307
|
}
|
|
@@ -241,13 +310,18 @@ function trimChromatogram({
|
|
|
241
310
|
chromatogramData,
|
|
242
311
|
range: { start, end },
|
|
243
312
|
justBaseCalls
|
|
244
|
-
}
|
|
313
|
+
}: {
|
|
314
|
+
chromatogramData: ChromatogramData;
|
|
315
|
+
range: { start: number; end: number };
|
|
316
|
+
justBaseCalls?: boolean;
|
|
317
|
+
}): ChromatogramData {
|
|
245
318
|
[
|
|
246
319
|
"baseCalls",
|
|
247
320
|
...(justBaseCalls ? [] : ["qualNums", "baseTraces", "basePos"])
|
|
248
321
|
].forEach(type => {
|
|
249
|
-
chromatogramData[type]
|
|
250
|
-
chromatogramData[type].splice(start, end - start + 1);
|
|
322
|
+
if (chromatogramData[type]) {
|
|
323
|
+
(chromatogramData[type] as unknown[]).splice(start, end - start + 1);
|
|
324
|
+
}
|
|
251
325
|
});
|
|
252
326
|
|
|
253
327
|
return chromatogramData;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { each, forEach, startsWith, filter } from "lodash-es";
|
|
2
|
+
import {
|
|
3
|
+
getYOffsetForPotentiallyCircularRange,
|
|
4
|
+
splitRangeIntoTwoPartsIfItIsCircular,
|
|
5
|
+
checkIfPotentiallyCircularRangesOverlap
|
|
6
|
+
} from "@teselagen/range-utils";
|
|
7
|
+
import { Annotation } from "./types";
|
|
8
|
+
|
|
9
|
+
export interface MappedAnnotation extends Annotation {
|
|
10
|
+
yOffset?: number;
|
|
11
|
+
enclosingRangeType?: "beginning" | "end" | "beginningAndEnd";
|
|
12
|
+
annotation?: Annotation;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function mapAnnotationsToRows(
|
|
16
|
+
annotations: Annotation[],
|
|
17
|
+
sequenceLength: number,
|
|
18
|
+
bpsPerRow: number,
|
|
19
|
+
{ splitForwardReverse }: { splitForwardReverse?: boolean } = {}
|
|
20
|
+
) {
|
|
21
|
+
const annotationsToRowsMap: Record<number | string, MappedAnnotation[]> = {};
|
|
22
|
+
const yOffsetLevelMap: Record<
|
|
23
|
+
string | number,
|
|
24
|
+
{ start: number; end: number }[][]
|
|
25
|
+
> = {};
|
|
26
|
+
const wrappedAnnotations: Record<string, boolean> = {};
|
|
27
|
+
|
|
28
|
+
each(annotations, annotation => {
|
|
29
|
+
const containsLocations = !!(
|
|
30
|
+
annotation.locations && annotation.locations.length
|
|
31
|
+
);
|
|
32
|
+
if (annotation.overlapsSelf) {
|
|
33
|
+
if (!wrappedAnnotations[annotation.id as string]) {
|
|
34
|
+
mapAnnotationToRows({
|
|
35
|
+
wrappedAnnotations,
|
|
36
|
+
annotation: {
|
|
37
|
+
...annotation,
|
|
38
|
+
start: 0,
|
|
39
|
+
end: sequenceLength - 1,
|
|
40
|
+
id: `__tempAnnRemoveMe__${annotation.id}`,
|
|
41
|
+
overlapsSelf: false
|
|
42
|
+
},
|
|
43
|
+
sequenceLength,
|
|
44
|
+
bpsPerRow,
|
|
45
|
+
annotationsToRowsMap,
|
|
46
|
+
yOffsetLevelMap,
|
|
47
|
+
containsLocations,
|
|
48
|
+
splitForwardReverse
|
|
49
|
+
});
|
|
50
|
+
wrappedAnnotations[annotation.id as string] = true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
mapAnnotationToRows({
|
|
55
|
+
wrappedAnnotations,
|
|
56
|
+
annotation,
|
|
57
|
+
sequenceLength,
|
|
58
|
+
bpsPerRow,
|
|
59
|
+
annotationsToRowsMap,
|
|
60
|
+
yOffsetLevelMap,
|
|
61
|
+
containsLocations,
|
|
62
|
+
splitForwardReverse
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (containsLocations) {
|
|
66
|
+
annotation.locations?.forEach(location => {
|
|
67
|
+
mapAnnotationToRows({
|
|
68
|
+
wrappedAnnotations,
|
|
69
|
+
annotation,
|
|
70
|
+
sequenceLength,
|
|
71
|
+
bpsPerRow,
|
|
72
|
+
annotationsToRowsMap,
|
|
73
|
+
yOffsetLevelMap,
|
|
74
|
+
location: location as Annotation,
|
|
75
|
+
splitForwardReverse
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
forEach(annotationsToRowsMap, (annotationsForRow, i) => {
|
|
82
|
+
annotationsToRowsMap[i] = filter(
|
|
83
|
+
annotationsForRow,
|
|
84
|
+
ann => !startsWith(String(ann.id), "__tempAnnRemoveMe__")
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
return annotationsToRowsMap;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface MapAnnotationToRowsParams {
|
|
91
|
+
wrappedAnnotations: Record<string, boolean>;
|
|
92
|
+
annotation: Annotation;
|
|
93
|
+
sequenceLength: number;
|
|
94
|
+
bpsPerRow: number;
|
|
95
|
+
annotationsToRowsMap: Record<number | string, MappedAnnotation[]>;
|
|
96
|
+
yOffsetLevelMap: Record<string | number, { start: number; end: number }[][]>;
|
|
97
|
+
location?: Annotation;
|
|
98
|
+
containsLocations?: boolean;
|
|
99
|
+
splitForwardReverse?: boolean;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function mapAnnotationToRows({
|
|
103
|
+
annotation,
|
|
104
|
+
sequenceLength,
|
|
105
|
+
bpsPerRow,
|
|
106
|
+
annotationsToRowsMap,
|
|
107
|
+
yOffsetLevelMap,
|
|
108
|
+
location,
|
|
109
|
+
containsLocations,
|
|
110
|
+
splitForwardReverse
|
|
111
|
+
}: MapAnnotationToRowsParams) {
|
|
112
|
+
const ranges = splitRangeIntoTwoPartsIfItIsCircular(
|
|
113
|
+
location || annotation,
|
|
114
|
+
sequenceLength
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
ranges.forEach((range, index) => {
|
|
118
|
+
const startingRow = Math.floor(range.start / bpsPerRow);
|
|
119
|
+
const endingRow = Math.floor(range.end / bpsPerRow);
|
|
120
|
+
|
|
121
|
+
for (let rowNumber = startingRow; rowNumber <= endingRow; rowNumber++) {
|
|
122
|
+
if (!annotationsToRowsMap[rowNumber]) {
|
|
123
|
+
annotationsToRowsMap[rowNumber] = [];
|
|
124
|
+
}
|
|
125
|
+
const key = splitForwardReverse
|
|
126
|
+
? annotation.forward
|
|
127
|
+
? rowNumber + "_forward"
|
|
128
|
+
: rowNumber + "_reverse"
|
|
129
|
+
: rowNumber;
|
|
130
|
+
|
|
131
|
+
const annotationsForRow = annotationsToRowsMap[rowNumber];
|
|
132
|
+
if (!yOffsetLevelMap[key]) {
|
|
133
|
+
yOffsetLevelMap[key] = [];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let yOffset: number | undefined;
|
|
137
|
+
const yOffsetsForRow = yOffsetLevelMap[key];
|
|
138
|
+
const start =
|
|
139
|
+
rowNumber === startingRow ? range.start : rowNumber * bpsPerRow;
|
|
140
|
+
const end =
|
|
141
|
+
rowNumber === endingRow
|
|
142
|
+
? range.end
|
|
143
|
+
: rowNumber * bpsPerRow + bpsPerRow - 1;
|
|
144
|
+
|
|
145
|
+
if (annotation.overlapsSelf) {
|
|
146
|
+
annotationsForRow.forEach(ann => {
|
|
147
|
+
if (ann.id === `__tempAnnRemoveMe__${annotation.id}`) {
|
|
148
|
+
yOffset = ann.yOffset;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
if (yOffset === undefined) {
|
|
152
|
+
annotationsForRow.forEach(ann => {
|
|
153
|
+
if (ann.id === annotation.id) {
|
|
154
|
+
yOffset = ann.yOffset;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
if (location) {
|
|
160
|
+
annotationsForRow.forEach(ann => {
|
|
161
|
+
if (ann.id === annotation.id) {
|
|
162
|
+
yOffset = ann.yOffset;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
} else {
|
|
166
|
+
if (
|
|
167
|
+
index > 0 &&
|
|
168
|
+
annotationsForRow.length &&
|
|
169
|
+
annotationsForRow[annotationsForRow.length - 1].annotation ===
|
|
170
|
+
annotation
|
|
171
|
+
) {
|
|
172
|
+
yOffset = annotationsForRow[annotationsForRow.length - 1].yOffset;
|
|
173
|
+
} else {
|
|
174
|
+
const siblingRangesOnThisRow = ranges.slice(index + 1).filter(r => {
|
|
175
|
+
const rStartRow = Math.floor(r.start / bpsPerRow);
|
|
176
|
+
const rEndRow = Math.floor(r.end / bpsPerRow);
|
|
177
|
+
return rowNumber >= rStartRow && rowNumber <= rEndRow;
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (siblingRangesOnThisRow.length > 0) {
|
|
181
|
+
// We have future ranges for this annotation on this row.
|
|
182
|
+
// We must choose a yOffset that works for the current range AND all future ranges.
|
|
183
|
+
let foundYOffset = -1;
|
|
184
|
+
yOffsetsForRow.some((rangesAlreadyAddedToYOffset, levelIndex) => {
|
|
185
|
+
const rangeBlocked = rangesAlreadyAddedToYOffset.some(
|
|
186
|
+
comparisonRange => {
|
|
187
|
+
return checkIfPotentiallyCircularRangesOverlap(
|
|
188
|
+
range,
|
|
189
|
+
comparisonRange
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
if (rangeBlocked) return false;
|
|
194
|
+
|
|
195
|
+
// Check siblings
|
|
196
|
+
const siblingBlocked = siblingRangesOnThisRow.some(
|
|
197
|
+
siblingRange => {
|
|
198
|
+
return rangesAlreadyAddedToYOffset.some(comparisonRange => {
|
|
199
|
+
return checkIfPotentiallyCircularRangesOverlap(
|
|
200
|
+
siblingRange,
|
|
201
|
+
comparisonRange
|
|
202
|
+
);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
if (!siblingBlocked) {
|
|
208
|
+
foundYOffset = levelIndex;
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
return false;
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
if (foundYOffset > -1) {
|
|
215
|
+
yOffset = foundYOffset;
|
|
216
|
+
yOffsetsForRow[foundYOffset].push(range);
|
|
217
|
+
} else {
|
|
218
|
+
// Create new level
|
|
219
|
+
yOffset = yOffsetsForRow.length;
|
|
220
|
+
yOffsetsForRow.push([range]);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
yOffset = getYOffsetForPotentiallyCircularRange(
|
|
224
|
+
range,
|
|
225
|
+
yOffsetsForRow,
|
|
226
|
+
false
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (yOffset !== undefined) {
|
|
231
|
+
if (!yOffsetsForRow[yOffset]) yOffsetsForRow[yOffset] = [];
|
|
232
|
+
yOffsetsForRow[yOffset].push({
|
|
233
|
+
start: start,
|
|
234
|
+
end: end
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
annotationsForRow.push({
|
|
241
|
+
...annotation,
|
|
242
|
+
id: annotation.id,
|
|
243
|
+
annotation: annotation,
|
|
244
|
+
start: start,
|
|
245
|
+
end: end,
|
|
246
|
+
...(containsLocations && { containsLocations }),
|
|
247
|
+
...(location && { isJoinedLocation: !!location }),
|
|
248
|
+
yOffset: yOffset,
|
|
249
|
+
enclosingRangeType: range.type as
|
|
250
|
+
| "beginning"
|
|
251
|
+
| "end"
|
|
252
|
+
| "beginningAndEnd"
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { cloneDeep } from "lodash-es";
|
|
2
|
+
import { getYOffsetsForPotentiallyCircularRanges } from "@teselagen/range-utils";
|
|
3
|
+
import { annotationTypes } from "./annotationTypes";
|
|
4
|
+
import { SequenceData, Annotation } from "./types";
|
|
5
|
+
|
|
6
|
+
//basically just adds yOffsets to the annotations
|
|
7
|
+
export default function prepareCircularViewData(sequenceData: SequenceData) {
|
|
8
|
+
const clonedSeqData = cloneDeep(sequenceData);
|
|
9
|
+
annotationTypes.forEach(annotationType => {
|
|
10
|
+
if (annotationType !== "cutsites") {
|
|
11
|
+
const annotations = clonedSeqData[annotationType] as Annotation[];
|
|
12
|
+
if (annotations) {
|
|
13
|
+
const maxYOffset = getYOffsetsForPotentiallyCircularRanges(
|
|
14
|
+
annotations,
|
|
15
|
+
true
|
|
16
|
+
).maxYOffset;
|
|
17
|
+
(
|
|
18
|
+
clonedSeqData[annotationType] as Annotation[] & { maxYOffset: number }
|
|
19
|
+
).maxYOffset = maxYOffset;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
return clonedSeqData;
|
|
24
|
+
}
|
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
import mapAnnotationsToRows from "./mapAnnotationsToRows";
|
|
1
|
+
import mapAnnotationsToRows, { MappedAnnotation } from "./mapAnnotationsToRows";
|
|
3
2
|
|
|
4
3
|
import { annotationTypes } from "./annotationTypes";
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
import { SequenceData, Annotation } from "./types";
|
|
6
|
+
|
|
7
|
+
export interface RowData {
|
|
8
|
+
rowNumber: number;
|
|
9
|
+
start: number;
|
|
10
|
+
end: number;
|
|
11
|
+
sequence: string;
|
|
12
|
+
[key: string]: MappedAnnotation[] | number | string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default function prepareRowData(
|
|
16
|
+
sequenceData: SequenceData,
|
|
17
|
+
bpsPerRow: number
|
|
18
|
+
) {
|
|
8
19
|
const sequenceLength = sequenceData.sequence.length;
|
|
9
20
|
const totalRows = Math.ceil(sequenceLength / bpsPerRow) || 1; //this check makes sure there is always at least 1 row!
|
|
10
|
-
const rows = [];
|
|
11
|
-
const rowMap
|
|
21
|
+
const rows: RowData[] = [];
|
|
22
|
+
const rowMap: Record<
|
|
23
|
+
string,
|
|
24
|
+
Record<string | number, MappedAnnotation[]>
|
|
25
|
+
> = {};
|
|
12
26
|
annotationTypes.forEach(type => {
|
|
13
27
|
rowMap[type] = mapAnnotationsToRows(
|
|
14
|
-
sequenceData[type],
|
|
28
|
+
(sequenceData[type] as Annotation[]) || [],
|
|
15
29
|
sequenceLength,
|
|
16
30
|
bpsPerRow,
|
|
17
31
|
{ splitForwardReverse: type === "primers" }
|
|
@@ -19,7 +33,12 @@ export default function prepareRowData(sequenceData, bpsPerRow) {
|
|
|
19
33
|
});
|
|
20
34
|
|
|
21
35
|
for (let rowNumber = 0; rowNumber < totalRows; rowNumber++) {
|
|
22
|
-
const row = {
|
|
36
|
+
const row: RowData = {
|
|
37
|
+
rowNumber,
|
|
38
|
+
start: 0,
|
|
39
|
+
end: 0,
|
|
40
|
+
sequence: ""
|
|
41
|
+
};
|
|
23
42
|
row.rowNumber = rowNumber;
|
|
24
43
|
row.start = rowNumber * bpsPerRow;
|
|
25
44
|
row.end =
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default function rotateBpsToPosition(
|
|
2
|
+
bps: string,
|
|
3
|
+
caretPosition: number
|
|
4
|
+
) {
|
|
5
|
+
return arrayRotate(bps.split(""), caretPosition).join("");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function arrayRotate<T>(arr: T[], count: number): T[] {
|
|
9
|
+
count -= arr.length * Math.floor(count / arr.length);
|
|
10
|
+
arr.push(...arr.splice(0, count));
|
|
11
|
+
return arr;
|
|
12
|
+
}
|