@jbrowse/core 2.11.2 → 2.12.0
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/BaseFeatureWidget/BaseFeatureDetail/DataGridDetails.js +16 -21
- package/BaseFeatureWidget/BaseFeatureDetail/index.js +1 -3
- package/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeatureDetails.js +24 -85
- package/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.js +2 -2
- package/BaseFeatureWidget/SequenceFeatureDetails/SequencePanel.d.ts +3 -4
- package/BaseFeatureWidget/SequenceFeatureDetails/SequencePanel.js +55 -24
- package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceDialog.d.ts +9 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceDialog.js +69 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceFeatureMenu.d.ts +9 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceFeatureMenu.js +126 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceTypeSelector.d.ts +6 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SequenceTypeSelector.js +68 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/dialogs/SettingsDialog.js +19 -10
- package/BaseFeatureWidget/SequenceFeatureDetails/model.d.ts +47 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/model.js +83 -9
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDNASequence.d.ts +3 -1
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDNASequence.js +76 -19
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDSSequence.d.ts +5 -2
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDSSequence.js +12 -3
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/GenomicSequence.d.ts +7 -2
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/GenomicSequence.js +51 -5
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/ProteinSequence.d.ts +5 -2
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/ProteinSequence.js +12 -3
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/SequenceDisplay.d.ts +11 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/SequenceDisplay.js +30 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/util.d.ts +11 -0
- package/BaseFeatureWidget/SequenceFeatureDetails/util.js +43 -1
- package/BaseFeatureWidget/stateModelFactory.d.ts +32 -2
- package/PluginManager.d.ts +2 -11
- package/ReExports/modules.d.ts +2 -11
- package/package.json +4 -2
- package/stories/JBrowseCore.stories.d.ts +5 -0
- package/stories/JBrowseCore.stories.js +10 -0
- package/stories/examples/WithSequencePanel.d.ts +7 -0
- package/stories/examples/WithSequencePanel.js +43 -0
- package/stories/examples/index.d.ts +1 -0
- package/stories/examples/index.js +17 -0
- package/stories/examples/util.d.ts +33 -0
- package/stories/examples/util.js +235 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/ui/Dialog.js +2 -1
- package/util/Base1DUtils.d.ts +1 -1
- package/util/Base1DUtils.js +3 -7
- package/util/Base1DViewModel.d.ts +5 -16
- package/util/Base1DViewModel.js +6 -12
- package/util/index.d.ts +1 -1
- package/util/tracks.d.ts +3 -2
- package/util/tracks.js +10 -6
- package/util/types/index.d.ts +4 -1
- package/ui/useResizeBar.d.ts +0 -5
- package/ui/useResizeBar.js +0 -22
|
@@ -36,25 +36,34 @@ const useStyles = (0, mui_1.makeStyles)()(theme => ({
|
|
|
36
36
|
dialogContent: {
|
|
37
37
|
width: '80em',
|
|
38
38
|
},
|
|
39
|
+
root: {
|
|
40
|
+
padding: 4,
|
|
41
|
+
},
|
|
39
42
|
}));
|
|
43
|
+
function TextField2(props) {
|
|
44
|
+
return (react_1.default.createElement("div", null,
|
|
45
|
+
react_1.default.createElement(material_1.TextField, { ...props })));
|
|
46
|
+
}
|
|
47
|
+
function FormControl2({ children }) {
|
|
48
|
+
return (react_1.default.createElement("div", null,
|
|
49
|
+
react_1.default.createElement(material_1.FormControl, null, children)));
|
|
50
|
+
}
|
|
40
51
|
const SequenceFeatureSettingsDialog = (0, mobx_react_1.observer)(function ({ handleClose, model, }) {
|
|
41
52
|
const { classes } = useStyles();
|
|
53
|
+
const { upperCaseCDS } = model;
|
|
42
54
|
const [intronBp, setIntronBp] = (0, react_1.useState)(`${model.intronBp}`);
|
|
43
55
|
const [upDownBp, setUpDownBp] = (0, react_1.useState)(`${model.upDownBp}`);
|
|
44
56
|
const intronBpValid = !Number.isNaN(+intronBp);
|
|
45
57
|
const upDownBpValid = !Number.isNaN(+upDownBp);
|
|
46
58
|
return (react_1.default.createElement(ui_1.Dialog, { maxWidth: "xl", open: true, onClose: () => handleClose(), title: "Feature sequence settings" },
|
|
47
59
|
react_1.default.createElement(material_1.DialogContent, { className: classes.dialogContent },
|
|
48
|
-
react_1.default.createElement("
|
|
49
|
-
|
|
50
|
-
react_1.default.createElement(
|
|
51
|
-
react_1.default.createElement(material_1.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
react_1.default.createElement(material_1.
|
|
55
|
-
react_1.default.createElement(material_1.RadioGroup, { value: model.upperCaseCDS ? 'cds' : 'unchanged', onChange: e => model.setUpperCaseCDS(e.target.value === 'cds') },
|
|
56
|
-
react_1.default.createElement(material_1.FormControlLabel, { value: "cds", control: react_1.default.createElement(material_1.Radio, null), label: "Capitalize CDS and lower case everything else" }),
|
|
57
|
-
react_1.default.createElement(material_1.FormControlLabel, { value: "unchanged", control: react_1.default.createElement(material_1.Radio, null), label: "Capitalization from reference genome sequence" }))))),
|
|
60
|
+
react_1.default.createElement(TextField2, { label: "Number of intronic bases around splice site to display", className: classes.formElt, value: intronBp, helperText: !intronBpValid ? 'Not a number' : '', error: !intronBpValid, onChange: event => setIntronBp(event.target.value) }),
|
|
61
|
+
react_1.default.createElement(TextField2, { label: "Number of bases up/down stream of feature to display", className: classes.formElt, value: upDownBp, helperText: !upDownBpValid ? 'Not a number' : '', error: !upDownBpValid, onChange: event => setUpDownBp(event.target.value) }),
|
|
62
|
+
react_1.default.createElement(FormControl2, null,
|
|
63
|
+
react_1.default.createElement(material_1.FormLabel, null, "Sequence capitalization"),
|
|
64
|
+
react_1.default.createElement(material_1.RadioGroup, { value: upperCaseCDS ? 'cds' : 'unchanged', onChange: e => model.setUpperCaseCDS(e.target.value === 'cds') },
|
|
65
|
+
react_1.default.createElement(material_1.FormControlLabel, { value: "cds", control: react_1.default.createElement(material_1.Radio, { className: classes.root, size: "small" }), label: "Capitalize CDS and lower case everything else" }),
|
|
66
|
+
react_1.default.createElement(material_1.FormControlLabel, { value: "unchanged", control: react_1.default.createElement(material_1.Radio, { className: classes.root, size: "small" }), label: "Capitalization from reference genome sequence" })))),
|
|
58
67
|
react_1.default.createElement(material_1.DialogActions, null,
|
|
59
68
|
react_1.default.createElement(material_1.Button, { onClick: () => {
|
|
60
69
|
model.setIntronBp(+intronBp);
|
|
@@ -1,12 +1,59 @@
|
|
|
1
1
|
import { Instance } from 'mobx-state-tree';
|
|
2
|
+
import { SimpleFeatureSerialized } from '../../util';
|
|
2
3
|
export declare function SequenceFeatureDetailsF(): import("mobx-state-tree").IModelType<{}, {
|
|
4
|
+
showCoordinatesSetting: string;
|
|
3
5
|
intronBp: number;
|
|
4
6
|
upDownBp: number;
|
|
5
7
|
upperCaseCDS: boolean;
|
|
8
|
+
charactersPerRow: number;
|
|
9
|
+
feature: SimpleFeatureSerialized | undefined;
|
|
10
|
+
mode: string;
|
|
6
11
|
} & {
|
|
12
|
+
/**
|
|
13
|
+
* #action
|
|
14
|
+
*/
|
|
15
|
+
setFeature(f: SimpleFeatureSerialized): void;
|
|
16
|
+
/**
|
|
17
|
+
* #action
|
|
18
|
+
*/
|
|
7
19
|
setUpDownBp(f: number): void;
|
|
20
|
+
/**
|
|
21
|
+
* #action
|
|
22
|
+
*/
|
|
8
23
|
setIntronBp(f: number): void;
|
|
24
|
+
/**
|
|
25
|
+
* #action
|
|
26
|
+
*/
|
|
9
27
|
setUpperCaseCDS(f: boolean): void;
|
|
28
|
+
/**
|
|
29
|
+
* #action
|
|
30
|
+
*/
|
|
31
|
+
setShowCoordinates(f: 'none' | 'relative' | 'genomic'): void;
|
|
32
|
+
/**
|
|
33
|
+
* #action
|
|
34
|
+
*/
|
|
35
|
+
setMode(mode: string): void;
|
|
36
|
+
} & {
|
|
37
|
+
/**
|
|
38
|
+
* #getter
|
|
39
|
+
*/
|
|
40
|
+
readonly showCoordinates: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* #getter
|
|
43
|
+
*/
|
|
44
|
+
readonly showGenomicCoordsOption: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* #getter
|
|
47
|
+
*/
|
|
48
|
+
readonly hasCDS: boolean | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* #getter
|
|
51
|
+
*/
|
|
52
|
+
readonly hasExon: boolean | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* #getter
|
|
55
|
+
*/
|
|
56
|
+
readonly hasExonOrCDS: boolean | undefined;
|
|
10
57
|
} & {
|
|
11
58
|
afterAttach(): void;
|
|
12
59
|
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
|
|
@@ -5,27 +5,97 @@ const mobx_state_tree_1 = require("mobx-state-tree");
|
|
|
5
5
|
const mobx_1 = require("mobx");
|
|
6
6
|
// locals
|
|
7
7
|
const util_1 = require("../../util");
|
|
8
|
+
function localStorageGetNumber(key, defaultVal) {
|
|
9
|
+
var _a;
|
|
10
|
+
return +((_a = (0, util_1.localStorageGetItem)(key)) !== null && _a !== void 0 ? _a : defaultVal);
|
|
11
|
+
}
|
|
8
12
|
function SequenceFeatureDetailsF() {
|
|
9
13
|
return mobx_state_tree_1.types
|
|
10
|
-
.model('SequenceFeatureDetails'
|
|
11
|
-
.volatile(() => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
.model('SequenceFeatureDetails')
|
|
15
|
+
.volatile(() => ({
|
|
16
|
+
showCoordinatesSetting: (0, util_1.localStorageGetItem)('sequenceFeatureDetails-showCoordinatesSetting') ||
|
|
17
|
+
'none',
|
|
18
|
+
intronBp: localStorageGetNumber('sequenceFeatureDetails-intronBp', 10),
|
|
19
|
+
upDownBp: localStorageGetNumber('sequenceFeatureDetails-upDownBp', 100),
|
|
20
|
+
upperCaseCDS: Boolean(JSON.parse((0, util_1.localStorageGetItem)('sequenceFeatureDetails-upperCaseCDS') || 'true')),
|
|
21
|
+
charactersPerRow: 100,
|
|
22
|
+
feature: undefined,
|
|
23
|
+
mode: '',
|
|
24
|
+
}))
|
|
19
25
|
.actions(self => ({
|
|
26
|
+
/**
|
|
27
|
+
* #action
|
|
28
|
+
*/
|
|
29
|
+
setFeature(f) {
|
|
30
|
+
self.feature = f;
|
|
31
|
+
},
|
|
32
|
+
/**
|
|
33
|
+
* #action
|
|
34
|
+
*/
|
|
20
35
|
setUpDownBp(f) {
|
|
21
36
|
self.upDownBp = f;
|
|
22
37
|
},
|
|
38
|
+
/**
|
|
39
|
+
* #action
|
|
40
|
+
*/
|
|
23
41
|
setIntronBp(f) {
|
|
24
42
|
self.intronBp = f;
|
|
25
43
|
},
|
|
44
|
+
/**
|
|
45
|
+
* #action
|
|
46
|
+
*/
|
|
26
47
|
setUpperCaseCDS(f) {
|
|
27
48
|
self.upperCaseCDS = f;
|
|
28
49
|
},
|
|
50
|
+
/**
|
|
51
|
+
* #action
|
|
52
|
+
*/
|
|
53
|
+
setShowCoordinates(f) {
|
|
54
|
+
self.showCoordinatesSetting = f;
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* #action
|
|
58
|
+
*/
|
|
59
|
+
setMode(mode) {
|
|
60
|
+
self.mode = mode;
|
|
61
|
+
},
|
|
62
|
+
}))
|
|
63
|
+
.views(self => ({
|
|
64
|
+
/**
|
|
65
|
+
* #getter
|
|
66
|
+
*/
|
|
67
|
+
get showCoordinates() {
|
|
68
|
+
return self.showCoordinatesSetting !== 'none';
|
|
69
|
+
},
|
|
70
|
+
/**
|
|
71
|
+
* #getter
|
|
72
|
+
*/
|
|
73
|
+
get showGenomicCoordsOption() {
|
|
74
|
+
return (self.mode === 'gene' ||
|
|
75
|
+
self.mode === 'gene_updownstream' ||
|
|
76
|
+
self.mode === 'genomic' ||
|
|
77
|
+
self.mode === 'genomic_sequence_updownstream');
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* #getter
|
|
81
|
+
*/
|
|
82
|
+
get hasCDS() {
|
|
83
|
+
var _a, _b;
|
|
84
|
+
return (_b = (_a = self.feature) === null || _a === void 0 ? void 0 : _a.subfeatures) === null || _b === void 0 ? void 0 : _b.some(sub => sub.type === 'CDS');
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* #getter
|
|
88
|
+
*/
|
|
89
|
+
get hasExon() {
|
|
90
|
+
var _a, _b;
|
|
91
|
+
return (_b = (_a = self.feature) === null || _a === void 0 ? void 0 : _a.subfeatures) === null || _b === void 0 ? void 0 : _b.some(sub => sub.type === 'exon');
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* #getter
|
|
95
|
+
*/
|
|
96
|
+
get hasExonOrCDS() {
|
|
97
|
+
return this.hasExon || this.hasCDS;
|
|
98
|
+
},
|
|
29
99
|
}))
|
|
30
100
|
.actions(self => ({
|
|
31
101
|
afterAttach() {
|
|
@@ -33,6 +103,10 @@ function SequenceFeatureDetailsF() {
|
|
|
33
103
|
(0, util_1.localStorageSetItem)('sequenceFeatureDetails-upDownBp', JSON.stringify(self.upDownBp));
|
|
34
104
|
(0, util_1.localStorageSetItem)('sequenceFeatureDetails-intronBp', JSON.stringify(self.intronBp));
|
|
35
105
|
(0, util_1.localStorageSetItem)('sequenceFeatureDetails-upperCaseCDS', JSON.stringify(self.upperCaseCDS));
|
|
106
|
+
(0, util_1.localStorageSetItem)('sequenceFeatureDetails-showCoordinatesSetting', self.showCoordinatesSetting);
|
|
107
|
+
}));
|
|
108
|
+
(0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
|
|
109
|
+
self.setMode(self.hasCDS ? 'cds' : self.hasExon ? 'cdna' : 'genomic');
|
|
36
110
|
}));
|
|
37
111
|
},
|
|
38
112
|
}));
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Feat } from '../../util';
|
|
3
3
|
import { SequenceFeatureDetailsModel } from '../model';
|
|
4
|
-
|
|
4
|
+
import { SimpleFeatureSerialized } from '../../../util';
|
|
5
|
+
declare const CDNASequence: ({ utr, cds, exons, sequence, upstream, downstream, feature, includeIntrons, collapseIntron, model, }: {
|
|
5
6
|
utr: Feat[];
|
|
6
7
|
cds: Feat[];
|
|
7
8
|
exons: Feat[];
|
|
8
9
|
sequence: string;
|
|
9
10
|
upstream?: string;
|
|
10
11
|
downstream?: string;
|
|
12
|
+
feature: SimpleFeatureSerialized;
|
|
11
13
|
includeIntrons?: boolean;
|
|
12
14
|
collapseIntron?: boolean;
|
|
13
15
|
model: SequenceFeatureDetailsModel;
|
|
@@ -6,29 +6,86 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const react_1 = __importDefault(require("react"));
|
|
7
7
|
const mobx_react_1 = require("mobx-react");
|
|
8
8
|
const util_1 = require("../util");
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
const SequenceDisplay_1 = __importDefault(require("./SequenceDisplay"));
|
|
10
|
+
const CDNASequence = (0, mobx_react_1.observer)(function ({ utr, cds, exons, sequence, upstream, downstream, feature, includeIntrons, collapseIntron, model, }) {
|
|
11
|
+
var _a;
|
|
12
|
+
const { upperCaseCDS, intronBp, charactersPerRow, showCoordinates, showCoordinatesSetting, } = model;
|
|
11
13
|
const hasCds = cds.length > 0;
|
|
12
14
|
const chunks = (cds.length ? [...cds, ...utr].sort((a, b) => a.start - b.start) : exons).filter(f => f.start !== f.end);
|
|
13
15
|
const toLower = (s) => (upperCaseCDS ? s.toLowerCase() : s);
|
|
14
16
|
const toUpper = (s) => (upperCaseCDS ? s.toUpperCase() : s);
|
|
17
|
+
const strand = feature.strand === -1 ? -1 : 1;
|
|
18
|
+
const fullGenomicCoordinates = showCoordinatesSetting === 'genomic' && includeIntrons && !collapseIntron;
|
|
19
|
+
const mult = fullGenomicCoordinates ? strand : 1;
|
|
20
|
+
let coordStart = fullGenomicCoordinates
|
|
21
|
+
? strand > 0
|
|
22
|
+
? feature.start + 1 - ((upstream === null || upstream === void 0 ? void 0 : upstream.length) || 0)
|
|
23
|
+
: feature.end + ((upstream === null || upstream === void 0 ? void 0 : upstream.length) || 0)
|
|
24
|
+
: 0;
|
|
25
|
+
let currStart = 0;
|
|
26
|
+
let currRemainder = 0;
|
|
27
|
+
let upstreamChunk = null;
|
|
28
|
+
if (upstream) {
|
|
29
|
+
const { segments, remainder } = (0, util_1.splitString)({
|
|
30
|
+
str: toLower(upstream),
|
|
31
|
+
charactersPerRow,
|
|
32
|
+
showCoordinates,
|
|
33
|
+
});
|
|
34
|
+
upstreamChunk = (react_1.default.createElement(SequenceDisplay_1.default, { model: model, color: util_1.updownstreamColor, strand: mult, start: currStart, coordStart: coordStart, chunks: segments }));
|
|
35
|
+
currRemainder = remainder;
|
|
36
|
+
currStart = currStart + upstream.length * mult;
|
|
37
|
+
coordStart = coordStart + upstream.length * mult;
|
|
38
|
+
}
|
|
39
|
+
const middleChunks = [];
|
|
40
|
+
for (let idx = 0; idx < chunks.length; idx++) {
|
|
41
|
+
const chunk = chunks[idx];
|
|
42
|
+
const intron = sequence.slice(chunk.end, (_a = chunks[idx + 1]) === null || _a === void 0 ? void 0 : _a.start);
|
|
43
|
+
const s = sequence.slice(chunk.start, chunk.end);
|
|
44
|
+
const { segments, remainder } = (0, util_1.splitString)({
|
|
45
|
+
str: hasCds
|
|
46
|
+
? chunk.type === 'CDS'
|
|
47
|
+
? toUpper(s)
|
|
48
|
+
: toLower(s)
|
|
49
|
+
: toUpper(s),
|
|
50
|
+
charactersPerRow,
|
|
51
|
+
currRemainder,
|
|
52
|
+
showCoordinates,
|
|
53
|
+
});
|
|
54
|
+
middleChunks.push(react_1.default.createElement(SequenceDisplay_1.default, { key: JSON.stringify(chunk) + '-mid', model: model, color: chunk.type === 'CDS' ? util_1.cdsColor : util_1.utrColor, strand: mult, start: currStart, coordStart: coordStart, chunks: segments }));
|
|
55
|
+
currRemainder = remainder;
|
|
56
|
+
currStart = currStart + s.length * mult;
|
|
57
|
+
coordStart = coordStart + s.length * mult;
|
|
58
|
+
if (intron && includeIntrons && idx < chunks.length - 1) {
|
|
59
|
+
const str = toLower(collapseIntron && intron.length > intronBp * 2
|
|
60
|
+
? `${intron.slice(0, intronBp)}...${intron.slice(-intronBp)}`
|
|
61
|
+
: intron);
|
|
62
|
+
const { segments, remainder } = (0, util_1.splitString)({
|
|
63
|
+
str,
|
|
64
|
+
charactersPerRow,
|
|
65
|
+
currRemainder,
|
|
66
|
+
showCoordinates,
|
|
67
|
+
});
|
|
68
|
+
if (segments.length) {
|
|
69
|
+
middleChunks.push(react_1.default.createElement(SequenceDisplay_1.default, { key: JSON.stringify(chunk) + '-intron', model: model, strand: mult, coordStart: coordStart, start: currStart, chunks: segments }));
|
|
70
|
+
currRemainder = remainder;
|
|
71
|
+
currStart = currStart + str.length * mult;
|
|
72
|
+
coordStart = coordStart + str.length * mult;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
let downstreamChunk = null;
|
|
77
|
+
if (downstream) {
|
|
78
|
+
const { segments } = (0, util_1.splitString)({
|
|
79
|
+
str: toLower(downstream),
|
|
80
|
+
charactersPerRow,
|
|
81
|
+
currRemainder,
|
|
82
|
+
showCoordinates,
|
|
83
|
+
});
|
|
84
|
+
downstreamChunk = (react_1.default.createElement(SequenceDisplay_1.default, { start: currStart, model: model, strand: mult, chunks: segments, coordStart: coordStart, color: util_1.updownstreamColor }));
|
|
85
|
+
}
|
|
15
86
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const intron = sequence.slice(chunk.end, (_a = chunks[idx + 1]) === null || _a === void 0 ? void 0 : _a.start);
|
|
20
|
-
return (react_1.default.createElement(react_1.default.Fragment, { key: JSON.stringify(chunk) },
|
|
21
|
-
react_1.default.createElement("span", { style: {
|
|
22
|
-
background: chunk.type === 'CDS' ? util_1.cdsColor : util_1.utrColor,
|
|
23
|
-
} }, hasCds
|
|
24
|
-
? chunk.type === 'CDS'
|
|
25
|
-
? toUpper(sequence.slice(chunk.start, chunk.end))
|
|
26
|
-
: toLower(sequence.slice(chunk.start, chunk.end))
|
|
27
|
-
: toUpper(sequence.slice(chunk.start, chunk.end))),
|
|
28
|
-
includeIntrons && idx < chunks.length - 1 ? (react_1.default.createElement("span", { style: { background: util_1.intronColor } }, toLower(collapseIntron && intron.length > intronBp * 2
|
|
29
|
-
? `${intron.slice(0, intronBp)}...${intron.slice(-intronBp)}`
|
|
30
|
-
: intron))) : null));
|
|
31
|
-
}),
|
|
32
|
-
downstream ? (react_1.default.createElement("span", { style: { background: util_1.updownstreamColor } }, toLower(downstream))) : null));
|
|
87
|
+
upstreamChunk,
|
|
88
|
+
middleChunks,
|
|
89
|
+
downstreamChunk));
|
|
33
90
|
});
|
|
34
91
|
exports.default = CDNASequence;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Feat } from '../../util';
|
|
3
|
-
|
|
3
|
+
import { SequenceFeatureDetailsModel } from '../model';
|
|
4
|
+
declare const CDSSequence: ({ cds, sequence, model, }: {
|
|
4
5
|
cds: Feat[];
|
|
5
6
|
sequence: string;
|
|
6
|
-
|
|
7
|
+
model: SequenceFeatureDetailsModel;
|
|
8
|
+
}) => React.JSX.Element;
|
|
9
|
+
export default CDSSequence;
|
|
@@ -4,9 +4,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const mobx_react_1 = require("mobx-react");
|
|
8
|
+
// locals
|
|
7
9
|
const util_1 = require("../util");
|
|
8
10
|
const util_2 = require("../../util");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
11
|
+
const SequenceDisplay_1 = __importDefault(require("./SequenceDisplay"));
|
|
12
|
+
const CDSSequence = (0, mobx_react_1.observer)(function ({ cds, sequence, model, }) {
|
|
13
|
+
const { charactersPerRow, showCoordinates } = model;
|
|
14
|
+
const { segments } = (0, util_1.splitString)({
|
|
15
|
+
str: (0, util_2.stitch)(cds, sequence),
|
|
16
|
+
charactersPerRow,
|
|
17
|
+
showCoordinates,
|
|
18
|
+
});
|
|
19
|
+
return (react_1.default.createElement(SequenceDisplay_1.default, { model: model, color: util_1.cdsColor, chunks: segments, start: 0 }));
|
|
20
|
+
});
|
|
12
21
|
exports.default = CDSSequence;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
|
|
2
|
+
import { SequenceFeatureDetailsModel } from '../model';
|
|
3
|
+
import { SimpleFeatureSerialized } from '../../../util';
|
|
4
|
+
declare const GenomicSequence: ({ sequence, upstream, feature, downstream, model, }: {
|
|
3
5
|
sequence: string;
|
|
6
|
+
feature: SimpleFeatureSerialized;
|
|
4
7
|
upstream?: string;
|
|
5
8
|
downstream?: string;
|
|
6
|
-
|
|
9
|
+
model: SequenceFeatureDetailsModel;
|
|
10
|
+
}) => React.JSX.Element;
|
|
11
|
+
export default GenomicSequence;
|
|
@@ -4,11 +4,57 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const mobx_react_1 = require("mobx-react");
|
|
8
|
+
// locals
|
|
7
9
|
const util_1 = require("../util");
|
|
8
|
-
|
|
10
|
+
const SequenceDisplay_1 = __importDefault(require("./SequenceDisplay"));
|
|
11
|
+
const GenomicSequence = (0, mobx_react_1.observer)(function ({ sequence, upstream, feature, downstream, model, }) {
|
|
12
|
+
const { charactersPerRow, showCoordinatesSetting, showCoordinates } = model;
|
|
13
|
+
let currStart = 0;
|
|
14
|
+
let upstreamChunk = null;
|
|
15
|
+
let currRemainder = 0;
|
|
16
|
+
const strand = feature.strand === -1 ? -1 : 1;
|
|
17
|
+
const fullGenomicCoordinates = showCoordinatesSetting === 'genomic';
|
|
18
|
+
const mult = fullGenomicCoordinates ? strand : 1;
|
|
19
|
+
let coordStart = fullGenomicCoordinates
|
|
20
|
+
? strand > 0
|
|
21
|
+
? feature.start + 1 - ((upstream === null || upstream === void 0 ? void 0 : upstream.length) || 0)
|
|
22
|
+
: feature.end + ((upstream === null || upstream === void 0 ? void 0 : upstream.length) || 0)
|
|
23
|
+
: 0;
|
|
24
|
+
if (upstream) {
|
|
25
|
+
const { segments, remainder } = (0, util_1.splitString)({
|
|
26
|
+
str: upstream,
|
|
27
|
+
charactersPerRow,
|
|
28
|
+
showCoordinates,
|
|
29
|
+
});
|
|
30
|
+
upstreamChunk = (react_1.default.createElement(SequenceDisplay_1.default, { model: model, color: util_1.updownstreamColor, start: currStart, coordStart: coordStart, chunks: segments }));
|
|
31
|
+
currRemainder = remainder;
|
|
32
|
+
currStart = currStart + upstream.length * mult;
|
|
33
|
+
coordStart = coordStart + upstream.length * mult;
|
|
34
|
+
}
|
|
35
|
+
const { segments, remainder } = (0, util_1.splitString)({
|
|
36
|
+
str: sequence,
|
|
37
|
+
charactersPerRow,
|
|
38
|
+
showCoordinates,
|
|
39
|
+
currRemainder,
|
|
40
|
+
});
|
|
41
|
+
const middleChunk = (react_1.default.createElement(SequenceDisplay_1.default, { model: model, color: util_1.genomeColor, start: currStart, coordStart: coordStart, chunks: segments }));
|
|
42
|
+
currRemainder = remainder;
|
|
43
|
+
currStart += sequence.length * mult;
|
|
44
|
+
coordStart = coordStart + sequence.length * mult;
|
|
45
|
+
let downstreamChunk = null;
|
|
46
|
+
if (downstream) {
|
|
47
|
+
const { segments } = (0, util_1.splitString)({
|
|
48
|
+
str: downstream,
|
|
49
|
+
charactersPerRow,
|
|
50
|
+
currRemainder,
|
|
51
|
+
showCoordinates,
|
|
52
|
+
});
|
|
53
|
+
downstreamChunk = (react_1.default.createElement(SequenceDisplay_1.default, { start: currStart, model: model, chunks: segments, coordStart: coordStart, color: util_1.updownstreamColor }));
|
|
54
|
+
}
|
|
9
55
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
56
|
+
upstreamChunk,
|
|
57
|
+
middleChunk,
|
|
58
|
+
downstreamChunk));
|
|
59
|
+
});
|
|
14
60
|
exports.default = GenomicSequence;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Feat } from '../../util';
|
|
3
|
-
|
|
3
|
+
import { SequenceFeatureDetailsModel } from '../model';
|
|
4
|
+
declare const ProteinSequence: ({ cds, sequence, codonTable, model, }: {
|
|
4
5
|
cds: Feat[];
|
|
5
6
|
sequence: string;
|
|
6
7
|
codonTable: Record<string, string>;
|
|
7
|
-
|
|
8
|
+
model: SequenceFeatureDetailsModel;
|
|
9
|
+
}) => React.JSX.Element;
|
|
10
|
+
export default ProteinSequence;
|
|
@@ -4,15 +4,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const mobx_react_1 = require("mobx-react");
|
|
8
|
+
// locals
|
|
7
9
|
const util_1 = require("../../util");
|
|
8
10
|
const util_2 = require("../util");
|
|
9
|
-
|
|
11
|
+
const SequenceDisplay_1 = __importDefault(require("./SequenceDisplay"));
|
|
12
|
+
const ProteinSequence = (0, mobx_react_1.observer)(function ({ cds, sequence, codonTable, model, }) {
|
|
13
|
+
const { charactersPerRow, showCoordinates } = model;
|
|
10
14
|
const str = (0, util_1.stitch)(cds, sequence);
|
|
11
15
|
let protein = '';
|
|
12
16
|
for (let i = 0; i < str.length; i += 3) {
|
|
13
17
|
// use & symbol for undefined codon, or partial slice
|
|
14
18
|
protein += codonTable[str.slice(i, i + 3)] || '&';
|
|
15
19
|
}
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
const { segments } = (0, util_2.splitString)({
|
|
21
|
+
str: protein,
|
|
22
|
+
charactersPerRow,
|
|
23
|
+
showCoordinates,
|
|
24
|
+
});
|
|
25
|
+
return (react_1.default.createElement(SequenceDisplay_1.default, { model: model, color: util_2.proteinColor, chunks: segments, start: 0 }));
|
|
26
|
+
});
|
|
18
27
|
exports.default = ProteinSequence;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { SequenceFeatureDetailsModel } from '../model';
|
|
3
|
+
declare const SequenceDisplay: ({ chunks, start, color, strand, coordStart, model, }: {
|
|
4
|
+
chunks: string[];
|
|
5
|
+
start: number;
|
|
6
|
+
coordStart?: number;
|
|
7
|
+
strand?: number;
|
|
8
|
+
color?: string;
|
|
9
|
+
model: SequenceFeatureDetailsModel;
|
|
10
|
+
}) => React.JSX.Element[];
|
|
11
|
+
export default SequenceDisplay;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const mobx_react_1 = require("mobx-react");
|
|
8
|
+
const SequenceDisplay = (0, mobx_react_1.observer)(function ({ chunks, start, color, strand = 1, coordStart = start, model, }) {
|
|
9
|
+
const { charactersPerRow, showCoordinates } = model;
|
|
10
|
+
return chunks.map((chunk, idx) => {
|
|
11
|
+
var _a;
|
|
12
|
+
const f = coordStart - (start % charactersPerRow);
|
|
13
|
+
const prefix = (idx == 0 && start % charactersPerRow == 0) || idx > 0
|
|
14
|
+
? `${f + idx * strand * charactersPerRow}`.padStart(4) + ' '
|
|
15
|
+
: '';
|
|
16
|
+
const postfix = idx === chunks.length - 1 &&
|
|
17
|
+
(((_a = chunks.at(-1)) === null || _a === void 0 ? void 0 : _a.replaceAll(' ', '').length) || 0) +
|
|
18
|
+
(idx === 0 ? start % charactersPerRow : 0) !==
|
|
19
|
+
charactersPerRow
|
|
20
|
+
? null
|
|
21
|
+
: showCoordinates
|
|
22
|
+
? ' \n'
|
|
23
|
+
: '';
|
|
24
|
+
return (react_1.default.createElement(react_1.default.Fragment, { key: `${chunk}-${idx}` },
|
|
25
|
+
showCoordinates ? prefix : null,
|
|
26
|
+
react_1.default.createElement("span", { style: { background: color } }, chunk),
|
|
27
|
+
postfix));
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
exports.default = SequenceDisplay;
|
|
@@ -4,3 +4,14 @@ export declare const proteinColor = "rgb(220,160,220)";
|
|
|
4
4
|
export declare const cdsColor = "rgb(220,220,180)";
|
|
5
5
|
export declare const updownstreamColor = "rgba(250,200,200)";
|
|
6
6
|
export declare const genomeColor = "rgb(200,280,200)";
|
|
7
|
+
export declare function splitString({ str, charactersPerRow, showCoordinates, currRemainder, splitSize, }: {
|
|
8
|
+
str: string;
|
|
9
|
+
charactersPerRow: number;
|
|
10
|
+
showCoordinates: boolean;
|
|
11
|
+
currRemainder?: number;
|
|
12
|
+
splitStart?: number;
|
|
13
|
+
splitSize?: number;
|
|
14
|
+
}): {
|
|
15
|
+
segments: any[];
|
|
16
|
+
remainder: number;
|
|
17
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.genomeColor = exports.updownstreamColor = exports.cdsColor = exports.proteinColor = exports.utrColor = exports.intronColor = void 0;
|
|
3
|
+
exports.splitString = exports.genomeColor = exports.updownstreamColor = exports.cdsColor = exports.proteinColor = exports.utrColor = exports.intronColor = void 0;
|
|
4
4
|
// note that these are currently put into the style section instead of being
|
|
5
5
|
// defined in classes to aid copy and paste to an external document e.g. word
|
|
6
6
|
exports.intronColor = undefined;
|
|
@@ -9,3 +9,45 @@ exports.proteinColor = 'rgb(220,160,220)';
|
|
|
9
9
|
exports.cdsColor = 'rgb(220,220,180)';
|
|
10
10
|
exports.updownstreamColor = 'rgba(250,200,200)';
|
|
11
11
|
exports.genomeColor = 'rgb(200,280,200)';
|
|
12
|
+
function splitString({ str, charactersPerRow, showCoordinates, currRemainder = 0, splitSize = 10, }) {
|
|
13
|
+
var _a;
|
|
14
|
+
const numChunks = Math.ceil(str.length / charactersPerRow);
|
|
15
|
+
const chunks = new Array(numChunks);
|
|
16
|
+
let splitStart = currRemainder % 10;
|
|
17
|
+
let iter = 0;
|
|
18
|
+
let offset = 0;
|
|
19
|
+
for (; iter < numChunks + 1; ++iter) {
|
|
20
|
+
const inc = iter === 0 ? charactersPerRow - currRemainder : charactersPerRow;
|
|
21
|
+
const r = str.slice(offset, offset + inc);
|
|
22
|
+
if (!r) {
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
if (showCoordinates) {
|
|
26
|
+
let res = '';
|
|
27
|
+
for (let i = 0, j = splitStart; i < r.length; i++, j++) {
|
|
28
|
+
// note: this adds a space at the start but it causes trouble to try to
|
|
29
|
+
// say e.g. j%splitSize==0 && j to try to only add non-zero spaces
|
|
30
|
+
if (j % splitSize === 0) {
|
|
31
|
+
res += ' ';
|
|
32
|
+
j = 0;
|
|
33
|
+
}
|
|
34
|
+
res += r[i];
|
|
35
|
+
}
|
|
36
|
+
if (res) {
|
|
37
|
+
chunks[iter] = res;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
chunks[iter] = r;
|
|
42
|
+
}
|
|
43
|
+
splitStart = 0; // after newline, reset
|
|
44
|
+
offset += inc;
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
segments: chunks,
|
|
48
|
+
remainder: ((((_a = chunks.at(-1)) === null || _a === void 0 ? void 0 : _a.replaceAll(' ', '').length) || 0) +
|
|
49
|
+
(iter < 2 ? currRemainder : 0)) %
|
|
50
|
+
charactersPerRow,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
exports.splitString = splitString;
|