@teselagen/ove 0.0.14 → 0.0.16

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.
Files changed (362) hide show
  1. package/index.umd.js +164825 -135871
  2. package/package.json +78 -9
  3. package/src/AlignmentTool/index.js +16 -0
  4. package/src/AlignmentView/AlignmentVisibilityTool.js +105 -0
  5. package/src/AlignmentView/EditTrackNameDialog.js +34 -0
  6. package/src/AlignmentView/HorizontalPanelDragHandle.js +35 -0
  7. package/src/AlignmentView/Minimap.js +520 -0
  8. package/src/AlignmentView/Mismatches.js +134 -0
  9. package/src/AlignmentView/PairwiseAlignmentView.js +68 -0
  10. package/src/AlignmentView/PerformantSelectionLayer.js +32 -0
  11. package/src/AlignmentView/coerceInitialValue.js +7 -0
  12. package/src/AlignmentView/getGapMap.js +12 -0
  13. package/src/AlignmentView/getGaps.js +27 -0
  14. package/src/AlignmentView/getPairwiseOverviewLinearViewOptions.js +38 -0
  15. package/src/AlignmentView/getTrackFromEvent.js +25 -0
  16. package/src/AlignmentView/index.js +2058 -0
  17. package/src/AlignmentView/isTargetWithinEl.js +6 -0
  18. package/src/AlignmentView/style.css +100 -0
  19. package/src/AlignmentView/updateTrackHelper.js +58 -0
  20. package/src/AutoAnnotate.js +500 -0
  21. package/src/AutoAnnotateBpMatchingDialog.js +208 -0
  22. package/src/CircularView/Axis.js +40 -0
  23. package/src/CircularView/AxisNumbers.js +35 -0
  24. package/src/CircularView/Caret.js +63 -0
  25. package/src/CircularView/CircularDnaSequence.js +73 -0
  26. package/src/CircularView/CircularZoomMinimap.js +16 -0
  27. package/src/CircularView/Cutsite.js +18 -0
  28. package/src/CircularView/Cutsites.js +113 -0
  29. package/src/CircularView/DeletionLayer.js +28 -0
  30. package/src/CircularView/Feature.js +83 -0
  31. package/src/CircularView/Labels/index.js +536 -0
  32. package/src/CircularView/Labels/relaxLabelAngles.js +157 -0
  33. package/src/CircularView/Labels/relaxLabels_DEPRECATED.js +105 -0
  34. package/src/CircularView/Labels/style.css +55 -0
  35. package/src/CircularView/Orf.js +25 -0
  36. package/src/CircularView/Part.js +34 -0
  37. package/src/CircularView/PositionAnnotationOnCircle.js +26 -0
  38. package/src/CircularView/Primer.js +41 -0
  39. package/src/CircularView/RotateCircularViewSlider.js +82 -0
  40. package/src/CircularView/SelectionLayer.js +132 -0
  41. package/src/CircularView/VeTopRightContainer.js +12 -0
  42. package/src/CircularView/ZoomCircularViewSlider.js +62 -0
  43. package/src/CircularView/drawAnnotations.js +433 -0
  44. package/src/CircularView/drawDirectedPiePiece.js +142 -0
  45. package/src/CircularView/getAngleForPositionMidpoint.js +3 -0
  46. package/src/CircularView/getInternalLabel.js +40 -0
  47. package/src/CircularView/getRangeAnglesSpecial.js +12 -0
  48. package/src/CircularView/getYOffset.js +15 -0
  49. package/src/CircularView/index.d.ts +20 -0
  50. package/src/CircularView/index.js +930 -0
  51. package/src/CircularView/normalizeAngle.js +3 -0
  52. package/src/CircularView/normalizeAngleRange.js +9 -0
  53. package/src/CircularView/positionCutsites.js +6 -0
  54. package/src/CircularView/shouldFlipText.js +4 -0
  55. package/src/CircularView/style.css +47 -0
  56. package/src/CircularView/utils/polarToSpecialCartesian.js +7 -0
  57. package/src/CreateAnnotationsPage.js +96 -0
  58. package/src/CreateCustomEnzyme/index.js +337 -0
  59. package/src/CreateCustomEnzyme/style.css +100 -0
  60. package/src/CutsiteFilter/AdditionalCutsiteInfoDialog.js +599 -0
  61. package/src/CutsiteFilter/index.js +408 -0
  62. package/src/CutsiteFilter/style.css +23 -0
  63. package/src/CutsiteFilter/withRestrictionEnzymes.js +15 -0
  64. package/src/DigestTool/AddLaddersDialog.js +82 -0
  65. package/src/DigestTool/DigestTool.js +223 -0
  66. package/src/DigestTool/Ladder.css +20 -0
  67. package/src/DigestTool/Ladder.js +303 -0
  68. package/src/DigestTool/createFragmentLines.js +120 -0
  69. package/src/DigestTool/ladderDefaults.js +26 -0
  70. package/src/DigestTool/ruler.css +89 -0
  71. package/src/Editor/CommandHotkeyHandler.js +44 -0
  72. package/src/Editor/DropHandler.css +21 -0
  73. package/src/Editor/DropHandler.js +64 -0
  74. package/src/Editor/FillWindow.js +46 -0
  75. package/src/Editor/darkmode.css +98 -0
  76. package/src/Editor/index.js +1005 -0
  77. package/src/Editor/style.css +235 -0
  78. package/src/Editor/userDefinedHandlersAndOpts.js +56 -0
  79. package/src/EnzymeViewer/index.js +81 -0
  80. package/src/EnzymeViewer/style.css +6 -0
  81. package/src/FindBar/index.js +411 -0
  82. package/src/FindBar/style.css +46 -0
  83. package/src/GlobalDialog.js +66 -0
  84. package/src/GlobalDialogUtils.js +85 -0
  85. package/src/LinearView/SequenceName.js +15 -0
  86. package/src/LinearView/ZoomLinearView.js +47 -0
  87. package/src/LinearView/index.js +374 -0
  88. package/src/LinearView/style.css +12 -0
  89. package/src/ManageEnzymes/index.js +326 -0
  90. package/src/ManageEnzymes/style.css +100 -0
  91. package/src/MenuBar/defaultConfig.js +149 -0
  92. package/src/MenuBar/index.js +98 -0
  93. package/src/MenuBar/viewSubmenu.js +479 -0
  94. package/src/PCRTool/PCRTool.js +173 -0
  95. package/src/Reflex/Browser.js +107 -0
  96. package/src/Reflex/ReflexContainer.js +802 -0
  97. package/src/Reflex/ReflexElement.js +160 -0
  98. package/src/Reflex/ReflexEvents.js +77 -0
  99. package/src/Reflex/ReflexSplitter.js +205 -0
  100. package/src/Reflex/index.js +5 -0
  101. package/src/Reflex/reflex-styles.css +128 -0
  102. package/src/Reflex/reflex-styles.css.map +9 -0
  103. package/src/RowItem/AnnotationContainerHolder.js +20 -0
  104. package/src/RowItem/AnnotationPositioner.js +27 -0
  105. package/src/RowItem/Axis.js +149 -0
  106. package/src/RowItem/Caret/index.js +64 -0
  107. package/src/RowItem/Caret/style.css +8 -0
  108. package/src/RowItem/Chromatograms/Chromatogram.js +289 -0
  109. package/src/RowItem/CutsiteSelectionLayers.js +47 -0
  110. package/src/RowItem/Cutsites.js +271 -0
  111. package/src/RowItem/DeletionLayers/index.js +113 -0
  112. package/src/RowItem/DeletionLayers/style.css +5 -0
  113. package/src/RowItem/Labels.js +327 -0
  114. package/src/RowItem/Orf.js +109 -0
  115. package/src/RowItem/Orfs.js +35 -0
  116. package/src/RowItem/ReplacementLayers/style.css +5 -0
  117. package/src/RowItem/SelectionLayer/index.js +184 -0
  118. package/src/RowItem/SelectionLayer/style.css +21 -0
  119. package/src/RowItem/Sequence.js +269 -0
  120. package/src/RowItem/StackedAnnotations/PointedAnnotation.js +347 -0
  121. package/src/RowItem/StackedAnnotations/getStructuredBases.js +97 -0
  122. package/src/RowItem/StackedAnnotations/index.js +182 -0
  123. package/src/RowItem/StackedAnnotations/primerBases.js +218 -0
  124. package/src/RowItem/StackedAnnotations/style.css +14 -0
  125. package/src/RowItem/Translations/AASliver.js +190 -0
  126. package/src/RowItem/Translations/Translation.js +162 -0
  127. package/src/RowItem/Translations/index.js +54 -0
  128. package/src/RowItem/Translations/style.css +3 -0
  129. package/src/RowItem/constants.js +3 -0
  130. package/src/RowItem/getCutsiteLabelHeights.js +56 -0
  131. package/src/RowItem/getXStartAndWidthFromNonCircularRange.js +12 -0
  132. package/src/RowItem/getXStartAndWidthOfRangeWrtRow.js +27 -0
  133. package/src/RowItem/getXStartAndWidthOfRowAnnotation.js +19 -0
  134. package/src/RowItem/index.js +647 -0
  135. package/src/RowItem/partOverhangs.js +6 -0
  136. package/src/RowItem/style.css +103 -0
  137. package/src/RowItem/utils.js +32 -0
  138. package/src/RowView/estimateRowHeight.js +184 -0
  139. package/src/RowView/index.d.ts +10 -0
  140. package/src/RowView/index.js +554 -0
  141. package/src/RowView/style.css +12 -0
  142. package/src/SimpleCircularOrLinearView.js +379 -0
  143. package/src/SimpleOligoPreview.js +39 -0
  144. package/src/StatusBar/MeltingTemp.js +81 -0
  145. package/src/StatusBar/index.js +275 -0
  146. package/src/StatusBar/style.css +38 -0
  147. package/src/ToolBar/ToolbarItem.js +194 -0
  148. package/src/ToolBar/alignmentTool.js +503 -0
  149. package/src/ToolBar/array_move.js +10 -0
  150. package/src/ToolBar/cutsiteTool.js +88 -0
  151. package/src/ToolBar/downloadTool.js +38 -0
  152. package/src/ToolBar/editTool.js +26 -0
  153. package/src/ToolBar/featureTool.js +34 -0
  154. package/src/ToolBar/findTool.js +2 -0
  155. package/src/ToolBar/importTool.js +27 -0
  156. package/src/ToolBar/index.js +231 -0
  157. package/src/ToolBar/inlineFindTool.js +38 -0
  158. package/src/ToolBar/oligoTool.js +30 -0
  159. package/src/ToolBar/orfTool.js +141 -0
  160. package/src/ToolBar/partTool.js +47 -0
  161. package/src/ToolBar/printTool.js +31 -0
  162. package/src/ToolBar/redoTool.js +30 -0
  163. package/src/ToolBar/saveTool.js +48 -0
  164. package/src/ToolBar/style.css +138 -0
  165. package/src/ToolBar/undoTool.js +30 -0
  166. package/src/ToolBar/veToolbarIcons/find.png +0 -0
  167. package/src/ToolBar/veToolbarIcons/fullscreen.png +0 -0
  168. package/src/ToolBar/veToolbarIcons/linear.png +0 -0
  169. package/src/ToolBar/veToolbarIcons/pie.png +0 -0
  170. package/src/ToolBar/veToolbarIcons/print.png +0 -0
  171. package/src/ToolBar/veToolbarIcons/save.png +0 -0
  172. package/src/ToolBar/veToolbarIcons/show_cut_sites.png +0 -0
  173. package/src/ToolBar/veToolbarIcons/show_features.png +0 -0
  174. package/src/ToolBar/veToolbarIcons/show_orfs.png +0 -0
  175. package/src/ToolBar/veToolbarIcons/show_primers.png +0 -0
  176. package/src/ToolBar/veToolbarIcons/toggle_views.svg +1 -0
  177. package/src/ToolBar/versionHistoryTool.js +20 -0
  178. package/src/ToolBar/visibilityTool.js +39 -0
  179. package/src/VersionHistoryView/index.js +215 -0
  180. package/src/addAlignment.js +6 -0
  181. package/src/commands/getOveHotkeyDefs.js +12 -0
  182. package/src/commands/index.js +1585 -0
  183. package/src/constants/constants.js +2 -0
  184. package/src/constants/dnaToColor.js +17 -0
  185. package/src/constants/draggableClassnames.js +5 -0
  186. package/src/constants/findToolConstants.js +1 -0
  187. package/src/constants/orfFrameToColorMap.js +10 -0
  188. package/src/constants/rowviewContants.js +3 -0
  189. package/src/constants/specialCutsiteFilterOptions.js +22 -0
  190. package/src/constants.js +1 -0
  191. package/src/createVectorEditor/index.js +138 -0
  192. package/src/createVectorEditor/makeStore.js +34 -0
  193. package/src/fileUtils.js +103 -0
  194. package/src/helperComponents/AddOrEditAnnotationDialog/index.js +711 -0
  195. package/src/helperComponents/AddOrEditAnnotationDialog/style.css +11 -0
  196. package/src/helperComponents/AddOrEditFeatureDialog/index.js +58 -0
  197. package/src/helperComponents/AddOrEditPartDialog/index.js +101 -0
  198. package/src/helperComponents/AddOrEditPrimerDialog/EditCaretPosition.js +234 -0
  199. package/src/helperComponents/AddOrEditPrimerDialog/index.js +329 -0
  200. package/src/helperComponents/AddOrEditPrimerDialog/style.css +41 -0
  201. package/src/helperComponents/EnzymesDialog/index.js +904 -0
  202. package/src/helperComponents/EnzymesDialog/style.css +21 -0
  203. package/src/helperComponents/GoToDialog.js +21 -0
  204. package/src/helperComponents/MergeFeaturesDialog/index.js +253 -0
  205. package/src/helperComponents/MergeFeaturesDialog/style.css +3 -0
  206. package/src/helperComponents/MultipleSeqsDetectedOnImportDialog.js +74 -0
  207. package/src/helperComponents/PinchHelper/PinchHelper.js +24 -0
  208. package/src/helperComponents/PrintDialog/index.js +396 -0
  209. package/src/helperComponents/PrintDialog/style.css +4 -0
  210. package/src/helperComponents/PropertiesDialog/ColorPicker.js +30 -0
  211. package/src/helperComponents/PropertiesDialog/CutsiteProperties.js +185 -0
  212. package/src/helperComponents/PropertiesDialog/FeatureProperties.js +6 -0
  213. package/src/helperComponents/PropertiesDialog/GenbankView.js +74 -0
  214. package/src/helperComponents/PropertiesDialog/GeneralProperties.js +140 -0
  215. package/src/helperComponents/PropertiesDialog/GenericAnnotationProperties.js +406 -0
  216. package/src/helperComponents/PropertiesDialog/OrfProperties.js +117 -0
  217. package/src/helperComponents/PropertiesDialog/PartProperties.js +9 -0
  218. package/src/helperComponents/PropertiesDialog/PrimerProperties.js +19 -0
  219. package/src/helperComponents/PropertiesDialog/SingleEnzymeCutsiteInfo.js +131 -0
  220. package/src/helperComponents/PropertiesDialog/TranslationProperties.js +149 -0
  221. package/src/helperComponents/PropertiesDialog/index.js +166 -0
  222. package/src/helperComponents/PropertiesDialog/style.css +68 -0
  223. package/src/helperComponents/PropertiesDialog/typeField.js +24 -0
  224. package/src/helperComponents/PropertiesDialog/utils.js +37 -0
  225. package/src/helperComponents/RemoveDuplicates/index.js +194 -0
  226. package/src/helperComponents/RenameSequenceDialog.js +7 -0
  227. package/src/helperComponents/SelectDialog.js +150 -0
  228. package/src/helperComponents/UncontrolledSliderWithPlusMinusBtns.css +5 -0
  229. package/src/helperComponents/UncontrolledSliderWithPlusMinusBtns.js +134 -0
  230. package/src/helperComponents/VeWarning/index.js +22 -0
  231. package/src/helperComponents/VeWarning/style.css +10 -0
  232. package/src/helperComponents/createSimpleDialog.js +89 -0
  233. package/src/helperComponents/partTagSearch.js +72 -0
  234. package/src/helperComponents/simpleDialog.css +13 -0
  235. package/src/helperComponents/withHover.js +90 -0
  236. package/src/index.js +60 -0
  237. package/src/redux/alignments.js +373 -0
  238. package/src/redux/annotationLabelVisibility.js +53 -0
  239. package/src/redux/annotationVisibility.js +196 -0
  240. package/src/redux/annotationsToSupport.js +104 -0
  241. package/src/redux/caretPosition.js +27 -0
  242. package/src/redux/charWidth.js +22 -0
  243. package/src/redux/copyOptions.js +34 -0
  244. package/src/redux/createYourOwnEnzyme.js +39 -0
  245. package/src/redux/deletionLayers.js +36 -0
  246. package/src/redux/digestTool.js +34 -0
  247. package/src/redux/featureLengthsToHide.js +27 -0
  248. package/src/redux/findTool.js +79 -0
  249. package/src/redux/frameTranslations.js +52 -0
  250. package/src/redux/hoveredAnnotation.js +24 -0
  251. package/src/redux/index.js +196 -0
  252. package/src/redux/labelLineIntensity.js +25 -0
  253. package/src/redux/labelSize.js +23 -0
  254. package/src/redux/lastSavedId.js +20 -0
  255. package/src/redux/middleware.js +112 -0
  256. package/src/redux/minimumOrfSize.js +24 -0
  257. package/src/redux/modalActions.js +3 -0
  258. package/src/redux/panelsShown.js +273 -0
  259. package/src/redux/partLengthsToHide.js +23 -0
  260. package/src/redux/primerLengthsToHide.js +27 -0
  261. package/src/redux/propertiesTool.js +40 -0
  262. package/src/redux/readOnly.js +28 -0
  263. package/src/redux/replacementLayers.js +36 -0
  264. package/src/redux/restrictionEnzymes.js +52 -0
  265. package/src/redux/selectedAnnotations.js +89 -0
  266. package/src/redux/selectedPartTags.js +21 -0
  267. package/src/redux/selectionLayer.js +46 -0
  268. package/src/redux/sequenceData/circular.js +19 -0
  269. package/src/redux/sequenceData/description.js +21 -0
  270. package/src/redux/sequenceData/features.js +19 -0
  271. package/src/redux/sequenceData/index.js +81 -0
  272. package/src/redux/sequenceData/lineageLines.js +11 -0
  273. package/src/redux/sequenceData/materiallyAvailable.js +19 -0
  274. package/src/redux/sequenceData/name.js +19 -0
  275. package/src/redux/sequenceData/parts.js +19 -0
  276. package/src/redux/sequenceData/primers.js +19 -0
  277. package/src/redux/sequenceData/sequence.js +12 -0
  278. package/src/redux/sequenceData/sharedActionCreators.js +0 -0
  279. package/src/redux/sequenceData/translations.js +20 -0
  280. package/src/redux/sequenceData/upsertDeleteActionGenerator.js +31 -0
  281. package/src/redux/sequenceDataHistory.js +43 -0
  282. package/src/redux/showGCContent.js +23 -0
  283. package/src/redux/toolBar.js +25 -0
  284. package/src/redux/uppercaseSequenceMapFont.js +25 -0
  285. package/src/redux/useAdditionalOrfStartCodons.js +24 -0
  286. package/src/redux/utils/addDashesForMatchStartAndEndForTracks/index.js +71 -0
  287. package/src/redux/utils/addMetaToActionCreators.js +12 -0
  288. package/src/redux/utils/createMergedDefaultStateReducer.js +30 -0
  289. package/src/redux/utils/createMetaAction.js +12 -0
  290. package/src/redux/versionHistory.js +27 -0
  291. package/src/selectors/annotationLabelVisibility.js +2 -0
  292. package/src/selectors/annotationSearchSelector.js +24 -0
  293. package/src/selectors/cdsFeaturesSelector.js +9 -0
  294. package/src/selectors/circularSelector.js +4 -0
  295. package/src/selectors/cutsiteLabelColorSelector.js +6 -0
  296. package/src/selectors/cutsitesByRangeSelector.js +5 -0
  297. package/src/selectors/cutsitesSelector.js +61 -0
  298. package/src/selectors/editorSelector.js +2 -0
  299. package/src/selectors/featuresSelector.js +8 -0
  300. package/src/selectors/filteredCutsitesSelector.js +137 -0
  301. package/src/selectors/filteredFeaturesSelector.js +32 -0
  302. package/src/selectors/filteredPartsSelector.js +57 -0
  303. package/src/selectors/filteredPrimersSelector.js +27 -0
  304. package/src/selectors/filteredRestrictionEnzymesSelector.js +1 -0
  305. package/src/selectors/getAdditionalEnzymesSelector.js +46 -0
  306. package/src/selectors/index.js +41 -0
  307. package/src/selectors/isEnzymeFilterAndSelector.js +1 -0
  308. package/src/selectors/minimumOrfSizeSelector.js +2 -0
  309. package/src/selectors/orfsSelector.js +15 -0
  310. package/src/selectors/partsSelector.js +8 -0
  311. package/src/selectors/primersSelector.js +8 -0
  312. package/src/selectors/restrictionEnzymesSelector.js +34 -0
  313. package/src/selectors/searchLayersSelector.js +71 -0
  314. package/src/selectors/selectedAnnotationsSelector.js +1 -0
  315. package/src/selectors/selectedCutsitesSelector.js +21 -0
  316. package/src/selectors/sequenceDataSelector.js +2 -0
  317. package/src/selectors/sequenceLengthSelector.js +5 -0
  318. package/src/selectors/sequenceSelector.js +4 -0
  319. package/src/selectors/tagsToBoldSelector.js +2 -0
  320. package/src/selectors/translationSearchMatchesSelector.js +14 -0
  321. package/src/selectors/translationsRawSelector.js +8 -0
  322. package/src/selectors/translationsSelector.js +137 -0
  323. package/src/style.css +82 -0
  324. package/src/updateEditor.js +198 -0
  325. package/src/utils/PassThrough.js +3 -0
  326. package/src/utils/addWrappedAddons.js +20 -0
  327. package/src/utils/annotationTypes.js +37 -0
  328. package/src/utils/arrayUtils.js +19 -0
  329. package/src/utils/calculateTickMarkPositionsForGivenRange.js +47 -0
  330. package/src/utils/cleanSequenceData_DEPRECATED/arrayToObjWithIds.js +17 -0
  331. package/src/utils/combineReducersDontIgnoreKeys.js +12 -0
  332. package/src/utils/commandUtils.js +18 -0
  333. package/src/utils/editorUtils.js +223 -0
  334. package/src/utils/getAnnotationClassnames.js +12 -0
  335. package/src/utils/getAnnotationNameAndStartStopString.js +61 -0
  336. package/src/utils/getVisibleStartEnd.js +7 -0
  337. package/src/utils/massageTickSpacing.js +19 -0
  338. package/src/utils/onlyUpdateForKeysDeep.js +31 -0
  339. package/src/utils/prepareRowData.js +64 -0
  340. package/src/utils/proteinUtils.js +3 -0
  341. package/src/utils/pureNoFunc.js +18 -0
  342. package/src/utils/selectionLayer.js +25 -0
  343. package/src/utils/shouldRerender.js +27 -0
  344. package/src/utils/showFileDialog.js +26 -0
  345. package/src/utils/updateLabelsForInViewFeatures.js +55 -0
  346. package/src/utils/updateLabelsForInViewFeaturesCircView.js +41 -0
  347. package/src/utils/useAAColorType.js +8 -0
  348. package/src/utils/useAnnotationLimits.js +42 -0
  349. package/src/utils/useChromatogramPrefs.js +31 -0
  350. package/src/utils/useLadders.js +6 -0
  351. package/src/utils/useMeltingTemp.js +7 -0
  352. package/src/utils/useTmType.js +10 -0
  353. package/src/withEditorInteractions/Keyboard.js +86 -0
  354. package/src/withEditorInteractions/clickAndDragUtils.js +576 -0
  355. package/src/withEditorInteractions/createSequenceInputPopup.js +296 -0
  356. package/src/withEditorInteractions/createSequenceInputPopupStyle.css +85 -0
  357. package/src/withEditorInteractions/getBpsPerRow.js +19 -0
  358. package/src/withEditorInteractions/index.js +1252 -0
  359. package/src/withEditorInteractions/isElementInViewport.js +29 -0
  360. package/src/withEditorInteractions/moveCaret.js +58 -0
  361. package/src/withEditorProps/index.js +1010 -0
  362. package/index.mjs +0 -193228
