@teselagen/ove 0.7.26 → 0.7.28
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/AASliver.js +187 -0
- package/AddLaddersDialog.js +82 -0
- package/AdditionalCutsiteInfoDialog.js +599 -0
- package/AlignmentView/Mismatches.d.ts +3 -3
- package/AlignmentVisibilityTool.js +105 -0
- package/AnnotationContainerHolder.js +20 -0
- package/AnnotationPositioner.js +27 -0
- package/AutoAnnotate.js +501 -0
- package/AutoAnnotateBpMatchingDialog.js +208 -0
- package/Axis.js +151 -0
- package/AxisNumbers.js +35 -0
- package/Browser.js +106 -0
- package/Caret.js +63 -0
- package/Chromatogram.js +293 -0
- package/CircularDnaSequence.js +73 -0
- package/CircularView/Labels/index.d.ts +1 -1
- package/CircularView/index.d.ts +0 -1
- package/CircularZoomMinimap.js +16 -0
- package/ColorPicker.js +30 -0
- package/CommandHotkeyHandler.js +44 -0
- package/CreateAnnotationsPage.d.ts +4 -4
- package/CreateAnnotationsPage.js +98 -0
- package/Cutsite.js +18 -0
- package/CutsiteProperties.js +176 -0
- package/CutsiteSelectionLayers.js +47 -0
- package/Cutsites.js +271 -0
- package/DeletionLayer.js +28 -0
- package/DigestTool/Ladder.d.ts +1 -1
- package/DropHandler.css +21 -0
- package/DropHandler.js +64 -0
- package/EditCaretPosition.js +234 -0
- package/EditTrackNameDialog.js +30 -0
- package/Feature.js +83 -0
- package/FeatureProperties.js +6 -0
- package/FillWindow.js +47 -0
- package/GenbankView.js +74 -0
- package/GeneralProperties.js +117 -0
- package/GenericAnnotationProperties.js +406 -0
- package/GlobalDialog.js +73 -0
- package/GlobalDialogUtils.js +110 -0
- package/GoToDialog.js +25 -0
- package/HorizontalPanelDragHandle.js +35 -0
- package/Keyboard.js +85 -0
- package/Labels.js +327 -0
- package/Ladder.css +20 -0
- package/Ladder.js +303 -0
- package/MeltingTemp.js +85 -0
- package/Menlo.ttf +0 -0
- package/Minimap.js +515 -0
- package/Mismatches.js +134 -0
- package/Monaco.ttf +0 -0
- package/MultipleSeqsDetectedOnImportDialog.js +74 -0
- package/Orf.js +109 -0
- package/OrfProperties.js +117 -0
- package/Orfs.js +35 -0
- package/PCRTool.js +179 -0
- package/PairwiseAlignmentView.js +68 -0
- package/Part.js +34 -0
- package/PartProperties.js +9 -0
- package/PassThrough.js +3 -0
- package/PerformantSelectionLayer.js +32 -0
- package/PinchHelper.js +24 -0
- package/PointedAnnotation.js +347 -0
- package/PositionAnnotationOnCircle.js +26 -0
- package/Primer.js +41 -0
- package/PrimerProperties.js +19 -0
- package/Reflex/index.d.ts +0 -1
- package/ReflexContainer.js +802 -0
- package/ReflexElement.js +160 -0
- package/ReflexEvents.js +77 -0
- package/ReflexSplitter.js +205 -0
- package/RenameSequenceDialog.js +7 -0
- package/RotateCircularViewSlider.js +93 -0
- package/RowView/index.d.ts +0 -1
- package/SelectDialog.js +150 -0
- package/SequenceName.js +15 -0
- package/SimpleCircularOrLinearView.js +381 -0
- package/SimpleOligoPreview.js +39 -0
- package/SingleEnzymeCutsiteInfo.js +139 -0
- package/ToolBar/ToolbarItem.d.ts +1 -3
- package/ToolbarItem.js +192 -0
- package/Translation.js +198 -0
- package/TranslationProperties.js +149 -0
- package/UncontrolledSliderWithPlusMinusBtns.css +5 -0
- package/UncontrolledSliderWithPlusMinusBtns.js +134 -0
- package/VeTopRightContainer.js +12 -0
- package/ZoomCircularViewSlider.js +62 -0
- package/ZoomLinearView.js +47 -0
- package/addAlignment.js +6 -0
- package/addMetaToActionCreators.js +12 -0
- package/addWrappedAddons.js +20 -0
- package/alignmentTool.js +503 -0
- package/alignments.js +379 -0
- package/annotationLabelVisibility.js +2 -0
- package/annotationSearchSelector.js +24 -0
- package/annotationTypes.js +35 -0
- package/annotationVisibility.js +196 -0
- package/annotationsToSupport.js +104 -0
- package/arrayToObjWithIds.js +17 -0
- package/arrayUtils.js +19 -0
- package/array_move.js +10 -0
- package/calculateTickMarkPositionsForGivenRange.js +47 -0
- package/caretPosition.js +27 -0
- package/cdsFeaturesSelector.js +9 -0
- package/charWidth.js +22 -0
- package/circular.js +19 -0
- package/circularSelector.js +4 -0
- package/clickAndDragUtils.js +576 -0
- package/coerceInitialValue.js +7 -0
- package/combineReducersDontIgnoreKeys.js +12 -0
- package/commandUtils.js +20 -0
- package/constants.js +2 -0
- package/copyOptions.js +34 -0
- package/createFragmentLines.js +120 -0
- package/createMergedDefaultStateReducer.js +30 -0
- package/createMetaAction.js +12 -0
- package/createSequenceInputPopup.js +290 -0
- package/createSequenceInputPopupStyle.css +87 -0
- package/createSimpleDialog.js +89 -0
- package/createYourOwnEnzyme.js +39 -0
- package/cutsiteLabelColorSelector.js +6 -0
- package/cutsiteTool.js +88 -0
- package/cutsitesByRangeSelector.js +5 -0
- package/cutsitesSelector.js +61 -0
- package/darkmode.css +98 -0
- package/defaultConfig.js +150 -0
- package/deletionLayers.js +36 -0
- package/description.js +21 -0
- package/digestTool.js +34 -0
- package/dnaToColor.js +17 -0
- package/downloadTool.js +39 -0
- package/draggableClassnames.js +5 -0
- package/drawAnnotations.js +440 -0
- package/drawDirectedPiePiece.js +142 -0
- package/editTool.js +49 -0
- package/editorSelector.js +2 -0
- package/editorUtils.js +205 -0
- package/estimateRowHeight.js +184 -0
- package/featureLengthsToHide.js +27 -0
- package/featureTool.js +34 -0
- package/features.js +19 -0
- package/featuresSelector.js +8 -0
- package/filteredCutsitesSelector.js +136 -0
- package/filteredFeaturesSelector.js +32 -0
- package/filteredPartsSelector.js +57 -0
- package/filteredPrimersSelector.js +27 -0
- package/filteredRestrictionEnzymesSelector.js +1 -0
- package/find.png +0 -0
- package/findTool.js +79 -0
- package/findToolConstants.js +1 -0
- package/frameTranslations.js +52 -0
- package/fullscreen.png +0 -0
- package/getAdditionalEnzymesSelector.js +46 -0
- package/getAngleForPositionMidpoint.js +3 -0
- package/getAnnotationClassnames.js +12 -0
- package/getAnnotationNameAndStartStopString.js +61 -0
- package/getBpsPerRow.js +19 -0
- package/getCutsiteLabelHeights.js +56 -0
- package/getGapMap.js +12 -0
- package/getGaps.js +27 -0
- package/getInternalLabel.js +40 -0
- package/getOveHotkeyDefs.js +12 -0
- package/getPairwiseOverviewLinearViewOptions.js +38 -0
- package/getRangeAnglesSpecial.js +12 -0
- package/getStructuredBases.js +97 -0
- package/getTrackFromEvent.js +25 -0
- package/getVisibleStartEnd.js +7 -0
- package/getXStartAndWidthFromNonCircularRange.js +12 -0
- package/getXStartAndWidthOfRangeWrtRow.js +27 -0
- package/getXStartAndWidthOfRowAnnotation.js +19 -0
- package/getYOffset.js +15 -0
- package/hoveredAnnotation.js +24 -0
- package/{html2canvas.esm--JN4fLQL.js → html2canvas.esm-DiGWN1gP.js} +187 -229
- package/{html2canvas.esm-B7d7VJmQ.cjs → html2canvas.esm-J1esNpMJ.cjs} +187 -229
- package/importTool.js +27 -0
- package/index.cjs.js +48165 -47142
- package/index.es.js +47699 -46676
- package/index.js +71 -0
- package/inlineFindTool.js +38 -0
- package/isElementInViewport.js +29 -0
- package/isEnzymeFilterAndSelector.js +1 -0
- package/isTargetWithinEl.js +6 -0
- package/labelLineIntensity.js +25 -0
- package/labelSize.js +23 -0
- package/ladderDefaults.js +25 -0
- package/lastSavedId.js +20 -0
- package/lineageLines.js +11 -0
- package/linear.png +0 -0
- package/makeStore.js +34 -0
- package/massageTickSpacing.js +19 -0
- package/materiallyAvailable.js +19 -0
- package/middleware.js +112 -0
- package/minimumOrfSize.js +24 -0
- package/minimumOrfSizeSelector.js +2 -0
- package/modalActions.js +3 -0
- package/moveCaret.js +58 -0
- package/name.js +19 -0
- package/normalizeAngle.js +3 -0
- package/normalizeAngleRange.js +9 -0
- package/oligoTool.js +30 -0
- package/onlyUpdateForKeysDeep.js +31 -0
- package/orfFrameToColorMap.js +10 -0
- package/orfTool.js +136 -0
- package/orfsSelector.js +15 -0
- package/ove.css +12107 -0
- package/package.json +8 -7
- package/panelsShown.js +294 -0
- package/partLengthsToHide.js +23 -0
- package/partOverhangs.js +6 -0
- package/partTagSearch.js +69 -0
- package/partTool.js +45 -0
- package/parts.js +19 -0
- package/partsSelector.js +8 -0
- package/pie.png +0 -0
- package/polarToSpecialCartesian.js +7 -0
- package/positionCutsites.js +6 -0
- package/prepareRowData.js +64 -0
- package/primerBases.js +221 -0
- package/primerLengthsToHide.js +27 -0
- package/primers.js +19 -0
- package/primersSelector.js +8 -0
- package/print.png +0 -0
- package/printTool.js +31 -0
- package/propertiesTool.js +40 -0
- package/proteinUtils.js +3 -0
- package/pureNoFunc.js +18 -0
- package/readOnly.js +25 -0
- package/redoTool.js +30 -0
- package/reflex-styles.css +128 -0
- package/reflex-styles.css.map +9 -0
- package/relaxLabelAngles.js +157 -0
- package/relaxLabels_DEPRECATED.js +105 -0
- package/replacementLayers.js +36 -0
- package/restrictionEnzymes.js +52 -0
- package/restrictionEnzymesSelector.js +34 -0
- package/rowviewContants.js +3 -0
- package/ruler.css +89 -0
- package/save.png +0 -0
- package/saveTool.js +44 -0
- package/searchLayersSelector.js +71 -0
- package/selectedAnnotations.js +89 -0
- package/selectedAnnotationsSelector.js +1 -0
- package/selectedCutsitesSelector.js +21 -0
- package/selectedPartTags.js +21 -0
- package/selectionLayer.js +25 -0
- package/selectors/annotationSearchSelector.d.ts +1 -1
- package/sequence.js +12 -0
- package/sequenceDataHistory.js +43 -0
- package/sequenceDataSelector.js +2 -0
- package/sequenceLengthSelector.js +5 -0
- package/sequenceSelector.js +4 -0
- package/sharedActionCreators.js +0 -0
- package/shouldFlipText.js +4 -0
- package/shouldRerender.js +27 -0
- package/showFileDialog.js +25 -0
- package/showGCContent.js +23 -0
- package/show_cut_sites.png +0 -0
- package/show_features.png +0 -0
- package/show_orfs.png +0 -0
- package/show_primers.png +0 -0
- package/simpleDialog.css +13 -0
- package/specialCutsiteFilterOptions.js +22 -0
- package/src/Editor/DropHandler.js +2 -1
- package/src/Editor/index.js +0 -2
- package/src/RowItem/StackedAnnotations/getStructuredBases.js +20 -6
- package/src/ToolBar/cutsiteTool.js +1 -1
- package/src/helperComponents/PropertiesDialog/TranslationProperties.js +2 -1
- package/style.css +3 -12100
- package/tagsToBoldSelector.js +2 -0
- package/toggle_views.svg +1 -0
- package/toolBar.js +23 -0
- package/translationSearchMatchesSelector.js +14 -0
- package/translations.js +20 -0
- package/translationsRawSelector.js +8 -0
- package/translationsSelector.js +137 -0
- package/typeField.js +24 -0
- package/undoTool.js +30 -0
- package/updateEditor.d.ts +1 -3
- package/updateEditor.js +200 -0
- package/updateLabelsForInViewFeatures.js +55 -0
- package/updateLabelsForInViewFeaturesCircView.js +41 -0
- package/updateTrackHelper.js +58 -0
- package/uppercaseSequenceMapFont.js +25 -0
- package/upsertDeleteActionGenerator.js +31 -0
- package/useAAColorType.js +8 -0
- package/useAdditionalOrfStartCodons.js +24 -0
- package/useAnnotationLimits.js +42 -0
- package/useChromatogramPrefs.js +31 -0
- package/useFormValue.js +7 -0
- package/useLadders.js +6 -0
- package/useMeltingTemp.js +7 -0
- package/useTmType.js +10 -0
- package/userDefinedHandlersAndOpts.js +61 -0
- package/utils/getAnnotationNameAndStartStopString.d.ts +1 -5
- package/utils/selectionLayer.d.ts +2 -2
- package/utils.js +37 -0
- package/versionHistory.js +26 -0
- package/versionHistoryTool.js +21 -0
- package/viewSubmenu.js +479 -0
- package/visibilityTool.js +39 -0
- package/withEditorInteractions/getBpsPerRow.d.ts +1 -3
- package/withHover.js +113 -0
- package/withRestrictionEnzymes.js +15 -0
- package/index.umd.js +0 -188322
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { cloneDeep } from "lodash-es";
|
|
2
|
+
|
|
3
|
+
export default relaxLabelAngles;
|
|
4
|
+
|
|
5
|
+
function normalizeAngle(angle) {
|
|
6
|
+
if (angle > Math.PI * 2) {
|
|
7
|
+
return angle - Math.PI * 2;
|
|
8
|
+
} else if (angle < 0) {
|
|
9
|
+
return angle + Math.PI * 2;
|
|
10
|
+
} else {
|
|
11
|
+
return angle;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
//this pure function allows the labels to spread out around the circle
|
|
16
|
+
//and groups overlapping labels together if necessary
|
|
17
|
+
function relaxLabelAngles(_labelPoints, spacing, maxradius) {
|
|
18
|
+
const maxLabelsPerQuadrant = Math.floor(maxradius / spacing) + 4;
|
|
19
|
+
let labels = cloneDeep(_labelPoints);
|
|
20
|
+
if (labels.length > maxLabelsPerQuadrant * 4) {
|
|
21
|
+
//group overlapping labels together
|
|
22
|
+
labels = combineLabels(labels, maxLabelsPerQuadrant * 4);
|
|
23
|
+
}
|
|
24
|
+
// labels = labels.sort(sortLabelsByAngle)
|
|
25
|
+
|
|
26
|
+
// Sort labels into four quadrants of the screen.
|
|
27
|
+
const totalLength = Math.PI * 2;
|
|
28
|
+
|
|
29
|
+
let rightTopLabels = [];
|
|
30
|
+
let rightBottomLabels = [];
|
|
31
|
+
let leftTopLabels = [];
|
|
32
|
+
let leftBottomLabels = [];
|
|
33
|
+
|
|
34
|
+
let label;
|
|
35
|
+
for (let i = 0; i < labels.length; i++) {
|
|
36
|
+
label = labels[i];
|
|
37
|
+
label.angle = normalizeAngle(label.angle);
|
|
38
|
+
const labelCenter = label.angle;
|
|
39
|
+
if (labelCenter <= totalLength / 4) {
|
|
40
|
+
rightTopLabels.push(label);
|
|
41
|
+
} else if (
|
|
42
|
+
labelCenter > totalLength / 4 &&
|
|
43
|
+
labelCenter <= totalLength / 2
|
|
44
|
+
) {
|
|
45
|
+
rightBottomLabels.push(label);
|
|
46
|
+
} else if (
|
|
47
|
+
labelCenter > totalLength / 2 &&
|
|
48
|
+
labelCenter <= (3 * totalLength) / 4
|
|
49
|
+
) {
|
|
50
|
+
leftBottomLabels.push(label);
|
|
51
|
+
} else {
|
|
52
|
+
leftTopLabels.push(label);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function repositionAndGroupLabels(labels /* logtrue */) {
|
|
57
|
+
const extraSpaces = Math.max(maxLabelsPerQuadrant - labels.length, 0);
|
|
58
|
+
let lastLabelYPosition = 0 - spacing / 2; // spacing to count label height
|
|
59
|
+
let lastlabel;
|
|
60
|
+
return labels
|
|
61
|
+
.map(function (label, idx) {
|
|
62
|
+
if (Math.abs(lastLabelYPosition) > maxradius + 80) {
|
|
63
|
+
lastlabel.labelAndSublabels.push(label);
|
|
64
|
+
lastlabel.labelIds[label.id] = true;
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
lastlabel = label;
|
|
68
|
+
if (label.y < lastLabelYPosition) {
|
|
69
|
+
const naturalSlot = Math.floor(Math.abs(label.y / spacing));
|
|
70
|
+
if (naturalSlot > extraSpaces) {
|
|
71
|
+
if (idx < naturalSlot && extraSpaces > 0) {
|
|
72
|
+
lastLabelYPosition = label.y;
|
|
73
|
+
}
|
|
74
|
+
label.y = lastLabelYPosition;
|
|
75
|
+
}
|
|
76
|
+
let x = Math.sqrt(Math.pow(maxradius, 2) - Math.pow(label.y, 2));
|
|
77
|
+
if (!x) x = 0;
|
|
78
|
+
label.x = label.x > 0 ? x : -x;
|
|
79
|
+
lastLabelYPosition = label.y - spacing;
|
|
80
|
+
} else {
|
|
81
|
+
label.y = lastLabelYPosition;
|
|
82
|
+
lastLabelYPosition = label.y - spacing;
|
|
83
|
+
}
|
|
84
|
+
return label;
|
|
85
|
+
})
|
|
86
|
+
.filter(function (l) {
|
|
87
|
+
return !!l;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Scale Right Top Labels
|
|
92
|
+
let labelsToReturn = [];
|
|
93
|
+
rightTopLabels = rightTopLabels.sort(sortLabelsByAngleReverse);
|
|
94
|
+
labelsToReturn = labelsToReturn.concat(
|
|
95
|
+
repositionAndGroupLabels(rightTopLabels, true)
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
// Scale Right Bottom Labels
|
|
99
|
+
rightBottomLabels = rightBottomLabels.sort(sortLabelsByAngle);
|
|
100
|
+
labelsToReturn = labelsToReturn.concat(
|
|
101
|
+
flipLabelYs(repositionAndGroupLabels(flipLabelYs(rightBottomLabels)))
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// Scale Left Bottom Labels
|
|
105
|
+
leftBottomLabels = leftBottomLabels.sort(sortLabelsByAngleReverse);
|
|
106
|
+
labelsToReturn = labelsToReturn.concat(
|
|
107
|
+
flipLabelYs(repositionAndGroupLabels(flipLabelYs(leftBottomLabels)))
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
// Scale Left Top Labels
|
|
111
|
+
leftTopLabels = leftTopLabels.sort(sortLabelsByAngle);
|
|
112
|
+
labelsToReturn = labelsToReturn.concat(
|
|
113
|
+
repositionAndGroupLabels(leftTopLabels)
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return labelsToReturn;
|
|
117
|
+
|
|
118
|
+
function flipLabelYs(labels) {
|
|
119
|
+
return labels.map(function (label) {
|
|
120
|
+
label.y = -label.y;
|
|
121
|
+
return label;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// function sortLabelsByHeight(a, b) {
|
|
127
|
+
// return b.innerPoint.y - a.innerPoint.y
|
|
128
|
+
// }
|
|
129
|
+
|
|
130
|
+
function sortLabelsByAngle(a, b) {
|
|
131
|
+
return a.angle - b.angle;
|
|
132
|
+
}
|
|
133
|
+
function sortLabelsByAngleReverse(b, a) {
|
|
134
|
+
return a.angle - b.angle;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
//function that groups labels that fall within the same angle together
|
|
138
|
+
function combineLabels(labels, numberOfBuckets) {
|
|
139
|
+
const buckets = {};
|
|
140
|
+
Object.keys(labels).forEach(function (key) {
|
|
141
|
+
const label = labels[key];
|
|
142
|
+
|
|
143
|
+
const bucket = Math.floor(
|
|
144
|
+
(label.annotationCenterAngle / 6.29) * numberOfBuckets
|
|
145
|
+
);
|
|
146
|
+
if (!buckets[bucket]) {
|
|
147
|
+
buckets[bucket] = label;
|
|
148
|
+
} else {
|
|
149
|
+
buckets[bucket].labelAndSublabels.push(label);
|
|
150
|
+
buckets[bucket].labelIds[label.id] = true;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
const combinedLabels = Object.keys(buckets).map(function (key) {
|
|
154
|
+
return buckets[key];
|
|
155
|
+
});
|
|
156
|
+
return combinedLabels;
|
|
157
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// import intervalTree2 from "node-interval-tree";
|
|
3
|
+
// var xRanges = new intervalTree2(0)
|
|
4
|
+
// var yRanges = new intervalTree2(0)
|
|
5
|
+
// iTree.search(start, end)
|
|
6
|
+
// featureITree.add(startAngle, expandedEndAngle, undefined, {...annotationCopy})
|
|
7
|
+
|
|
8
|
+
let alpha = 1.5; //the larger the alpha, the fewer loops through relax necessary, but too large and things are spaced unevenly
|
|
9
|
+
let spacing = 12;
|
|
10
|
+
let relaxCounter = 0;
|
|
11
|
+
export default function relaxLabels(labelPoints) {
|
|
12
|
+
let mutableLabelPoints = labelPoints.map(function (point) {
|
|
13
|
+
return {
|
|
14
|
+
...point
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
function spreadPointsOutOnCircle(labels) {}
|
|
18
|
+
function relax() {
|
|
19
|
+
let again = false;
|
|
20
|
+
relaxCounter++;
|
|
21
|
+
mutableLabelPoints.forEach(function (point1, index1) {
|
|
22
|
+
// var xOverlaps = xRanges.search(point1.x, point1.x + point1.width)
|
|
23
|
+
// var yOverlaps = yRanges.search(point1.y, point1.y + point1.height)
|
|
24
|
+
// xOverlaps
|
|
25
|
+
// xRanges.add(point1.x, point1.x + point1.width, undefined, point1)
|
|
26
|
+
// yRanges.add(point1.y, point1.y + point1.height, undefined, point1)
|
|
27
|
+
|
|
28
|
+
mutableLabelPoints.forEach(function (point2, index2) {
|
|
29
|
+
// a & b are the same element and don't collide.
|
|
30
|
+
if (index1 === index2) return;
|
|
31
|
+
|
|
32
|
+
// a & b are on opposite sides of the chart and
|
|
33
|
+
// don't collide
|
|
34
|
+
if (
|
|
35
|
+
(point1.x > 0 && point2.x <= 0) ||
|
|
36
|
+
(point1.x < 0 && point2.x >= 0)
|
|
37
|
+
) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Now let's calculate the distance between
|
|
41
|
+
// these elements.
|
|
42
|
+
let deltaY = point1.y - point2.y;
|
|
43
|
+
|
|
44
|
+
// Our spacing is greater than our specified spacing,
|
|
45
|
+
// so they don't collide.
|
|
46
|
+
if (Math.abs(deltaY) > spacing) return;
|
|
47
|
+
|
|
48
|
+
// If the labels collide, we'll push each
|
|
49
|
+
// of the two labels up and down a little bit.
|
|
50
|
+
let weight1 = point1.y > 0 ? 0.5 : -0.5;
|
|
51
|
+
let weight2 = point2.y > 0 ? 0.5 : -0.5;
|
|
52
|
+
again = true;
|
|
53
|
+
let sign = deltaY > 0 ? 1 : -1;
|
|
54
|
+
let adjust = sign * alpha;
|
|
55
|
+
point1.y += adjust + weight1;
|
|
56
|
+
point2.y -= adjust + weight2;
|
|
57
|
+
|
|
58
|
+
// point1.x += -weight1
|
|
59
|
+
// point2.x -= -weight2
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
// Adjust our line leaders here
|
|
63
|
+
// so that they follow the labels.
|
|
64
|
+
if (again && relaxCounter < 1) {
|
|
65
|
+
relax();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
relax();
|
|
69
|
+
|
|
70
|
+
//group colliding labels
|
|
71
|
+
let stableLabels = [];
|
|
72
|
+
mutableLabelPoints.forEach(function (point1) {
|
|
73
|
+
let collision = false;
|
|
74
|
+
stableLabels.some(function (point2) {
|
|
75
|
+
// a & b are on opposite sides of the chart and
|
|
76
|
+
// don't collide
|
|
77
|
+
if ((point1.x > 0 && point2.x <= 0) || (point1.x < 0 && point2.x >= 0)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
// Now let's calculate the distance between
|
|
81
|
+
// these elements.
|
|
82
|
+
let deltaY = point1.y - point2.y;
|
|
83
|
+
|
|
84
|
+
// Our spacing is greater than our specified spacing,
|
|
85
|
+
// so they don't collide.
|
|
86
|
+
if (Math.abs(deltaY) > spacing) return;
|
|
87
|
+
// If the labels collide, we'll push each
|
|
88
|
+
collision = true;
|
|
89
|
+
point2.labels.push(point1);
|
|
90
|
+
return true; //stop the loop early
|
|
91
|
+
});
|
|
92
|
+
if (!collision) {
|
|
93
|
+
stableLabels.push({
|
|
94
|
+
...point1,
|
|
95
|
+
labels: [point1]
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
stableLabels = stableLabels.sort(sortLabels);
|
|
100
|
+
return stableLabels;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function sortLabels(a, b) {
|
|
104
|
+
return b.y - a.y;
|
|
105
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//./selectionLayer.js
|
|
2
|
+
import { createReducer } from "redux-act";
|
|
3
|
+
import createAction from "./utils/createMetaAction";
|
|
4
|
+
import omit from "lodash/omit";
|
|
5
|
+
|
|
6
|
+
// ------------------------------------
|
|
7
|
+
// Actions
|
|
8
|
+
// ------------------------------------
|
|
9
|
+
export const replacementLayerClear = createAction("replacementLayerClear");
|
|
10
|
+
export const replacementLayerUpdate = createAction("REPLACEMENT_LAYER_UPDATE");
|
|
11
|
+
export const replacementLayerDelete = createAction("REPLACEMENT_LAYER_DELETE");
|
|
12
|
+
|
|
13
|
+
// ------------------------------------
|
|
14
|
+
// Reducer
|
|
15
|
+
// ------------------------------------
|
|
16
|
+
export default createReducer(
|
|
17
|
+
{
|
|
18
|
+
[replacementLayerClear]: () => {
|
|
19
|
+
return {};
|
|
20
|
+
},
|
|
21
|
+
[replacementLayerUpdate]: (state, payload) => {
|
|
22
|
+
return {
|
|
23
|
+
...state,
|
|
24
|
+
[payload.id]: {
|
|
25
|
+
color: "darkolivegreen",
|
|
26
|
+
id: payload.id,
|
|
27
|
+
...payload.range
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
[replacementLayerDelete]: (state, payload) => {
|
|
32
|
+
return omit(state, payload.id);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{}
|
|
36
|
+
);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { combineReducers } from "redux";
|
|
2
|
+
import { createReducer } from "redux-act";
|
|
3
|
+
import createAction from "./utils/createMetaAction";
|
|
4
|
+
import specialCutsiteFilterOptions from "../constants/specialCutsiteFilterOptions";
|
|
5
|
+
// ------------------------------------
|
|
6
|
+
// Actions
|
|
7
|
+
// ------------------------------------
|
|
8
|
+
export const filteredRestrictionEnzymesUpdate = createAction(
|
|
9
|
+
"FILTERED_RESTRICTION_ENZYMES_UPDATE"
|
|
10
|
+
);
|
|
11
|
+
export const isEnzymeFilterAndUpdate = createAction("IS_ENZYME_FILTER_AND");
|
|
12
|
+
export const filteredRestrictionEnzymesReset = createAction(
|
|
13
|
+
"FILTERED_RESTRICTION_ENZYMES_RESET"
|
|
14
|
+
);
|
|
15
|
+
export const filteredRestrictionEnzymesAdd = createAction(
|
|
16
|
+
"FILTERED_RESTRICTION_ENZYMES_ADD"
|
|
17
|
+
);
|
|
18
|
+
// ------------------------------------
|
|
19
|
+
// Reducer
|
|
20
|
+
// ------------------------------------
|
|
21
|
+
const defaultInitialState = [specialCutsiteFilterOptions.single];
|
|
22
|
+
// let initialState = defaultInitialState;
|
|
23
|
+
// const localDefault = window.localStorage.getItem("tgInitialCutsiteFilter");
|
|
24
|
+
|
|
25
|
+
// if (localDefault) {
|
|
26
|
+
// try {
|
|
27
|
+
// initialState = JSON.parse(localDefault);
|
|
28
|
+
// if (!Array.isArray(initialState)) throw new Error("Must be an array");
|
|
29
|
+
// } catch (e) {
|
|
30
|
+
// initialState = defaultInitialState;
|
|
31
|
+
// }
|
|
32
|
+
// }
|
|
33
|
+
|
|
34
|
+
export default combineReducers({
|
|
35
|
+
//filteredRestrictionEnzymes refer to the enzymes actively included in the react-select filter component
|
|
36
|
+
isEnzymeFilterAnd: createReducer(
|
|
37
|
+
{
|
|
38
|
+
[isEnzymeFilterAndUpdate]: (state, payload) => payload
|
|
39
|
+
},
|
|
40
|
+
false
|
|
41
|
+
),
|
|
42
|
+
filteredRestrictionEnzymes: createReducer(
|
|
43
|
+
{
|
|
44
|
+
[filteredRestrictionEnzymesReset]: () => defaultInitialState,
|
|
45
|
+
[filteredRestrictionEnzymesUpdate]: (state, payload) => payload,
|
|
46
|
+
[filteredRestrictionEnzymesAdd]: function (state, payload) {
|
|
47
|
+
return [...state, payload];
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
defaultInitialState
|
|
51
|
+
)
|
|
52
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { forEach } from "lodash-es";
|
|
2
|
+
import { createSelector } from "reselect";
|
|
3
|
+
import {
|
|
4
|
+
defaultEnzymesByName,
|
|
5
|
+
aliasedEnzymesByName
|
|
6
|
+
} from "@teselagen/sequence-utils";
|
|
7
|
+
|
|
8
|
+
export default createSelector(
|
|
9
|
+
() => defaultEnzymesByName,
|
|
10
|
+
(state, additionalEnzymes) => {
|
|
11
|
+
return additionalEnzymes;
|
|
12
|
+
},
|
|
13
|
+
() => localStorage.getItem("enzymeGroups"), //it should recompute if the enzyme groups change in localstorage
|
|
14
|
+
(defaultEnzymesByName, additionalEnzymes) => {
|
|
15
|
+
const enzymesFromGroups = {};
|
|
16
|
+
forEach(window.getExistingEnzymeGroups(), group => {
|
|
17
|
+
forEach(group, enzymeName => {
|
|
18
|
+
const enzyme = { ...aliasedEnzymesByName, ...additionalEnzymes }[
|
|
19
|
+
enzymeName.toLowerCase()
|
|
20
|
+
];
|
|
21
|
+
if (!enzyme) {
|
|
22
|
+
console.warn("ruh roh, no enzyme found for: ", enzymeName);
|
|
23
|
+
} else {
|
|
24
|
+
enzymesFromGroups[enzymeName.toLowerCase()] = enzyme;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
...defaultEnzymesByName,
|
|
30
|
+
...additionalEnzymes,
|
|
31
|
+
...enzymesFromGroups
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
);
|
package/ruler.css
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* .managerListLadder {
|
|
2
|
+
height: 265px;
|
|
3
|
+
overflow: visible;
|
|
4
|
+
border: 1px solid #E0E0E0;
|
|
5
|
+
padding: 0 !important;
|
|
6
|
+
position: fixed;
|
|
7
|
+
width: 225px;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.left {
|
|
11
|
+
border-color: black;
|
|
12
|
+
position: absolute;
|
|
13
|
+
height: 5px;
|
|
14
|
+
width: 80%;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.right {
|
|
18
|
+
border-color: black;
|
|
19
|
+
position: absolute;
|
|
20
|
+
height: 5px;
|
|
21
|
+
width: 80%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.tooltip {
|
|
25
|
+
position: absolute;
|
|
26
|
+
height: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.tooltip .tooltiptext {
|
|
30
|
+
visibility: hidden;
|
|
31
|
+
position: absolute;
|
|
32
|
+
width: auto;
|
|
33
|
+
background-color: black;
|
|
34
|
+
color: white;
|
|
35
|
+
text-align: left;
|
|
36
|
+
padding: 5px;
|
|
37
|
+
font-size: 7pt;
|
|
38
|
+
bottom: 5px;
|
|
39
|
+
white-space: nowrap;
|
|
40
|
+
border-radius: 6px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.tooltip .tooltiptext::after {
|
|
44
|
+
content: " ";
|
|
45
|
+
/* i don't know what this content attribute does, but it works... */
|
|
46
|
+
/* position: absolute;
|
|
47
|
+
top: 100%;
|
|
48
|
+
left: 50%;
|
|
49
|
+
margin-left: -5px;
|
|
50
|
+
border-width: 5px;
|
|
51
|
+
border-style: solid;
|
|
52
|
+
border-color: black transparent transparent transparent;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.tooltip:hover .tooltiptext {
|
|
56
|
+
visibility: visible;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.rightLabel {
|
|
60
|
+
margin-right: 2%;
|
|
61
|
+
margin-left: 60%;
|
|
62
|
+
position: relative;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.leftLabel {
|
|
66
|
+
margin-left: 2%;
|
|
67
|
+
margin-right: 60%;
|
|
68
|
+
position: relative;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.block {
|
|
72
|
+
height: 265px;
|
|
73
|
+
max-height: none;
|
|
74
|
+
padding-bottom: 40px;
|
|
75
|
+
padding-top: 10px;
|
|
76
|
+
overflow: scroll;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.fragmentsNumLabel {
|
|
80
|
+
text-align: left;
|
|
81
|
+
padding: 0 5px;
|
|
82
|
+
color: #333333;
|
|
83
|
+
height: 30px;
|
|
84
|
+
width: 100%;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
*/
|
package/save.png
ADDED
|
Binary file
|
package/saveTool.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Icon } from "@blueprintjs/core";
|
|
3
|
+
import ToolbarItem from "./ToolbarItem";
|
|
4
|
+
import { connectToEditor, handleSave } from "../withEditorProps";
|
|
5
|
+
import { withHandlers } from "recompose";
|
|
6
|
+
import { compose } from "redux";
|
|
7
|
+
|
|
8
|
+
export default compose(
|
|
9
|
+
connectToEditor(
|
|
10
|
+
({ readOnly, sequenceData = {}, lastSavedId = "134%!@#%!@#%!@%" }) => {
|
|
11
|
+
return {
|
|
12
|
+
readOnly: readOnly,
|
|
13
|
+
sequenceData: sequenceData,
|
|
14
|
+
hasBeenSaved:
|
|
15
|
+
sequenceData.stateTrackingId === "initialLoadId" ||
|
|
16
|
+
sequenceData.stateTrackingId === lastSavedId
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
),
|
|
20
|
+
withHandlers({ handleSave })
|
|
21
|
+
)(({
|
|
22
|
+
toolbarItemProps,
|
|
23
|
+
alwaysAllowSave,
|
|
24
|
+
handleSave,
|
|
25
|
+
readOnly,
|
|
26
|
+
hasBeenSaved,
|
|
27
|
+
onSave
|
|
28
|
+
}) => {
|
|
29
|
+
return (
|
|
30
|
+
<ToolbarItem
|
|
31
|
+
{...{
|
|
32
|
+
Icon: <Icon data-test="saveTool" icon="floppy-disk" />,
|
|
33
|
+
onIconClick: handleSave,
|
|
34
|
+
disabled: alwaysAllowSave ? false : !onSave || hasBeenSaved || readOnly,
|
|
35
|
+
tooltip: (
|
|
36
|
+
<span>
|
|
37
|
+
Save <span style={{ fontSize: 10 }}>(Cmd/Ctrl+S)</span>
|
|
38
|
+
</span>
|
|
39
|
+
),
|
|
40
|
+
...toolbarItemProps
|
|
41
|
+
}}
|
|
42
|
+
/>
|
|
43
|
+
);
|
|
44
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { findSequenceMatches } from "@teselagen/sequence-utils";
|
|
2
|
+
import sequenceSelector from "./sequenceSelector";
|
|
3
|
+
import { createSelector } from "reselect";
|
|
4
|
+
import circularSelector from "./circularSelector";
|
|
5
|
+
|
|
6
|
+
function searchLayersSelector(
|
|
7
|
+
sequence,
|
|
8
|
+
isCircular,
|
|
9
|
+
isOpen,
|
|
10
|
+
searchString,
|
|
11
|
+
ambiguousOrLiteral,
|
|
12
|
+
dnaOrAA,
|
|
13
|
+
isProtein,
|
|
14
|
+
proteinSequence
|
|
15
|
+
) {
|
|
16
|
+
if (!searchString || !isOpen) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
if (isProtein) {
|
|
20
|
+
const searchingDna = dnaOrAA === "DNA";
|
|
21
|
+
const matches = findSequenceMatches(
|
|
22
|
+
searchingDna ? sequence : proteinSequence,
|
|
23
|
+
searchString,
|
|
24
|
+
{
|
|
25
|
+
isCircular: false,
|
|
26
|
+
isProteinSequence: true,
|
|
27
|
+
isAmbiguous: ambiguousOrLiteral === "AMBIGUOUS",
|
|
28
|
+
// isProteinSearch: dnaOrAA !== "DNA",
|
|
29
|
+
searchReverseStrand: false
|
|
30
|
+
}
|
|
31
|
+
).sort(({ start }, { start: start2 }) => {
|
|
32
|
+
return start - start2;
|
|
33
|
+
});
|
|
34
|
+
return searchingDna
|
|
35
|
+
? matches
|
|
36
|
+
: matches.map(({ start, end, ...rest }) => ({
|
|
37
|
+
...rest,
|
|
38
|
+
isSearchLayer: true,
|
|
39
|
+
start: start * 3,
|
|
40
|
+
end: end * 3 + 2
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
const matches = findSequenceMatches(sequence, searchString, {
|
|
44
|
+
isCircular,
|
|
45
|
+
isAmbiguous: ambiguousOrLiteral === "AMBIGUOUS",
|
|
46
|
+
isProteinSearch: dnaOrAA !== "DNA",
|
|
47
|
+
searchReverseStrand: true
|
|
48
|
+
}).sort(({ start }, { start: start2 }) => {
|
|
49
|
+
return start - start2;
|
|
50
|
+
});
|
|
51
|
+
return matches.map(match => ({
|
|
52
|
+
...match,
|
|
53
|
+
forward: !match.bottomStrand,
|
|
54
|
+
className:
|
|
55
|
+
"veSearchLayer " +
|
|
56
|
+
(match.bottomStrand ? " veSearchLayerBottomStrand" : ""),
|
|
57
|
+
isSearchLayer: true
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default createSelector(
|
|
62
|
+
sequenceSelector,
|
|
63
|
+
circularSelector,
|
|
64
|
+
state => state.findTool && state.findTool.isOpen,
|
|
65
|
+
state => state.findTool && state.findTool.searchText,
|
|
66
|
+
state => state.findTool && state.findTool.ambiguousOrLiteral,
|
|
67
|
+
state => state.findTool && state.findTool.dnaOrAA,
|
|
68
|
+
state => state.sequenceData.isProtein,
|
|
69
|
+
state => state.sequenceData.proteinSequence,
|
|
70
|
+
searchLayersSelector
|
|
71
|
+
);
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { showContextMenu } from "@teselagen/ui";
|
|
2
|
+
import without from "lodash/without";
|
|
3
|
+
import { createReducer } from "redux-act";
|
|
4
|
+
import createAction from "./utils/createMetaAction";
|
|
5
|
+
|
|
6
|
+
// ------------------------------------
|
|
7
|
+
// Actions
|
|
8
|
+
// ------------------------------------
|
|
9
|
+
export const annotationSelect = createAction("VE_ANNOTATION_SELECT");
|
|
10
|
+
export const updateSelectedAnnotation = createAction(
|
|
11
|
+
"VE_ANNOTATION_UPDATE_SELECTED"
|
|
12
|
+
);
|
|
13
|
+
export const annotationDeselect = createAction("VE_ANNOTATION_DESELECT");
|
|
14
|
+
export const annotationDeselectAll = createAction("VE_ANNOTATION_DESELECT_ALL");
|
|
15
|
+
|
|
16
|
+
export function replacementLayerRightClicked({ event, annotation }, meta) {
|
|
17
|
+
event.preventDefault();
|
|
18
|
+
event.stopPropagation();
|
|
19
|
+
return function (dispatch /* getState */) {
|
|
20
|
+
const items = [
|
|
21
|
+
{
|
|
22
|
+
text: "Remove Edit",
|
|
23
|
+
onClick: function () {
|
|
24
|
+
dispatch({
|
|
25
|
+
type: "REPLACEMENT_LAYER_DELETE",
|
|
26
|
+
meta,
|
|
27
|
+
payload: { ...annotation }
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
showContextMenu(items, undefined, event);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ------------------------------------
|
|
38
|
+
// Reducer
|
|
39
|
+
// ------------------------------------
|
|
40
|
+
const startingState = {
|
|
41
|
+
idMap: {},
|
|
42
|
+
idStack: []
|
|
43
|
+
};
|
|
44
|
+
export default createReducer(
|
|
45
|
+
{
|
|
46
|
+
[annotationSelect]: (state, payload) => {
|
|
47
|
+
if (!payload.id) throw new Error("Annotation must have an id!");
|
|
48
|
+
const newState = {
|
|
49
|
+
idMap: {
|
|
50
|
+
...state.idMap,
|
|
51
|
+
[payload.id]: payload
|
|
52
|
+
},
|
|
53
|
+
idStack: [...state.idStack, payload.id]
|
|
54
|
+
};
|
|
55
|
+
return newState;
|
|
56
|
+
},
|
|
57
|
+
[annotationDeselect]: (state, payload) => {
|
|
58
|
+
const id = payload.id || payload;
|
|
59
|
+
const idMap = { ...state.idMap };
|
|
60
|
+
delete idMap[id];
|
|
61
|
+
const idStack = without(state.idStack, id);
|
|
62
|
+
return {
|
|
63
|
+
idMap,
|
|
64
|
+
idStack
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
[updateSelectedAnnotation]: (state, payload) => {
|
|
68
|
+
const id = payload.id;
|
|
69
|
+
const idMap = { ...state.idMap };
|
|
70
|
+
if (!idMap[id]) {
|
|
71
|
+
return state;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
idMap: {
|
|
75
|
+
...idMap,
|
|
76
|
+
[id]: {
|
|
77
|
+
...idMap[id],
|
|
78
|
+
...payload
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
idStack: state.idStack
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
[annotationDeselectAll]: () => {
|
|
85
|
+
return startingState;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
startingState
|
|
89
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default state => state.selectedAnnotations;
|