@teselagen/ove 0.7.30-beta.2 → 0.7.31
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/CircularView/Labels/index.d.ts +1 -0
- package/CreateAnnotationsPage.d.ts +3 -4
- package/index.cjs.js +12310 -11063
- package/index.es.js +12310 -11063
- package/index.umd.js +13613 -12366
- package/ove.css +55 -55
- package/package.json +9 -13
- package/selectors/orfsSelector.d.ts +2 -2
- package/selectors/translationsSelector.d.ts +1 -1
- package/src/AlignmentView/index.js +11 -44
- package/src/AutoAnnotate.js +4 -4
- package/src/CircularView/Labels/index.js +84 -49
- package/src/CreateAnnotationsPage.js +2 -1
- package/src/GlobalDialogUtils.js +2 -2
- package/src/RowItem/Labels.js +5 -4
- package/src/ToolBar/alignmentTool.js +2 -2
- package/src/helperComponents/MergeFeaturesDialog/index.js +2 -2
- package/src/redux/alignments.js +2 -2
- package/src/redux/sequenceData/index.js +2 -2
- package/src/redux/sequenceData/upsertDeleteActionGenerator.js +2 -2
- package/src/selectors/cutsitesSelector.js +2 -2
- package/src/selectors/translationsSelector.js +3 -3
- package/src/utils/cleanSequenceData_DEPRECATED/arrayToObjWithIds.js +2 -2
- package/src/withEditorInteractions/index.js +136 -83
- package/src/withEditorProps/index.js +2 -2
- package/fileUtils.d.ts +0 -12
- package/html2canvas.esm--JN4fLQL.js +0 -7891
- package/html2canvas.esm-B7d7VJmQ.cjs +0 -7891
- package/src/fileUtils.js +0 -103
- package/style.css +0 -12107
package/ove.css
CHANGED
|
@@ -10724,6 +10724,61 @@ li.bp3-menu-divider:last-child {
|
|
|
10724
10724
|
.veLabelText {
|
|
10725
10725
|
user-select: none;
|
|
10726
10726
|
}
|
|
10727
|
+
.veLabels {
|
|
10728
|
+
font-weight: lighter;
|
|
10729
|
+
}
|
|
10730
|
+
|
|
10731
|
+
.labelTspan:hover {
|
|
10732
|
+
fill: red !important;
|
|
10733
|
+
}
|
|
10734
|
+
|
|
10735
|
+
.labelText {
|
|
10736
|
+
cursor: pointer;
|
|
10737
|
+
}
|
|
10738
|
+
|
|
10739
|
+
.veEditor .veAnnotationHovered:not(.topLevelLabelGroup) {
|
|
10740
|
+
font-weight: bold;
|
|
10741
|
+
}
|
|
10742
|
+
.veEditor
|
|
10743
|
+
.veAnnotationHovered:not(.topLevelLabelGroup):not(
|
|
10744
|
+
.veCircularViewInternalLabelText
|
|
10745
|
+
) {
|
|
10746
|
+
text-decoration: underline;
|
|
10747
|
+
}
|
|
10748
|
+
|
|
10749
|
+
.veEditor .veAnnotationHovered.veCutsiteLabel {
|
|
10750
|
+
font-weight: bold;
|
|
10751
|
+
text-decoration: underline;
|
|
10752
|
+
}
|
|
10753
|
+
|
|
10754
|
+
.bp3-dark .veLabels .veAnnotationHovered:not(.topLevelLabelGroup) {
|
|
10755
|
+
/* fill: white !important; */
|
|
10756
|
+
font-weight: normal;
|
|
10757
|
+
}
|
|
10758
|
+
.bp3-dark .veLabels .veAnnotationHovered rect {
|
|
10759
|
+
fill: rgb(64, 64, 92) !important;
|
|
10760
|
+
}
|
|
10761
|
+
|
|
10762
|
+
.partWithSelectedTag {
|
|
10763
|
+
font-size: 14px !important;
|
|
10764
|
+
font-weight: 900;
|
|
10765
|
+
text-decoration: underline;
|
|
10766
|
+
}
|
|
10767
|
+
.veCircularView .partWithSelectedTag.vePart .veLabelText {
|
|
10768
|
+
/* stroke: #ac68cc; */
|
|
10769
|
+
font-size: 15px !important;
|
|
10770
|
+
}
|
|
10771
|
+
.vePartLabel.partWithSelectedTag {
|
|
10772
|
+
font-size: large !important;
|
|
10773
|
+
}
|
|
10774
|
+
|
|
10775
|
+
.partWithSelectedTag path,
|
|
10776
|
+
path.partWithSelectedTag {
|
|
10777
|
+
stroke-width: 1.5 !important;
|
|
10778
|
+
}
|
|
10779
|
+
/* .veLabelLine {
|
|
10780
|
+
opacity: 0.1;
|
|
10781
|
+
} */
|
|
10727
10782
|
.veRowView {
|
|
10728
10783
|
overflow-x: visible;
|
|
10729
10784
|
}
|
|
@@ -11197,61 +11252,6 @@ li.bp3-menu-divider:last-child {
|
|
|
11197
11252
|
.simple-dialog .bp3-form-content {
|
|
11198
11253
|
height: 40px;
|
|
11199
11254
|
}
|
|
11200
|
-
.veLabels {
|
|
11201
|
-
font-weight: lighter;
|
|
11202
|
-
}
|
|
11203
|
-
|
|
11204
|
-
.labelTspan:hover {
|
|
11205
|
-
fill: red !important;
|
|
11206
|
-
}
|
|
11207
|
-
|
|
11208
|
-
.labelText {
|
|
11209
|
-
cursor: pointer;
|
|
11210
|
-
}
|
|
11211
|
-
|
|
11212
|
-
.veEditor .veAnnotationHovered:not(.topLevelLabelGroup) {
|
|
11213
|
-
font-weight: bold;
|
|
11214
|
-
}
|
|
11215
|
-
.veEditor
|
|
11216
|
-
.veAnnotationHovered:not(.topLevelLabelGroup):not(
|
|
11217
|
-
.veCircularViewInternalLabelText
|
|
11218
|
-
) {
|
|
11219
|
-
text-decoration: underline;
|
|
11220
|
-
}
|
|
11221
|
-
|
|
11222
|
-
.veEditor .veAnnotationHovered.veCutsiteLabel {
|
|
11223
|
-
font-weight: bold;
|
|
11224
|
-
text-decoration: underline;
|
|
11225
|
-
}
|
|
11226
|
-
|
|
11227
|
-
.bp3-dark .veLabels .veAnnotationHovered:not(.topLevelLabelGroup) {
|
|
11228
|
-
/* fill: white !important; */
|
|
11229
|
-
font-weight: normal;
|
|
11230
|
-
}
|
|
11231
|
-
.bp3-dark .veLabels .veAnnotationHovered rect {
|
|
11232
|
-
fill: rgb(64, 64, 92) !important;
|
|
11233
|
-
}
|
|
11234
|
-
|
|
11235
|
-
.partWithSelectedTag {
|
|
11236
|
-
font-size: 14px !important;
|
|
11237
|
-
font-weight: 900;
|
|
11238
|
-
text-decoration: underline;
|
|
11239
|
-
}
|
|
11240
|
-
.veCircularView .partWithSelectedTag.vePart .veLabelText {
|
|
11241
|
-
/* stroke: #ac68cc; */
|
|
11242
|
-
font-size: 15px !important;
|
|
11243
|
-
}
|
|
11244
|
-
.vePartLabel.partWithSelectedTag {
|
|
11245
|
-
font-size: large !important;
|
|
11246
|
-
}
|
|
11247
|
-
|
|
11248
|
-
.partWithSelectedTag path,
|
|
11249
|
-
path.partWithSelectedTag {
|
|
11250
|
-
stroke-width: 1.5 !important;
|
|
11251
|
-
}
|
|
11252
|
-
/* .veLabelLine {
|
|
11253
|
-
opacity: 0.1;
|
|
11254
|
-
} */
|
|
11255
11255
|
.veCircularViewMiddleOfVectorText {
|
|
11256
11256
|
display: flex;
|
|
11257
11257
|
height: 100%;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teselagen/ove",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.31",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -14,19 +14,19 @@
|
|
|
14
14
|
"@blueprintjs/core": "3.54.0",
|
|
15
15
|
"@hello-pangea/dnd": "16.2.0",
|
|
16
16
|
"@risingstack/react-easy-state": "^6.3.0",
|
|
17
|
-
"@teselagen/bio-parsers": "0.4.
|
|
17
|
+
"@teselagen/bio-parsers": "0.4.28",
|
|
18
18
|
"@teselagen/file-utils": "0.3.20",
|
|
19
|
-
"@teselagen/range-utils": "0.3.
|
|
19
|
+
"@teselagen/range-utils": "0.3.13",
|
|
20
20
|
"@teselagen/react-list": "0.8.18",
|
|
21
|
-
"@teselagen/sequence-utils": "0.3.32
|
|
22
|
-
"@teselagen/ui": "0.
|
|
21
|
+
"@teselagen/sequence-utils": "0.3.32",
|
|
22
|
+
"@teselagen/ui": "0.9.4",
|
|
23
23
|
"@use-gesture/react": "10.3.0",
|
|
24
24
|
"biomsa": "^0.2.4",
|
|
25
25
|
"classnames": "^2.3.2",
|
|
26
|
-
"
|
|
26
|
+
"clipboard": "^2.0.11",
|
|
27
|
+
"color": "^3.2.1",
|
|
27
28
|
"combokeys": "^3.0.1",
|
|
28
29
|
"copy-to-clipboard": "^3.3.1",
|
|
29
|
-
"cypress-real-events": "^1.13.0",
|
|
30
30
|
"deep-equal": "^1.1.1",
|
|
31
31
|
"dom-to-image": "^2.6.0",
|
|
32
32
|
"downloadjs": "^1.4.7",
|
|
@@ -57,15 +57,11 @@
|
|
|
57
57
|
"redux-thunk": "2.4.1",
|
|
58
58
|
"remark-gfm": "^4.0.0",
|
|
59
59
|
"reselect": "^4.1.7",
|
|
60
|
+
"shortid": "2.2.16",
|
|
60
61
|
"tg-use-local-storage-state": "^16.0.3",
|
|
61
62
|
"to-regex-range": "5.0.1",
|
|
62
63
|
"use-debounce": "^8.0.4",
|
|
63
|
-
"validate.io-nonnegative-integer-array": "^1.0.1"
|
|
64
|
-
"nanoid": "5.1.5"
|
|
65
|
-
},
|
|
66
|
-
"volta": {
|
|
67
|
-
"node": "18.18.0",
|
|
68
|
-
"yarn": "1.22.21"
|
|
64
|
+
"validate.io-nonnegative-integer-array": "^1.0.1"
|
|
69
65
|
},
|
|
70
66
|
"license": "MIT"
|
|
71
67
|
}
|
|
@@ -7,7 +7,7 @@ declare const _default: ((state: any) => {
|
|
|
7
7
|
forward: any;
|
|
8
8
|
annotationTypePlural: string;
|
|
9
9
|
isOrf: boolean;
|
|
10
|
-
id:
|
|
10
|
+
id: any;
|
|
11
11
|
}[]) & import('reselect').OutputSelectorFields<(args_0: any, args_1: any, args_2: any, args_3: any) => {
|
|
12
12
|
start: number;
|
|
13
13
|
end: number;
|
|
@@ -17,7 +17,7 @@ declare const _default: ((state: any) => {
|
|
|
17
17
|
forward: any;
|
|
18
18
|
annotationTypePlural: string;
|
|
19
19
|
isOrf: boolean;
|
|
20
|
-
id:
|
|
20
|
+
id: any;
|
|
21
21
|
}[], {
|
|
22
22
|
clearCache: () => void;
|
|
23
23
|
}> & {
|
|
@@ -7,7 +7,7 @@ declare const _default: ((state: any) => any) & import('reselect').OutputSelecto
|
|
|
7
7
|
forward: any;
|
|
8
8
|
annotationTypePlural: string;
|
|
9
9
|
isOrf: boolean;
|
|
10
|
-
id:
|
|
10
|
+
id: any;
|
|
11
11
|
}[], args_4: any, args_5: any, args_6: any[], args_7: any, args_8: any, args_9: any, args_10: any, args_11: any, args_12: any) => any, {
|
|
12
12
|
clearCache: () => void;
|
|
13
13
|
}> & {
|
|
@@ -15,9 +15,6 @@ import { connect } from "react-redux";
|
|
|
15
15
|
import {
|
|
16
16
|
Button,
|
|
17
17
|
Intent,
|
|
18
|
-
Popover,
|
|
19
|
-
Menu,
|
|
20
|
-
MenuItem,
|
|
21
18
|
Tooltip,
|
|
22
19
|
Icon,
|
|
23
20
|
Spinner,
|
|
@@ -90,6 +87,7 @@ try {
|
|
|
90
87
|
|
|
91
88
|
export const AlignmentView = props => {
|
|
92
89
|
const {
|
|
90
|
+
dimensions,
|
|
93
91
|
alignmentType,
|
|
94
92
|
alignmentRunUpdate,
|
|
95
93
|
alignmentName: _alignmentName,
|
|
@@ -103,13 +101,11 @@ export const AlignmentView = props => {
|
|
|
103
101
|
sequenceLength,
|
|
104
102
|
shouldAutosave,
|
|
105
103
|
store,
|
|
106
|
-
height,
|
|
104
|
+
height: _height,
|
|
107
105
|
minimapLaneHeight,
|
|
108
106
|
minimapLaneSpacing,
|
|
109
107
|
isInPairwiseOverviewView,
|
|
110
108
|
noVisibilityOptions,
|
|
111
|
-
updateAlignmentSortOrder,
|
|
112
|
-
alignmentSortOrder,
|
|
113
109
|
handleBackButtonClicked,
|
|
114
110
|
allowTrimming,
|
|
115
111
|
additionalSelectionLayerRightClickedOptions,
|
|
@@ -121,6 +117,10 @@ export const AlignmentView = props => {
|
|
|
121
117
|
style,
|
|
122
118
|
unmappedSeqs
|
|
123
119
|
} = props;
|
|
120
|
+
let height = _height;
|
|
121
|
+
if (dimensions && dimensions.height) {
|
|
122
|
+
height = dimensions.height;
|
|
123
|
+
}
|
|
124
124
|
|
|
125
125
|
const {
|
|
126
126
|
alignmentId,
|
|
@@ -616,7 +616,6 @@ export const AlignmentView = props => {
|
|
|
616
616
|
} else {
|
|
617
617
|
i = _i;
|
|
618
618
|
}
|
|
619
|
-
|
|
620
619
|
const track = alignmentTracks?.[i];
|
|
621
620
|
if (!track) return null;
|
|
622
621
|
const {
|
|
@@ -636,7 +635,7 @@ export const AlignmentView = props => {
|
|
|
636
635
|
});
|
|
637
636
|
const linearViewWidth =
|
|
638
637
|
(alignmentData || sequenceData).sequence.length * charWidth;
|
|
639
|
-
const name = sequenceData.name || sequenceData.id;
|
|
638
|
+
const name = alignmentData.name || sequenceData.name || sequenceData.id;
|
|
640
639
|
|
|
641
640
|
const tickSpacing = massageTickSpacing(Math.ceil(120 / charWidth));
|
|
642
641
|
|
|
@@ -1261,7 +1260,7 @@ export const AlignmentView = props => {
|
|
|
1261
1260
|
await navigator.clipboard.writeText(seqDataToCopy);
|
|
1262
1261
|
};
|
|
1263
1262
|
|
|
1264
|
-
const
|
|
1263
|
+
const copyAllAlignmentsFastaText = async () => {
|
|
1265
1264
|
await navigator.clipboard.writeText(
|
|
1266
1265
|
getAllAlignmentsFastaText()
|
|
1267
1266
|
);
|
|
@@ -1281,7 +1280,7 @@ export const AlignmentView = props => {
|
|
|
1281
1280
|
"copyAllAlignmentsFastaClipboardHelper",
|
|
1282
1281
|
hotkey: "cmd+c",
|
|
1283
1282
|
onClick: () => {
|
|
1284
|
-
|
|
1283
|
+
copyAllAlignmentsFastaText();
|
|
1285
1284
|
window.toastr.success("Selection Copied");
|
|
1286
1285
|
}
|
|
1287
1286
|
},
|
|
@@ -1289,8 +1288,8 @@ export const AlignmentView = props => {
|
|
|
1289
1288
|
text: `Copy Selection of ${name} as Fasta`,
|
|
1290
1289
|
className:
|
|
1291
1290
|
"copySpecificAlignmentFastaClipboardHelper",
|
|
1292
|
-
onClick:
|
|
1293
|
-
copySpecificAlignmentFasta();
|
|
1291
|
+
onClick: e => {
|
|
1292
|
+
copySpecificAlignmentFasta(e);
|
|
1294
1293
|
window.toastr.success(
|
|
1295
1294
|
"Selection Copied As Fasta"
|
|
1296
1295
|
);
|
|
@@ -1410,7 +1409,6 @@ export const AlignmentView = props => {
|
|
|
1410
1409
|
updateLabelsForInViewFeatures();
|
|
1411
1410
|
}
|
|
1412
1411
|
};
|
|
1413
|
-
|
|
1414
1412
|
return (
|
|
1415
1413
|
<PinchHelper {...pinchHandler}>
|
|
1416
1414
|
<ResizeSensor onResize={handleResize}>
|
|
@@ -1581,37 +1579,6 @@ export const AlignmentView = props => {
|
|
|
1581
1579
|
{...alignmentVisibilityToolOptions}
|
|
1582
1580
|
/>
|
|
1583
1581
|
)}
|
|
1584
|
-
{updateAlignmentSortOrder && !isInPairwiseOverviewView && (
|
|
1585
|
-
<Popover
|
|
1586
|
-
minimal
|
|
1587
|
-
content={
|
|
1588
|
-
<Menu>
|
|
1589
|
-
<MenuItem
|
|
1590
|
-
active={true || alignmentSortOrder}
|
|
1591
|
-
onClick={() => {
|
|
1592
|
-
updateAlignmentSortOrder("Position");
|
|
1593
|
-
}}
|
|
1594
|
-
text="Position"
|
|
1595
|
-
/>
|
|
1596
|
-
<MenuItem
|
|
1597
|
-
active={false || alignmentSortOrder}
|
|
1598
|
-
onClick={() => {
|
|
1599
|
-
updateAlignmentSortOrder("Alphabetical");
|
|
1600
|
-
}}
|
|
1601
|
-
text="Alphabetical"
|
|
1602
|
-
/>
|
|
1603
|
-
</Menu>
|
|
1604
|
-
}
|
|
1605
|
-
target={
|
|
1606
|
-
<Button
|
|
1607
|
-
small
|
|
1608
|
-
text="Sort Order"
|
|
1609
|
-
rightIcon="caret-down"
|
|
1610
|
-
icon="sort"
|
|
1611
|
-
/>
|
|
1612
|
-
}
|
|
1613
|
-
/>
|
|
1614
|
-
)}
|
|
1615
1582
|
{additionalTopEl}
|
|
1616
1583
|
{saveMessage && (
|
|
1617
1584
|
<div
|
package/src/AutoAnnotate.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { unparse } from "papaparse";
|
|
5
5
|
import pluralize from "pluralize";
|
|
6
6
|
import { SubmissionError, reduxForm } from "redux-form";
|
|
7
|
-
import
|
|
7
|
+
import shortid from "shortid";
|
|
8
8
|
import CreateAnnotationsPage from "./CreateAnnotationsPage";
|
|
9
9
|
import { formName } from "./constants";
|
|
10
10
|
import { AutoAnnotateBpMatchingDialog } from "./AutoAnnotateBpMatchingDialog";
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
} from "@teselagen/ui";
|
|
34
34
|
import { startCase } from "lodash-es";
|
|
35
35
|
import withEditorProps from "./withEditorProps";
|
|
36
|
-
import
|
|
36
|
+
import { useEffect, useState } from "react";
|
|
37
37
|
import { Colors, Tab, Tabs } from "@blueprintjs/core";
|
|
38
38
|
import { typeField } from "./helperComponents/PropertiesDialog/typeField";
|
|
39
39
|
|
|
@@ -403,7 +403,7 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
403
403
|
if (ann.matchType === "protein") {
|
|
404
404
|
ann.sequence = convertProteinSeqToDNAIupac(ann.sequence);
|
|
405
405
|
}
|
|
406
|
-
const id =
|
|
406
|
+
const id = shortid();
|
|
407
407
|
annotationsToCheckById[id] = {
|
|
408
408
|
...ann,
|
|
409
409
|
sequence: ann.isRegex
|
|
@@ -428,7 +428,7 @@ FRT GAAGTTCCTATTCTCTAGAAAGTATAGGAACTTC misc_recomb orchid pink 0 0`,
|
|
|
428
428
|
...annotationsToCheckById[a.id],
|
|
429
429
|
...a,
|
|
430
430
|
forward: a.strand !== -1,
|
|
431
|
-
id:
|
|
431
|
+
id: shortid()
|
|
432
432
|
};
|
|
433
433
|
toRet.color =
|
|
434
434
|
toRet.color || getFeatureToColorMap()[toRet.type];
|
|
@@ -8,11 +8,19 @@ import { avoidOverlapWith } from "../drawAnnotations";
|
|
|
8
8
|
|
|
9
9
|
const fontWidthToFontSize = 1.75;
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
let
|
|
11
|
+
export const getTextLengthWithCollapseSpace = (text, collapseWhiteSpace = true) => {
|
|
12
|
+
let displayText = text || "Unlabeled";
|
|
13
|
+
if (collapseWhiteSpace) {
|
|
14
|
+
displayText = displayText.replaceAll(
|
|
15
|
+
/\s+/g,
|
|
16
|
+
" "
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
let len = displayText.length;
|
|
13
20
|
// eslint-disable-next-line no-control-regex
|
|
14
21
|
const nonEnInputReg = /[^\x00-\xff]+/g;
|
|
15
|
-
const nonEnStrings =
|
|
22
|
+
const nonEnStrings =
|
|
23
|
+
displayText.match(nonEnInputReg) || [];
|
|
16
24
|
nonEnStrings.forEach(str => (len += str.length * 0.5));
|
|
17
25
|
return len;
|
|
18
26
|
};
|
|
@@ -58,7 +66,7 @@ function Labels({
|
|
|
58
66
|
_annotationCenterAngle + (rotationRadians || 0);
|
|
59
67
|
return {
|
|
60
68
|
...label,
|
|
61
|
-
width:
|
|
69
|
+
width: getTextLengthWithCollapseSpace(label.text) * fontWidth,
|
|
62
70
|
//three points define the label:
|
|
63
71
|
innerPoint: {
|
|
64
72
|
...polarToSpecialCartesian(
|
|
@@ -214,42 +222,26 @@ const DrawLabelGroup = withHover(function ({
|
|
|
214
222
|
}) {
|
|
215
223
|
let { text = "Unlabeled" } = label;
|
|
216
224
|
|
|
217
|
-
const textLength = getTextLength(text);
|
|
218
225
|
let groupLabelXStart;
|
|
219
226
|
//Add the number of unshown labels
|
|
220
227
|
if (label.labelAndSublabels && label.labelAndSublabels.length > 1) {
|
|
221
|
-
// if (label.x > 0) {
|
|
222
228
|
text = "+" + (label.labelAndSublabels.length - 1) + "," + text;
|
|
223
|
-
// } else {
|
|
224
|
-
// text += ', +' + (label.labelAndSublabels.length - 1)
|
|
225
|
-
// }
|
|
226
229
|
}
|
|
227
230
|
|
|
228
|
-
const labelLength =
|
|
229
|
-
const maxLabelLength = labelAndSublabels.reduce(function (
|
|
230
|
-
currentLength,
|
|
231
|
-
{ text = "Unlabeled" }
|
|
232
|
-
) {
|
|
233
|
-
const _textLength = getTextLength(text);
|
|
234
|
-
if (_textLength > currentLength) {
|
|
235
|
-
return _textLength;
|
|
236
|
-
}
|
|
237
|
-
return currentLength;
|
|
238
|
-
}, 0);
|
|
231
|
+
const labelLength = getTextLengthWithCollapseSpace(text) * fontWidth;
|
|
239
232
|
|
|
240
|
-
const maxLabelWidth = maxLabelLength * fontWidth;
|
|
241
233
|
const labelOnLeft = label.angle > Math.PI;
|
|
242
234
|
let labelXStart = label.x - (labelOnLeft ? labelLength : 0);
|
|
235
|
+
const maxDistance =
|
|
236
|
+
(outerRadius + 90) * Math.max(1, circularViewWidthVsHeightRatio);
|
|
243
237
|
if (condenseOverflowingXLabels) {
|
|
244
238
|
const distancePastBoundary =
|
|
245
239
|
Math.abs(label.x + (labelOnLeft ? -labelLength : labelLength)) -
|
|
246
|
-
|
|
247
|
-
|
|
240
|
+
maxDistance;
|
|
241
|
+
|
|
248
242
|
if (distancePastBoundary > 0) {
|
|
249
243
|
const numberOfCharsToChop =
|
|
250
244
|
Math.ceil(distancePastBoundary / fontWidth) + 2;
|
|
251
|
-
// if (numberOfCharsToChop > text.length) numberOfCharsToChop = text.length
|
|
252
|
-
//label overflows the boundaries!
|
|
253
245
|
text = text.slice(0, -numberOfCharsToChop) + "..";
|
|
254
246
|
groupLabelXStart =
|
|
255
247
|
labelXStart +
|
|
@@ -261,17 +253,58 @@ const DrawLabelGroup = withHover(function ({
|
|
|
261
253
|
const textYStart = label.y + dy / 2;
|
|
262
254
|
|
|
263
255
|
//if label xStart or label xEnd don't fit within the canvas, we need to shorten the label..
|
|
264
|
-
|
|
265
256
|
let content;
|
|
266
257
|
const labelClass = ` veLabelText veLabel veCircularViewLabelText clickable ${label.color} `;
|
|
267
258
|
|
|
268
259
|
if ((multipleLabels || groupLabelXStart !== undefined) && hovered) {
|
|
260
|
+
// Calculate the maximum label length for hovered status
|
|
261
|
+
const maxLabelLength = labelAndSublabels.reduce(function (
|
|
262
|
+
currentLength,
|
|
263
|
+
{ text = "Unlabeled" }
|
|
264
|
+
) {
|
|
265
|
+
const _textLength = getTextLengthWithCollapseSpace(text);
|
|
266
|
+
if (_textLength > currentLength) {
|
|
267
|
+
return _textLength;
|
|
268
|
+
}
|
|
269
|
+
return currentLength;
|
|
270
|
+
}, 0);
|
|
271
|
+
const maxLabelWidth = maxLabelLength * fontWidth;
|
|
272
|
+
|
|
273
|
+
labelXStart = label.x - (labelOnLeft ? maxLabelWidth : 0);
|
|
274
|
+
let distancePastBoundary = Math.abs(label.x + (labelOnLeft ? -maxLabelWidth : maxLabelWidth)) - maxDistance;
|
|
275
|
+
let lableRectWidth = maxLabelWidth - 14;
|
|
276
|
+
|
|
277
|
+
if (maxLabelWidth > maxDistance * 2) {
|
|
278
|
+
labelXStart = -maxDistance;
|
|
279
|
+
lableRectWidth = maxDistance * 2 - 24;
|
|
280
|
+
distancePastBoundary = maxLabelWidth - maxDistance * 2;
|
|
281
|
+
} else if (distancePastBoundary > 0) {
|
|
282
|
+
labelXStart += (labelOnLeft ? distancePastBoundary : -distancePastBoundary);
|
|
283
|
+
distancePastBoundary = 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
269
286
|
//HOVERED: DRAW MULTIPLE LABELS IN A RECTANGLE
|
|
270
287
|
window.isLabelGroupOpen = true;
|
|
271
288
|
let hoveredLabel;
|
|
272
|
-
|
|
273
|
-
|
|
289
|
+
|
|
290
|
+
let truncatedLabelAndSublabels;
|
|
291
|
+
if (distancePastBoundary > 0) {
|
|
292
|
+
truncatedLabelAndSublabels = labelAndSublabels.map(lable => {
|
|
293
|
+
const labelWidth = getTextLengthWithCollapseSpace(lable.text) * fontWidth;
|
|
294
|
+
const truncatedText =
|
|
295
|
+
labelWidth >= lableRectWidth
|
|
296
|
+
? lable.text.slice(
|
|
297
|
+
0,
|
|
298
|
+
-Math.ceil((labelWidth - lableRectWidth) / fontWidth) - 2
|
|
299
|
+
) + ".."
|
|
300
|
+
: lable.text;
|
|
301
|
+
return {
|
|
302
|
+
...lable,
|
|
303
|
+
text: truncatedText
|
|
304
|
+
};
|
|
305
|
+
});
|
|
274
306
|
}
|
|
307
|
+
|
|
275
308
|
labelAndSublabels.some(function (label) {
|
|
276
309
|
if (label.id === hoveredId) {
|
|
277
310
|
hoveredLabel = label;
|
|
@@ -317,7 +350,7 @@ const DrawLabelGroup = withHover(function ({
|
|
|
317
350
|
// zIndex={10}
|
|
318
351
|
x={labelXStart - 4}
|
|
319
352
|
y={labelYStart - dy / 2}
|
|
320
|
-
width={
|
|
353
|
+
width={lableRectWidth + 24}
|
|
321
354
|
height={labelGroupHeight + 4}
|
|
322
355
|
fill="white"
|
|
323
356
|
stroke="black"
|
|
@@ -331,24 +364,26 @@ const DrawLabelGroup = withHover(function ({
|
|
|
331
364
|
fontStyle: label.fontStyle
|
|
332
365
|
}}
|
|
333
366
|
>
|
|
334
|
-
{labelAndSublabels.map(
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
367
|
+
{(truncatedLabelAndSublabels || labelAndSublabels).map(
|
|
368
|
+
function (label, index) {
|
|
369
|
+
return (
|
|
370
|
+
<DrawGroupInnerLabel
|
|
371
|
+
isSubLabel
|
|
372
|
+
noRedux={noRedux}
|
|
373
|
+
editorName={editorName}
|
|
374
|
+
logHover
|
|
375
|
+
key={"labelItem" + index}
|
|
376
|
+
className={
|
|
377
|
+
(label.className || "") +
|
|
378
|
+
labelClass +
|
|
379
|
+
" veDrawGroupInnerLabel"
|
|
380
|
+
}
|
|
381
|
+
id={label.id}
|
|
382
|
+
{...{ labelXStart, label, fontWidth, index, dy }}
|
|
383
|
+
/>
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
)}
|
|
352
387
|
</text>
|
|
353
388
|
</g>
|
|
354
389
|
</PutMyParentOnTop>
|
|
@@ -364,7 +399,7 @@ const DrawLabelGroup = withHover(function ({
|
|
|
364
399
|
data-title={label.title || label.text}
|
|
365
400
|
{...avoidOverlapWith}
|
|
366
401
|
x={labelXStart}
|
|
367
|
-
textLength={
|
|
402
|
+
textLength={getTextLengthWithCollapseSpace(text) * fontWidth}
|
|
368
403
|
lengthAdjust="spacing"
|
|
369
404
|
className={
|
|
370
405
|
labelClass + label.className + (hovered ? " veAnnotationHovered" : "")
|
|
@@ -438,7 +473,7 @@ const DrawGroupInnerLabel = withHover(
|
|
|
438
473
|
data-title={label.title}
|
|
439
474
|
{...avoidOverlapWith}
|
|
440
475
|
x={labelXStart}
|
|
441
|
-
textLength={
|
|
476
|
+
textLength={getTextLengthWithCollapseSpace(label.text) * fontWidth}
|
|
442
477
|
lengthAdjust="spacing"
|
|
443
478
|
onClick={label.onClick}
|
|
444
479
|
onDoubleClick={e => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { compose } from "redux";
|
|
2
2
|
import pluralize from "pluralize";
|
|
3
|
+
|
|
3
4
|
import { formName } from "./constants";
|
|
4
5
|
import { typeField } from "./helperComponents/PropertiesDialog/typeField";
|
|
5
6
|
import {
|
|
@@ -8,7 +9,7 @@ import {
|
|
|
8
9
|
withSelectTableRecords,
|
|
9
10
|
withSelectedEntities
|
|
10
11
|
} from "@teselagen/ui";
|
|
11
|
-
import
|
|
12
|
+
import { useEffect } from "react";
|
|
12
13
|
import { hideDialog } from "./GlobalDialogUtils";
|
|
13
14
|
import { startCase } from "lodash-es";
|
|
14
15
|
import { tidyUpAnnotation } from "@teselagen/sequence-utils";
|
package/src/GlobalDialogUtils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import shortid from "shortid";
|
|
2
2
|
|
|
3
3
|
import { cloneDeep, startCase } from "lodash-es";
|
|
4
4
|
import { convertRangeTo1Based } from "@teselagen/range-utils";
|
|
@@ -36,7 +36,7 @@ export function showDialog({
|
|
|
36
36
|
dialogHolder.CustomModalComponent = ModalComponent;
|
|
37
37
|
dialogHolder.props = props;
|
|
38
38
|
dialogHolder.overrideName = overrideName;
|
|
39
|
-
dialogHolder.setUniqKeyToForceRerender(
|
|
39
|
+
dialogHolder.setUniqKeyToForceRerender(shortid());
|
|
40
40
|
}
|
|
41
41
|
export function hideDialog() {
|
|
42
42
|
delete dialogHolder.dialogType;
|
package/src/RowItem/Labels.js
CHANGED
|
@@ -8,6 +8,7 @@ import { reduce, values, startCase, filter, clamp } from "lodash-es";
|
|
|
8
8
|
import { getRangeLength } from "@teselagen/range-utils";
|
|
9
9
|
import { doesLabelFitInAnnotation } from "./utils";
|
|
10
10
|
import getAnnotationNameAndStartStopString from "../utils/getAnnotationNameAndStartStopString";
|
|
11
|
+
import { getTextLengthWithCollapseSpace } from "../CircularView/Labels";
|
|
11
12
|
|
|
12
13
|
const BUFFER_WIDTH = 6; //labels shouldn't be less than 6px from eachother on the same line
|
|
13
14
|
|
|
@@ -98,11 +99,11 @@ function Labels(props) {
|
|
|
98
99
|
annotation = annotationRange;
|
|
99
100
|
}
|
|
100
101
|
const annotationLength =
|
|
101
|
-
|
|
102
|
+
getTextLengthWithCollapseSpace(
|
|
102
103
|
annotation.name ||
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
)
|
|
104
|
+
(annotation.restrictionEnzyme && annotation.restrictionEnzyme.name) ||
|
|
105
|
+
""
|
|
106
|
+
) * textWidth;
|
|
106
107
|
let { xStart, width } = getXStartAndWidthOfRowAnnotation(
|
|
107
108
|
annotationRange,
|
|
108
109
|
bpsPerRow,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { reduxForm, FieldArray } from "redux-form";
|
|
11
11
|
import { anyToJson } from "@teselagen/bio-parsers";
|
|
12
12
|
import { flatMap } from "lodash-es";
|
|
13
|
-
import
|
|
13
|
+
import uniqid from "shortid";
|
|
14
14
|
import { cloneDeep } from "lodash-es";
|
|
15
15
|
import classNames from "classnames";
|
|
16
16
|
|
|
@@ -155,7 +155,7 @@ class AlignmentTool extends React.Component {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
hideModal();
|
|
158
|
-
const alignmentId =
|
|
158
|
+
const alignmentId = uniqid();
|
|
159
159
|
// const alignmentIdMismatches = uniqid();
|
|
160
160
|
createNewAlignment({
|
|
161
161
|
id: alignmentId,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import
|
|
2
|
+
import uuid from "shortid";
|
|
3
3
|
|
|
4
4
|
import { reduxForm } from "redux-form";
|
|
5
5
|
|
|
@@ -58,7 +58,7 @@ class MergeFeaturesDialog extends React.Component {
|
|
|
58
58
|
upsertFeature(
|
|
59
59
|
{
|
|
60
60
|
...feat1,
|
|
61
|
-
id:
|
|
61
|
+
id: uuid(),
|
|
62
62
|
start: start - 1,
|
|
63
63
|
end: end - 1,
|
|
64
64
|
name
|