@@ -0,0 +1,930 @@
1
+ import { ZoomCircularViewSlider } from "./ZoomCircularViewSlider";
2
+ import VeWarning from "../helperComponents/VeWarning";
3
+ import Labels from "./Labels";
4
+ import SelectionLayer from "./SelectionLayer";
5
+ import Caret from "./Caret";
6
+ import Axis from "./Axis";
7
+ import Orf from "./Orf";
8
+ import Feature from "./Feature";
9
+ import Primer from "./Primer";
10
+ import Cutsite from "./Cutsite";
11
+ import sortBy from "lodash/sortBy";
12
+ import {
13
+ normalizePositionByRangeLength,
14
+ getPositionFromAngle,
15
+ getRangeLength,
16
+ getOverlapsOfPotentiallyCircularRanges,
17
+ isRangeOrPositionWithinRange,
18
+ getMiddleOfRange,
19
+ getSequenceWithinRange,
20
+ trimRangeByAnotherRange
21
+ } from "@teselagen/range-utils";
22
+ import React, { useEffect, useRef, useState } from "react";
23
+ import Draggable from "react-draggable";
24
+ import withEditorInteractions from "../withEditorInteractions";
25
+ import drawAnnotations from "./drawAnnotations";
26
+ import "./style.css";
27
+ import draggableClassnames from "../constants/draggableClassnames";
28
+ import { getOrfColor } from "../constants/orfFrameToColorMap";
29
+ import { getSingular } from "../utils/annotationTypes";
30
+ import { upperFirst, map, flatMap, noop } from "lodash";
31
+
32
+ import useAnnotationLimits from "../utils/useAnnotationLimits";
33
+ import {
34
+ getClientX,
35
+ getClientY,
36
+ getParedDownWarning,
37
+ pareDownAnnotations
38
+ } from "../utils/editorUtils";
39
+ import { getAllSelectionLayers } from "../utils/selectionLayer";
40
+ import classNames from "classnames";
41
+ import calculateTickMarkPositionsForGivenRange from "../utils/calculateTickMarkPositionsForGivenRange";
42
+ import { RotateCircularViewSlider } from "./RotateCircularViewSlider";
43
+ import { AxisNumbers } from "./AxisNumbers";
44
+ import { positionCutsites } from "./positionCutsites";
45
+ import { usePinch } from "@use-gesture/react";
46
+ import { CircularZoomMinimap } from "./CircularZoomMinimap";
47
+ import { normalizeAngleRange } from "./normalizeAngleRange";
48
+ import { CircularDnaSequence } from "./CircularDnaSequence";
49
+ import { VeTopRightContainer } from "./VeTopRightContainer";
50
+ import { normalizeAngle } from "./normalizeAngle";
51
+ import {
52
+ editorDragged,
53
+ editorDragStarted,
54
+ editorDragStopped
55
+ } from "../withEditorInteractions/clickAndDragUtils";
56
+ // import { updateLabelsForInViewFeaturesCircView } from "../utils/updateLabelsForInViewFeaturesCircView";
57
+
58
+ const BASE_RADIUS = 70;
59
+
60
+ function getNearestCursorPositionToMouseEvent(
61
+ event,
62
+ {
63
+ updateSelectionOrCaret,
64
+ caretPosition,
65
+ selectionLayer,
66
+ caretPositionUpdate,
67
+ selectionLayerUpdate,
68
+ sequenceData,
69
+ sequenceLength,
70
+ circRef,
71
+ rotationRadians
72
+ },
73
+ callback
74
+ ) {
75
+ const clientX = getClientX(event);
76
+ const clientY = getClientY(event);
77
+ if (!clientX) {
78
+ return;
79
+ }
80
+ const boundingRect = circRef.current.getBoundingClientRect();
81
+ //get relative click positions
82
+ const clickX = clientX - boundingRect.left - boundingRect.width / 2;
83
+ const clickY = clientY - boundingRect.top - boundingRect.height / 2;
84
+
85
+ //get angle
86
+ let angle = Math.atan2(clickY, clickX) + Math.PI / 2 - rotationRadians;
87
+ if (angle < 0) angle += Math.PI * 2; //normalize the angle if necessary
88
+ let nearestCaretPos =
89
+ sequenceLength === 0
90
+ ? 0
91
+ : normalizePositionByRangeLength(
92
+ getPositionFromAngle(angle, sequenceLength, true),
93
+ sequenceLength
94
+ ); //true because we're in between positions
95
+ if (sequenceData && sequenceData.isProtein) {
96
+ nearestCaretPos = Math.round(nearestCaretPos / 3) * 3;
97
+ }
98
+
99
+ callback({
100
+ updateSelectionOrCaret,
101
+ caretPosition,
102
+ selectionLayer,
103
+ caretPositionUpdate,
104
+ selectionLayerUpdate,
105
+ sequenceLength,
106
+ event,
107
+ doNotWrapOrigin: !(sequenceData && sequenceData.circular),
108
+ className: event.target.parentNode.className.animVal,
109
+ shiftHeld: event.shiftKey,
110
+ nearestCaretPos,
111
+ selectionStartGrabbed: event.target.parentNode.classList.contains(
112
+ draggableClassnames.selectionStart
113
+ ),
114
+ selectionEndGrabbed: event.target.parentNode.classList.contains(
115
+ draggableClassnames.selectionEnd
116
+ )
117
+ });
118
+ }
119
+
120
+ export function CircularView(props) {
121
+ const [limits] = useAnnotationLimits();
122
+ let [rotationRadians, setRotationRadians] = useState(0);
123
+ let [_zoomLevel, setZoomLevel] = useState(1);
124
+
125
+ if (props.circ_zoomLevel !== undefined) {
126
+ //override from the editor to not lose the state when the Circular View component isn't rendered
127
+ rotationRadians = props.circ_rotationRadians;
128
+ setRotationRadians = props.circ_setRotationRadians;
129
+ _zoomLevel = props.circ_zoomLevel;
130
+ setZoomLevel = props.circ_setZoomLevel;
131
+ }
132
+ const { sequenceData = {}, smallSlider } = props;
133
+ const { sequence = "atgc", circular } = sequenceData;
134
+
135
+ const sequenceLength = sequenceData.noSequence
136
+ ? sequenceData.size
137
+ : sequenceData.sequence.length;
138
+
139
+ const hasZoomableLength = sequenceLength >= 50;
140
+ const hasRotateableLength = sequenceLength >= 10;
141
+ if (!hasZoomableLength) _zoomLevel = 1;
142
+ if (!hasRotateableLength) rotationRadians = 0;
143
+ const circRef = useRef();
144
+ const rotateHelper = useRef({});
145
+ const zoomHelper = useRef({});
146
+ useEffect(() => {
147
+ rotateHelper.current.triggerChange &&
148
+ rotateHelper.current.triggerChange(({ changeValue }) => {
149
+ changeValue(
150
+ (normalizeAngle(Math.PI * 2 - rotationRadians) / Math.PI) * 180
151
+ );
152
+ });
153
+ // eslint-disable-next-line react-hooks/exhaustive-deps
154
+ }, []);
155
+ let zoomLevel = _zoomLevel;
156
+
157
+ let smallZoom = 1;
158
+ if (_zoomLevel < 1) {
159
+ smallZoom = _zoomLevel;
160
+ zoomLevel = 1;
161
+ }
162
+
163
+ const {
164
+ //set defaults for all of these vars
165
+ width = 400,
166
+ height = 400,
167
+ noRedux,
168
+ readOnly,
169
+ hideName = false,
170
+ editorName,
171
+ smartCircViewLabelRender,
172
+ showCicularViewInternalLabels,
173
+ withRotateCircularView: _withRotateCircularView,
174
+ withZoomCircularView,
175
+ selectionLayer = { start: -1, end: -1 },
176
+ annotationHeight = 15,
177
+ spaceBetweenAnnotations = 2,
178
+ annotationVisibility = {},
179
+ annotationLabelVisibility = {},
180
+ caretPosition = -1,
181
+ editorClicked = noop,
182
+ backgroundRightClicked = noop,
183
+ searchLayers = [],
184
+ additionalSelectionLayers = [],
185
+ maxAnnotationsToDisplay,
186
+ searchLayerRightClicked = noop,
187
+ selectionLayerRightClicked = noop,
188
+ searchLayerClicked = noop,
189
+ instantiated,
190
+ noWarnings,
191
+ labelLineIntensity,
192
+ fontHeightMultiplier,
193
+ hoveredId,
194
+ labelSize,
195
+ nameFontSizeCircularView = 14,
196
+ fullScreen
197
+ } = props;
198
+ const withRotateCircularView =
199
+ _withRotateCircularView || withZoomCircularView; //if we're showing zoom then we MUST show rotation as well
200
+
201
+ const sequenceName = hideName ? "" : sequenceData.name || "";
202
+ let annotationsSvgs = [];
203
+ let labels = {};
204
+
205
+ const { isProtein } = sequenceData;
206
+ const maxZoomLevel = Math.max(5, Math.floor(sequenceLength / 100));
207
+
208
+ const svgWidth = Math.max(Number(width) || 300);
209
+ const svgHeight = Math.max(Number(height) || 300);
210
+ const percentOfCircle = ((1 / zoomLevel) * Math.min(svgWidth, 800)) / 800;
211
+ const isZoomedIn = zoomLevel !== 1;
212
+ let radius = BASE_RADIUS;
213
+ const rotation = 2 * Math.PI - rotationRadians; //get radians
214
+
215
+ let rangeToShowLength = sequenceLength;
216
+ let rangeToShow = { start: 0, end: Math.max(sequenceLength - 1, 0) };
217
+ let visibleAngleRange;
218
+ if (isZoomedIn) {
219
+ const visibleAngle = Math.PI * percentOfCircle;
220
+ radius = Math.max(BASE_RADIUS, svgWidth / Math.sin(visibleAngle / 2) / 2);
221
+
222
+ visibleAngleRange = normalizeAngleRange({
223
+ start: rotation - visibleAngle / 2,
224
+ end: rotation + visibleAngle / 2
225
+ });
226
+ const rangeToShowStart = getPositionFromAngle(
227
+ visibleAngleRange.start,
228
+ sequenceLength
229
+ );
230
+ const rangeToShowEnd = getPositionFromAngle(
231
+ visibleAngleRange.end,
232
+ sequenceLength
233
+ );
234
+ rangeToShow = {
235
+ start: normalizePositionByRangeLength(rangeToShowStart, sequenceLength),
236
+ end: normalizePositionByRangeLength(rangeToShowEnd, sequenceLength)
237
+ };
238
+
239
+ rangeToShowLength = getRangeLength(rangeToShow, sequenceLength);
240
+ }
241
+ const innerRadius = radius - 10;
242
+ const initialRadius = radius;
243
+ const showSeq = isZoomedIn && rangeToShowLength < 140;
244
+ const showSeqText = rangeToShowLength < 80;
245
+
246
+ //RENDERING CONCEPTS:
247
+ //-"Circular" annotations get a radius, and a curvature based on their radius:
248
+ //<CircularFeature>
249
+ //-Then we rotate the annotations as necessary (and optionally flip them):
250
+ //<PositionAnnotationOnCircle>
251
+
252
+ const layersToDraw = [
253
+ { zIndex: 10, layerName: "sequenceChars" },
254
+ {
255
+ zIndex: 20,
256
+ layerName: "features",
257
+ isAnnotation: true,
258
+ // spaceBefore: 10,
259
+ spaceAfter: 5
260
+ },
261
+
262
+ ...(annotationVisibility.axis
263
+ ? [
264
+ {
265
+ layerName: "axisNumbers",
266
+ annotationType: "axisNumbers",
267
+ Annotation: AxisNumbers,
268
+ isAnnotation: true,
269
+ noTitle: true,
270
+ noHover: true,
271
+ annotations: calculateTickMarkPositionsForGivenRange({
272
+ increaseOffset: true,
273
+ range: rangeToShow,
274
+ tickSpacing:
275
+ rangeToShowLength < 10
276
+ ? 2
277
+ : rangeToShowLength < 50
278
+ ? Math.ceil(rangeToShowLength / 25) * 5
279
+ : Math.ceil(rangeToShowLength / 100) * 10,
280
+ sequenceLength,
281
+ isProtein
282
+ }).map((pos) => {
283
+ return {
284
+ name: "Tick Mark",
285
+ tickPosition: pos,
286
+ start: pos,
287
+ end: pos
288
+ };
289
+ }),
290
+ annotationProps: {
291
+ hideTicks: !annotationVisibility.axis,
292
+ hideNumbers: !annotationVisibility.axisNumbers
293
+ },
294
+ useCenter: true,
295
+
296
+ passAnnotation: true,
297
+ allOnSameLevel: true,
298
+ addHeight: true,
299
+ alwaysShow: true,
300
+ showLabels: false,
301
+ spaceBefore: 0,
302
+ spaceAfter: 0
303
+ },
304
+ {
305
+ zIndex: 0,
306
+ layerName: "axis",
307
+ Annotation: Axis,
308
+ spaceBefore: 10,
309
+ spaceAfter: 5
310
+ }
311
+ ]
312
+ : []),
313
+ {
314
+ zIndex: 10,
315
+ layerName: "cutsites",
316
+ fontStyle: "italic",
317
+ Annotation: Cutsite,
318
+ hideAnnotation: showSeqText,
319
+ useStartAngle: true,
320
+ allOnSameLevel: true,
321
+ noHeight: true,
322
+ addHeight: false,
323
+ positionBy: positionCutsites,
324
+ isAnnotation: true
325
+ },
326
+ ...(showSeq && annotationVisibility.sequence
327
+ ? [
328
+ {
329
+ layerName: "dnaSequences",
330
+ annotationType: "dnaSequences",
331
+ noTitle: true,
332
+ Annotation: CircularDnaSequence,
333
+ isAnnotation: true,
334
+ annotationProps: {
335
+ showReverseSequence: annotationVisibility.reverseSequence,
336
+ showDnaColors: annotationVisibility.dnaColors,
337
+ showSeqText
338
+ },
339
+ noHover: true,
340
+ annotations: getSequenceWithinRange(rangeToShow, sequence)
341
+ .split("")
342
+ .map((letter, i) => {
343
+ const pos = rangeToShow.start + i;
344
+ return {
345
+ className: `ve-dna-letter-${pos}`,
346
+ start: pos,
347
+ end: pos,
348
+ letter
349
+ };
350
+ }),
351
+ useCenter: true,
352
+ passAnnotation: true,
353
+ allOnSameLevel: true,
354
+ addHeight: true,
355
+ alwaysShow: true,
356
+ showLabels: false,
357
+ spaceBefore: 5,
358
+ spaceAfter: annotationVisibility.reverseSequence ? 20 : 5
359
+ }
360
+ ]
361
+ : []),
362
+ {
363
+ zIndex: 15,
364
+ alwaysShow: true,
365
+ layerName: "caret",
366
+ Annotation: drawCaret
367
+ },
368
+
369
+ {
370
+ zIndex: 10,
371
+ alwaysShow: true,
372
+ layerName: "selectionLayer",
373
+ Annotation: drawSelectionLayer,
374
+ spaceAfter: 10
375
+ },
376
+ {
377
+ zIndex: 20,
378
+ layerName: "replacementLayers",
379
+ isAnnotation: true,
380
+ spaceAfter: 20
381
+ },
382
+ {
383
+ zIndex: 20,
384
+ layerName: "deletionLayers",
385
+ isAnnotation: true,
386
+ spaceAfter: 20
387
+ },
388
+
389
+ {
390
+ zIndex: 20,
391
+ Annotation: Orf,
392
+ showLabels: false,
393
+ getColor: getOrfColor,
394
+ layerName: "orfs",
395
+ isAnnotation: true,
396
+ spaceBefore: 10
397
+ },
398
+ {
399
+ spaceBefore: 10,
400
+ spaceAfter: 5,
401
+ zIndex: 20,
402
+ Annotation: Primer,
403
+ isAnnotation: true,
404
+ layerName: "primers"
405
+ },
406
+ {
407
+ zIndex: 20,
408
+ layerName: "parts",
409
+ isAnnotation: true,
410
+ spaceBefore: 10,
411
+ spaceAfter: 5
412
+ },
413
+ {
414
+ zIndex: 20,
415
+ layerName: "lineageAnnotations",
416
+ isAnnotation: true,
417
+ spaceBefore: 10,
418
+ spaceAfter: 5
419
+ },
420
+ {
421
+ zIndex: 20,
422
+ layerName: "assemblyPieces",
423
+ isAnnotation: true,
424
+ spaceBefore: 10,
425
+ spaceAfter: 5
426
+ },
427
+ {
428
+ zIndex: 20,
429
+ layerName: "warnings",
430
+ isAnnotation: true,
431
+ spaceBefore: 10,
432
+ spaceAfter: 5
433
+ },
434
+ {
435
+ zIndex: 30,
436
+ alwaysShow: true,
437
+ layerName: "labels",
438
+ Annotation: Labels,
439
+ circularViewWidthVsHeightRatio: width / height,
440
+ passLabels: true,
441
+ labelLineIntensity: labelLineIntensity,
442
+ labelSize: labelSize,
443
+ fontHeightMultiplier: fontHeightMultiplier,
444
+ textScalingFactor: 700 / Math.min(width, height)
445
+ }
446
+ ];
447
+ const paredDownMessages = [];
448
+ const output = layersToDraw
449
+ .map((layer) => {
450
+ const {
451
+ layerName,
452
+ maxToDisplay,
453
+ Comp,
454
+ Annotation,
455
+ fontStyle,
456
+ alwaysShow,
457
+ isAnnotation,
458
+ spaceBefore = 0,
459
+ spaceAfter = 0,
460
+ zIndex,
461
+ passLabels,
462
+ noTitle,
463
+ ...rest
464
+ } = layer;
465
+ if (!(alwaysShow || annotationVisibility[layerName])) {
466
+ return null;
467
+ }
468
+ //DRAW FEATURES
469
+ let comp;
470
+ let results;
471
+
472
+ const singularName = getSingular(layerName);
473
+ const nameUpper = upperFirst(layerName);
474
+ radius += spaceBefore;
475
+
476
+ const sharedProps = {
477
+ radius,
478
+ innerRadius: BASE_RADIUS,
479
+ outerRadius: radius,
480
+ noRedux,
481
+ isProtein,
482
+ smartCircViewLabelRender,
483
+ extraSideSpace: Math.max(0, width - height),
484
+ onClick: props[singularName + "Clicked"],
485
+ onDoubleClick: props[singularName + "DoubleClicked"],
486
+ onRightClicked: props[singularName + "RightClicked"],
487
+ sequenceLength,
488
+ editorName,
489
+ showCicularViewInternalLabels,
490
+ ...rest
491
+ };
492
+ if (isAnnotation) {
493
+ //we're drawing features/cutsites/primers/orfs/etc (something that lives on the seqData)
494
+ if (!map(sequenceData[layerName]).length && !alwaysShow) {
495
+ radius -= spaceBefore;
496
+ return null;
497
+ }
498
+
499
+ const trimmedAnnotations = flatMap(
500
+ layer.annotations ||
501
+ sequenceData["filtered" + nameUpper] ||
502
+ sequenceData[layerName] ||
503
+ [],
504
+ (range) => {
505
+ const overlapOfRanges = getOverlapsOfPotentiallyCircularRanges(
506
+ range,
507
+ rangeToShow,
508
+ sequenceLength,
509
+ true
510
+ );
511
+ if (!overlapOfRanges || !overlapOfRanges.length) return [];
512
+ return { ...range };
513
+ }
514
+ );
515
+
516
+ const maxToShow =
517
+ !isZoomedIn &&
518
+ ((maxAnnotationsToDisplay
519
+ ? maxAnnotationsToDisplay[layerName]
520
+ : limits[layerName]) ||
521
+ 50);
522
+ const [trimmedAndParedAnns, paredDown] = maxToShow
523
+ ? pareDownAnnotations(trimmedAnnotations, maxToShow)
524
+ : [trimmedAnnotations];
525
+
526
+ if (paredDown) {
527
+ paredDownMessages.push(
528
+ getParedDownWarning({
529
+ nameUpper,
530
+ maxToShow,
531
+ isAdjustable: !maxAnnotationsToDisplay
532
+ })
533
+ );
534
+ }
535
+
536
+ results = drawAnnotations({
537
+ readOnly,
538
+ noTitle,
539
+ rotationRadians,
540
+ visibleAngleRange,
541
+ isZoomedIn,
542
+ Annotation: Annotation || Comp || Feature,
543
+ fontStyle: fontStyle,
544
+ hoveredId: hoveredId,
545
+ annotationType: singularName,
546
+ type: singularName,
547
+ reverseAnnotations: true,
548
+ showLabels: !(annotationLabelVisibility[layerName] === false),
549
+ annotations: trimmedAndParedAnns,
550
+ annotationHeight,
551
+ spaceBetweenAnnotations,
552
+ ...sharedProps,
553
+ ...props[singularName + "Options"]
554
+ });
555
+ } else {
556
+ //we're drawing axis/selectionLayer/labels/caret/etc (something that doesn't live on the seqData)
557
+ results = Annotation({
558
+ rotationRadians: rotationRadians,
559
+ ...(passLabels && { labels }),
560
+ ...sharedProps
561
+ });
562
+ }
563
+ if (results) {
564
+ // //update the radius, labels, and svg
565
+ radius += results.height || 0;
566
+ //tnr: we had been storing labels as a keyed-by-id object but that caused parts and features with the same id to override eachother
567
+ labels = [...map(labels), ...map(results.labels || {})];
568
+ comp = results.component === undefined ? results : results.component;
569
+ }
570
+ radius += spaceAfter;
571
+ // console.warn('radius after draw:',JSON.stringify(radius,null,4))
572
+ return {
573
+ result: comp,
574
+ zIndex
575
+ };
576
+ })
577
+ .filter(function (i) {
578
+ return !!i;
579
+ });
580
+
581
+ annotationsSvgs = sortBy(output, "zIndex").reduce(function (arr, { result }) {
582
+ return arr.concat(result);
583
+ }, []);
584
+
585
+ function drawSelectionLayer() {
586
+ //DRAW SELECTION LAYER
587
+ return getAllSelectionLayers({
588
+ additionalSelectionLayers,
589
+ searchLayers,
590
+ selectionLayer
591
+ })
592
+ .map(function (selectionLayer, index) {
593
+ if (
594
+ selectionLayer.start >= 0 &&
595
+ selectionLayer.end >= 0 &&
596
+ sequenceLength > 0
597
+ ) {
598
+ return (
599
+ <SelectionLayer
600
+ key={index}
601
+ {...{
602
+ index,
603
+ isDraggable: true,
604
+ isProtein,
605
+ key: "veCircularViewSelectionLayer" + index,
606
+ selectionLayer,
607
+ onRightClicked: selectionLayer.isSearchLayer
608
+ ? searchLayerRightClicked
609
+ : selectionLayerRightClicked,
610
+ onClick: selectionLayer.isSearchLayer
611
+ ? searchLayerClicked
612
+ : undefined,
613
+ sequenceLength,
614
+ radius,
615
+ innerRadius
616
+ }}
617
+ />
618
+ );
619
+ } else {
620
+ return null;
621
+ }
622
+ })
623
+ .filter((el) => {
624
+ return !!el;
625
+ });
626
+ }
627
+
628
+ function drawCaret() {
629
+ //DRAW CARET
630
+ if (
631
+ caretPosition !== -1 &&
632
+ selectionLayer.start < 0 &&
633
+ sequenceLength >= 0
634
+ ) {
635
+ //only render if there is no selection layer
636
+ return (
637
+ <Caret
638
+ {...{
639
+ caretPosition,
640
+ sequenceLength,
641
+ isProtein,
642
+ innerRadius,
643
+ outerRadius: radius,
644
+ key: "veCircularViewCaret"
645
+ }}
646
+ />
647
+ );
648
+ }
649
+ }
650
+
651
+ //tnr: Make the radius have a minimum so the empty yellow axis circle doesn't take up the entire screen
652
+ if (radius < 150) radius = 150;
653
+ const widthToUse = Math.max(Number(width) || 300);
654
+ const heightToUse = Math.max(Number(height) || 300);
655
+ const bpTitle = isProtein
656
+ ? `${Math.floor(sequenceLength / 3)} AAs`
657
+ : `${sequenceLength} bps`;
658
+ const nameEl = (
659
+ <div
660
+ className="veSequenceName"
661
+ style={{
662
+ position: "absolute",
663
+ width: "100%",
664
+ height: "100%",
665
+ pointerEvents: "none",
666
+ display: "flex",
667
+ justifyContent: "center",
668
+ alignItems: isZoomedIn || smallZoom < 1 ? "end" : "center",
669
+ paddingLeft: isZoomedIn || smallZoom < 1 ? 20 : 0,
670
+ paddingRight: isZoomedIn || smallZoom < 1 ? 20 : 0,
671
+ textAlign: "center",
672
+
673
+ zIndex: 1
674
+ }}
675
+ >
676
+ <div style={{ marginBottom: isZoomedIn || smallZoom < 1 ? 80 : 0 }}>
677
+ <div
678
+ title={sequenceName}
679
+ className="veCircularViewTextWrapper"
680
+ style={{
681
+ textAlign: "center",
682
+ display: "-webkit-box",
683
+ WebkitLineClamp: "3",
684
+ WebkitBoxOrient: "vertical",
685
+ overflow: "hidden",
686
+ wordBreak: "break-all",
687
+ textOverflow: "ellipsis",
688
+ width: isZoomedIn || smallZoom < 1 ? undefined : innerRadius,
689
+ maxHeight: innerRadius - 15,
690
+ fontSize: nameFontSizeCircularView
691
+ }}
692
+ >
693
+ {sequenceName}
694
+ </div>
695
+ <span title={bpTitle} style={{ fontSize: 10 }}>
696
+ {bpTitle}
697
+ </span>
698
+ </div>
699
+ </div>
700
+ );
701
+
702
+ const target = React.useRef();
703
+
704
+ usePinch(
705
+ ({ delta: [d], event }) => {
706
+ if (d === 0) return;
707
+ event.stopPropagation();
708
+ zoomHelper.current.triggerChange &&
709
+ zoomHelper.current.triggerChange(({ changeValue, value }) => {
710
+ changeValue(value + d * 5);
711
+ });
712
+ },
713
+ {
714
+ target,
715
+ from: [zoomLevel]
716
+ }
717
+ );
718
+ const toPass = { ...props, sequenceLength, circRef, rotationRadians };
719
+
720
+ return (
721
+ <div
722
+ style={{
723
+ width: widthToUse,
724
+ height: heightToUse,
725
+ position: "relative",
726
+ overflow: "hidden"
727
+ }}
728
+ onWheel={
729
+ withZoomCircularView && hasRotateableLength
730
+ ? (e) => {
731
+ let delta = e.deltaY;
732
+ if (Math.abs(e.deltaY) < Math.abs(e.deltaX)) {
733
+ delta = e.deltaX;
734
+ }
735
+ rotateHelper.current.triggerChange &&
736
+ rotateHelper.current.triggerChange(({ changeValue, value }) => {
737
+ changeValue(
738
+ (normalizeAngle(((value + delta / 4) * Math.PI) / 180) /
739
+ Math.PI) *
740
+ 180
741
+ );
742
+ });
743
+
744
+ e.stopPropagation();
745
+ }
746
+ : undefined
747
+ }
748
+ className={classNames("veCircularView", props.className)}
749
+ >
750
+ {!hideName && isZoomedIn && nameEl}
751
+
752
+ {withRotateCircularView && hasRotateableLength && (
753
+ <RotateCircularViewSlider
754
+ bindOutsideChangeHelper={rotateHelper.current}
755
+ zoomLevel={zoomLevel}
756
+ smallSlider={smallSlider}
757
+ maxZoomLevel={maxZoomLevel}
758
+ setRotationRadians={setRotationRadians}
759
+ ></RotateCircularViewSlider>
760
+ )}
761
+ {withZoomCircularView && hasZoomableLength && (
762
+ <ZoomCircularViewSlider
763
+ zoomHelper={zoomHelper}
764
+ smallSlider={smallSlider}
765
+ onZoom={() => {
766
+ const caret =
767
+ caretPosition > -1
768
+ ? caretPosition
769
+ : selectionLayer.start > -1
770
+ ? getMiddleOfRange(selectionLayer, sequenceLength)
771
+ : undefined;
772
+ if (caret !== undefined) {
773
+ const radToRotateTo = (caret / sequenceLength) * Math.PI * 2;
774
+ rotateHelper.current.triggerChange &&
775
+ rotateHelper.current.triggerChange(({ changeValue }) => {
776
+ const isInView = isRangeOrPositionWithinRange(
777
+ caret,
778
+ rangeToShow,
779
+ sequenceLength
780
+ );
781
+ if (!isInView) {
782
+ if (selectionLayer.start > -1) {
783
+ const trimmed = trimRangeByAnotherRange(
784
+ selectionLayer,
785
+ rangeToShow,
786
+ sequenceLength
787
+ );
788
+ if (
789
+ trimmed.start !== selectionLayer.start ||
790
+ trimmed.end !== selectionLayer.end
791
+ )
792
+ return;
793
+ }
794
+ changeValue((radToRotateTo / Math.PI) * 180);
795
+ }
796
+ });
797
+ }
798
+ // updateLabelsForInViewFeaturesCircView({ radius });
799
+ }}
800
+ zoomLevel={_zoomLevel}
801
+ maxZoomLevel={maxZoomLevel}
802
+ setZoomLevel={setZoomLevel}
803
+ />
804
+ )}
805
+ <Draggable
806
+ // enableUserSelectHack={false} //needed to prevent the input bubble from losing focus post user drag
807
+ bounds={{ top: 0, left: 0, right: 0, bottom: 0 }}
808
+ onDrag={(event) => {
809
+ getNearestCursorPositionToMouseEvent(event, toPass, editorDragged);
810
+ }}
811
+ onStart={(event) => {
812
+ getNearestCursorPositionToMouseEvent(
813
+ event,
814
+ toPass,
815
+ editorDragStarted
816
+ );
817
+ }}
818
+ onStop={editorDragStopped}
819
+ >
820
+ <div
821
+ ref={withZoomCircularView && hasZoomableLength ? target : undefined}
822
+ >
823
+ <svg
824
+ key="circViewSvg"
825
+ onClick={(event) => {
826
+ instantiated &&
827
+ getNearestCursorPositionToMouseEvent(
828
+ event,
829
+ toPass,
830
+ editorClicked
831
+ );
832
+ }}
833
+ onContextMenu={(e) => {
834
+ getNearestCursorPositionToMouseEvent(
835
+ e,
836
+ toPass,
837
+ backgroundRightClicked
838
+ );
839
+ }}
840
+ style={{
841
+ overflow: "visible",
842
+ display: "block"
843
+ }}
844
+ className="circularViewSvg"
845
+ viewBox={
846
+ isZoomedIn
847
+ ? `${-svgWidth / 2 / smallZoom},${
848
+ -svgHeight / 2 / smallZoom -
849
+ (!isZoomedIn ? 0 : initialRadius + BASE_RADIUS * 2 - 100)
850
+ },${svgWidth / smallZoom},${svgHeight / smallZoom}`
851
+ : `-${radius} -${radius} ${radius * 2} ${radius * 2}`
852
+ }
853
+ width={svgWidth}
854
+ height={svgHeight}
855
+ >
856
+ <g>
857
+ {/* {isZoomedIn && (
858
+
859
+ )} */}
860
+ <circle
861
+ ref={circRef}
862
+ r={radius}
863
+ style={{ opacity: 0, zIndex: -1 }}
864
+ className="veHiddenAxis"
865
+ ></circle>
866
+ {annotationsSvgs}
867
+ {!hideName && !isZoomedIn && (
868
+ <foreignObject
869
+ x={-72.5 / 2}
870
+ y={-72.5 / 2}
871
+ width={72.5}
872
+ height={72.5}
873
+ transform={`rotate(${(-rotationRadians * 180) / Math.PI})`}
874
+ >
875
+ <div
876
+ xmlns="http://www.w3.org/1999/xhtml"
877
+ key="circViewSvgCenterText"
878
+ className="veCircularViewMiddleOfVectorText"
879
+ >
880
+ <div
881
+ title={sequenceName}
882
+ className="veCircularViewTextWrapper"
883
+ style={{
884
+ display: "-webkit-box",
885
+ WebkitLineClamp: "3",
886
+ WebkitBoxOrient: "vertical",
887
+ overflow: "hidden",
888
+ wordBreak: "break-all",
889
+ textOverflow: "ellipsis",
890
+ width: 72.5,
891
+ maxHeight: 72.5 - 15,
892
+ fontSize: nameFontSizeCircularView
893
+ }}
894
+ >
895
+ {sequenceName}
896
+ </div>
897
+ <span title={bpTitle} style={{ fontSize: 10 }}>
898
+ {bpTitle}
899
+ </span>
900
+ </div>
901
+ </foreignObject>
902
+ )}
903
+ </g>
904
+ </svg>
905
+ <VeTopRightContainer {...{ fullScreen }}>
906
+ {!circular && !noWarnings && (
907
+ <VeWarning
908
+ key="ve-warning-circular-to-linear"
909
+ data-test="ve-warning-circular-to-linear"
910
+ intent="warning"
911
+ tooltip={
912
+ "Warning! You're viewing a linear sequence in the Circular Map. Click on 'Linear Map' to view the linear sequence in a more intuitive way."
913
+ }
914
+ />
915
+ )}
916
+ {!noWarnings && paredDownMessages}
917
+ {isZoomedIn && (
918
+ <CircularZoomMinimap
919
+ rotationRadians={rotationRadians}
920
+ percentOfCircle={percentOfCircle}
921
+ ></CircularZoomMinimap>
922
+ )}
923
+ </VeTopRightContainer>
924
+ </div>
925
+ </Draggable>
926
+ </div>
927
+ );
928
+ }
929
+
930
+ export default withEditorInteractions(CircularView);