@apollo-annotation/jbrowse-plugin-apollo 0.3.12 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/dist/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.d.ts +1 -1
  2. package/dist/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.d.ts.map +1 -1
  3. package/dist/BackendDrivers/BackendDriver.d.ts +29 -4
  4. package/dist/BackendDrivers/BackendDriver.d.ts.map +1 -1
  5. package/dist/BackendDrivers/CollaborationServerDriver.d.ts +3 -1
  6. package/dist/BackendDrivers/CollaborationServerDriver.d.ts.map +1 -1
  7. package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts +22 -0
  8. package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts.map +1 -0
  9. package/dist/BackendDrivers/LocalDriver/db.d.ts +4 -0
  10. package/dist/BackendDrivers/LocalDriver/db.d.ts.map +1 -0
  11. package/dist/BackendDrivers/index.d.ts +1 -2
  12. package/dist/BackendDrivers/index.d.ts.map +1 -1
  13. package/dist/ChangeManager.d.ts +3 -3
  14. package/dist/ChangeManager.d.ts.map +1 -1
  15. package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts +0 -6
  16. package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts.map +1 -1
  17. package/dist/FeatureDetailsWidget/TranscriptWidgetEditLocation.d.ts.map +1 -1
  18. package/dist/FeatureDetailsWidget/model.d.ts +0 -2
  19. package/dist/FeatureDetailsWidget/model.d.ts.map +1 -1
  20. package/dist/LinearApolloDisplay/components/CheckResultWarnings.d.ts.map +1 -1
  21. package/dist/LinearApolloDisplay/components/LinearApolloDisplay.d.ts.map +1 -1
  22. package/dist/LinearApolloDisplay/components/OverlayCanvas.d.ts +7 -0
  23. package/dist/LinearApolloDisplay/components/OverlayCanvas.d.ts.map +1 -0
  24. package/dist/LinearApolloDisplay/components/Tooltip.d.ts +10 -0
  25. package/dist/LinearApolloDisplay/components/Tooltip.d.ts.map +1 -0
  26. package/dist/LinearApolloDisplay/glyphs/BoxGlyph.d.ts +0 -1
  27. package/dist/LinearApolloDisplay/glyphs/BoxGlyph.d.ts.map +1 -1
  28. package/dist/LinearApolloDisplay/glyphs/CDSGlyph.d.ts +3 -0
  29. package/dist/LinearApolloDisplay/glyphs/CDSGlyph.d.ts.map +1 -0
  30. package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts +3 -0
  31. package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts.map +1 -0
  32. package/dist/LinearApolloDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
  33. package/dist/LinearApolloDisplay/glyphs/GenericChildGlyph.d.ts.map +1 -1
  34. package/dist/LinearApolloDisplay/glyphs/Glyph.d.ts +26 -20
  35. package/dist/LinearApolloDisplay/glyphs/Glyph.d.ts.map +1 -1
  36. package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts +3 -0
  37. package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts.map +1 -0
  38. package/dist/LinearApolloDisplay/glyphs/util.d.ts +13 -0
  39. package/dist/LinearApolloDisplay/glyphs/util.d.ts.map +1 -1
  40. package/dist/LinearApolloDisplay/stateModel/base.d.ts +17 -0
  41. package/dist/LinearApolloDisplay/stateModel/base.d.ts.map +1 -1
  42. package/dist/LinearApolloDisplay/stateModel/index.d.ts +35 -17
  43. package/dist/LinearApolloDisplay/stateModel/index.d.ts.map +1 -1
  44. package/dist/LinearApolloDisplay/stateModel/layouts.d.ts +29 -7
  45. package/dist/LinearApolloDisplay/stateModel/layouts.d.ts.map +1 -1
  46. package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts +69 -23
  47. package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts.map +1 -1
  48. package/dist/LinearApolloDisplay/stateModel/rendering.d.ts +26 -9
  49. package/dist/LinearApolloDisplay/stateModel/rendering.d.ts.map +1 -1
  50. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts +6 -0
  51. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts.map +1 -1
  52. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts +6 -0
  53. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts.map +1 -1
  54. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts +6 -0
  55. package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts.map +1 -1
  56. package/dist/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.d.ts.map +1 -1
  57. package/dist/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
  58. package/dist/LinearApolloSixFrameDisplay/glyphs/Glyph.d.ts +1 -1
  59. package/dist/LinearApolloSixFrameDisplay/glyphs/Glyph.d.ts.map +1 -1
  60. package/dist/LinearApolloSixFrameDisplay/stateModel/layouts.d.ts.map +1 -1
  61. package/dist/LinearApolloSixFrameDisplay/stateModel/rendering.d.ts.map +1 -1
  62. package/dist/OntologyManager/OntologyStore/fulltext.d.ts +1 -1
  63. package/dist/OntologyManager/OntologyStore/fulltext.d.ts.map +1 -1
  64. package/dist/OntologyManager/OntologyStore/index.d.ts +2 -2
  65. package/dist/OntologyManager/OntologyStore/index.d.ts.map +1 -1
  66. package/dist/OntologyManager/OntologyStore/indexeddb-storage.d.ts +1 -1
  67. package/dist/OntologyManager/OntologyStore/indexeddb-storage.d.ts.map +1 -1
  68. package/dist/OntologyManager/OntologyStore/types.d.ts +18 -0
  69. package/dist/OntologyManager/OntologyStore/types.d.ts.map +1 -0
  70. package/dist/TabularEditor/HybridGrid/featureContextMenuItems.d.ts.map +1 -1
  71. package/dist/components/AddChildFeature.d.ts.map +1 -1
  72. package/dist/components/ColorFeature.d.ts +13 -0
  73. package/dist/components/ColorFeature.d.ts.map +1 -0
  74. package/dist/components/CreateApolloAnnotation.d.ts.map +1 -1
  75. package/dist/components/DownloadGFF3.d.ts +4 -1
  76. package/dist/components/DownloadGFF3.d.ts.map +1 -1
  77. package/dist/components/DuplicateTranscript.d.ts.map +1 -1
  78. package/dist/components/ViewChangeLog.d.ts +2 -1
  79. package/dist/components/ViewChangeLog.d.ts.map +1 -1
  80. package/dist/components/ViewCheckResults.d.ts +2 -1
  81. package/dist/components/ViewCheckResults.d.ts.map +1 -1
  82. package/dist/components/index.d.ts +1 -1
  83. package/dist/components/index.d.ts.map +1 -1
  84. package/dist/config.d.ts +4 -0
  85. package/dist/config.d.ts.map +1 -0
  86. package/dist/extensions/annotationFromJBrowseFeature.d.ts.map +1 -1
  87. package/dist/extensions/annotationFromPileup.d.ts.map +1 -1
  88. package/dist/index.d.ts +11 -0
  89. package/dist/index.d.ts.map +1 -0
  90. package/dist/index.esm.js +6325 -5997
  91. package/dist/index.esm.js.map +1 -1
  92. package/dist/jbrowse-plugin-apollo.cjs.development.js +5869 -5541
  93. package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
  94. package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
  95. package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
  96. package/dist/jbrowse-plugin-apollo.umd.development.js +16782 -25897
  97. package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
  98. package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
  99. package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
  100. package/dist/makeDisplayComponent.d.ts.map +1 -1
  101. package/dist/menus/Icons.d.ts +3 -0
  102. package/dist/menus/Icons.d.ts.map +1 -0
  103. package/dist/menus/topLevelMenu.d.ts.map +1 -1
  104. package/dist/session/changeHandlers.d.ts +9 -0
  105. package/dist/session/changeHandlers.d.ts.map +1 -0
  106. package/dist/util/annotationFeatureUtils.d.ts +2 -1
  107. package/dist/util/annotationFeatureUtils.d.ts.map +1 -1
  108. package/dist/util/glyphUtils.d.ts +3 -3
  109. package/dist/util/glyphUtils.d.ts.map +1 -1
  110. package/dist/util/index.d.ts +0 -1
  111. package/dist/util/index.d.ts.map +1 -1
  112. package/package.json +4 -4
  113. package/src/ApolloInternetAccount/model.ts +68 -4
  114. package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +6 -3
  115. package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +1 -1
  116. package/src/BackendDrivers/BackendDriver.ts +36 -3
  117. package/src/BackendDrivers/CollaborationServerDriver.ts +78 -23
  118. package/src/BackendDrivers/LocalDriver/LocalDriver.ts +367 -0
  119. package/src/BackendDrivers/LocalDriver/db.ts +37 -0
  120. package/src/BackendDrivers/index.ts +1 -2
  121. package/src/ChangeManager.ts +27 -25
  122. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +1 -1
  123. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +69 -53
  124. package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +1 -5
  125. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +95 -115
  126. package/src/LinearApolloDisplay/components/OverlayCanvas.tsx +76 -0
  127. package/src/LinearApolloDisplay/components/Tooltip.tsx +42 -0
  128. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +60 -302
  129. package/src/LinearApolloDisplay/glyphs/CDSGlyph.ts +145 -0
  130. package/src/LinearApolloDisplay/glyphs/ExonGlyph.ts +212 -0
  131. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +65 -999
  132. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +71 -181
  133. package/src/LinearApolloDisplay/glyphs/Glyph.ts +42 -66
  134. package/src/LinearApolloDisplay/glyphs/TranscriptGlyph.ts +291 -0
  135. package/src/LinearApolloDisplay/glyphs/util.ts +87 -0
  136. package/src/LinearApolloDisplay/stateModel/base.ts +83 -0
  137. package/src/LinearApolloDisplay/stateModel/layouts.ts +198 -138
  138. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +252 -158
  139. package/src/LinearApolloDisplay/stateModel/rendering.ts +103 -21
  140. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +3 -3
  141. package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +20 -2
  142. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +7 -2
  143. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +8 -13
  144. package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +1 -1
  145. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +4 -3
  146. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +1 -1
  147. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +2 -1
  148. package/src/OntologyManager/OntologyStore/__snapshots__/index.test.ts.snap +18262 -8519
  149. package/src/OntologyManager/OntologyStore/fulltext.ts +1 -2
  150. package/src/OntologyManager/OntologyStore/index.test.ts +5 -2
  151. package/src/OntologyManager/OntologyStore/index.ts +7 -8
  152. package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +2 -2
  153. package/src/OntologyManager/OntologyStore/types.ts +27 -0
  154. package/src/OntologyManager/index.ts +15 -26
  155. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +4 -5
  156. package/src/components/AddChildFeature.tsx +15 -8
  157. package/src/components/ColorFeature.tsx +167 -0
  158. package/src/components/CreateApolloAnnotation.tsx +35 -9
  159. package/src/components/DownloadGFF3.tsx +92 -121
  160. package/src/components/DuplicateTranscript.tsx +10 -0
  161. package/src/components/ViewChangeLog.tsx +123 -83
  162. package/src/components/ViewCheckResults.tsx +15 -73
  163. package/src/components/index.ts +1 -1
  164. package/src/config.ts +37 -19
  165. package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -1
  166. package/src/extensions/annotationFromJBrowseFeature.ts +91 -63
  167. package/src/extensions/annotationFromPileup.ts +40 -40
  168. package/src/index.ts +45 -1
  169. package/src/makeDisplayComponent.tsx +10 -3
  170. package/src/menus/Icons.tsx +49 -0
  171. package/src/menus/topLevelMenu.ts +24 -96
  172. package/src/session/ClientDataStore.ts +16 -17
  173. package/src/session/changeHandlers.ts +261 -0
  174. package/src/session/session.ts +77 -46
  175. package/src/util/annotationFeatureUtils.ts +29 -1
  176. package/src/util/glyphUtils.ts +74 -31
  177. package/src/util/index.ts +0 -1
  178. package/dist/BackendDrivers/DesktopFileDriver.d.ts +0 -160
  179. package/dist/BackendDrivers/DesktopFileDriver.d.ts.map +0 -1
  180. package/dist/BackendDrivers/InMemoryFileDriver.d.ts +0 -162
  181. package/dist/BackendDrivers/InMemoryFileDriver.d.ts.map +0 -1
  182. package/dist/LinearApolloDisplay/glyphs/index.d.ts +0 -4
  183. package/dist/LinearApolloDisplay/glyphs/index.d.ts.map +0 -1
  184. package/dist/components/OpenLocalFile.d.ts +0 -15
  185. package/dist/components/OpenLocalFile.d.ts.map +0 -1
  186. package/dist/util/loadAssemblyIntoClient.d.ts +0 -5
  187. package/dist/util/loadAssemblyIntoClient.d.ts.map +0 -1
  188. package/src/BackendDrivers/DesktopFileDriver.ts +0 -184
  189. package/src/BackendDrivers/InMemoryFileDriver.ts +0 -107
  190. package/src/LinearApolloDisplay/glyphs/index.ts +0 -3
  191. package/src/components/OpenLocalFile.tsx +0 -189
  192. package/src/util/loadAssemblyIntoClient.ts +0 -94
@@ -0,0 +1,291 @@
1
+ import type { AnnotationFeature } from '@apollo-annotation/mst'
2
+ import type { MenuItem } from '@jbrowse/core/ui'
3
+ import {
4
+ type AbstractSessionModel,
5
+ isSessionModelWithWidgets,
6
+ } from '@jbrowse/core/util'
7
+ import type { ContentBlock } from '@jbrowse/core/util/blockTypes'
8
+
9
+ import { DuplicateTranscript, MergeTranscripts } from '../../components'
10
+ import {
11
+ isCDSFeature,
12
+ isExonFeature,
13
+ isSelectedFeature,
14
+ } from '../../util/glyphUtils'
15
+ import type { LinearApolloDisplay } from '../stateModel'
16
+
17
+ import { boxGlyph } from './BoxGlyph'
18
+ import type { Glyph, LayoutRow, OverlayType } from './Glyph'
19
+ import { drawOverlayBox, getFeatureBox, getLeftPx } from './util'
20
+
21
+ function* range(start: number, stop: number, step = 1): Generator<number> {
22
+ if (start === stop) {
23
+ return
24
+ }
25
+ if (start < stop) {
26
+ for (let i = start; i < stop; i += step) {
27
+ yield i
28
+ }
29
+ return
30
+ }
31
+ for (let i = start; i > stop; i -= step) {
32
+ yield i
33
+ }
34
+ }
35
+
36
+ function drawTranscriptLine(
37
+ display: LinearApolloDisplay,
38
+ ctx: CanvasRenderingContext2D,
39
+ transcript: AnnotationFeature,
40
+ row: number,
41
+ block: ContentBlock,
42
+ ) {
43
+ const { apolloRowHeight, lgv, theme } = display
44
+ const { bpPerPx } = lgv
45
+ const { reversed } = block
46
+ const left = Math.round(getLeftPx(display, transcript, block))
47
+ const width = Math.round(transcript.length / bpPerPx)
48
+ const top = Math.round(apolloRowHeight / 2) + row * apolloRowHeight
49
+ ctx.strokeStyle = theme.palette.text.primary
50
+ const { strand = 1 } = transcript
51
+ ctx.beginPath()
52
+ // If view is reversed, draw forward as reverse and vice versa
53
+ const effectiveStrand = strand * (reversed ? -1 : 1)
54
+ // Draw the transcript line, and extend it out a bit on the 3` end
55
+ let lineStart = left - (effectiveStrand === -1 ? 5 : 0)
56
+ let lineEnd = left + width + (effectiveStrand === -1 ? 0 : 5)
57
+ // Limit the transcript line to the width of the screen to avoid drawing
58
+ // too many arrows
59
+ lineStart = Math.max(lineStart, 0)
60
+ lineEnd = Math.min(lineEnd, globalThis.innerWidth)
61
+ ctx.moveTo(lineStart, top)
62
+ ctx.lineTo(lineEnd, top)
63
+ // Now to draw arrows every 20 pixels along the line
64
+ // Make the arrow range a bit shorter to avoid an arrow hanging off the 5` end
65
+ const arrowsStart = lineStart + (effectiveStrand === -1 ? 0 : 3)
66
+ const arrowsEnd = lineEnd - (effectiveStrand === -1 ? 3 : 0)
67
+ // Offset determines if the arrows face left or right
68
+ const offset = effectiveStrand === -1 ? 3 : -3
69
+ const arrowRange =
70
+ effectiveStrand === -1
71
+ ? range(arrowsStart, arrowsEnd, 20)
72
+ : range(arrowsEnd, arrowsStart, 20)
73
+ for (const arrowLocation of arrowRange) {
74
+ ctx.moveTo(arrowLocation + offset, top + offset)
75
+ ctx.lineTo(arrowLocation, top)
76
+ ctx.lineTo(arrowLocation + offset, top - offset)
77
+ }
78
+ ctx.stroke()
79
+ }
80
+
81
+ function getExonChildren(
82
+ display: LinearApolloDisplay,
83
+ transcript: AnnotationFeature,
84
+ ): AnnotationFeature[] {
85
+ const { children } = transcript
86
+ if (!children) {
87
+ return []
88
+ }
89
+ const { session } = display
90
+ return [...children.values()].filter((child) => isExonFeature(child, session))
91
+ }
92
+
93
+ function getNonExonChildren(
94
+ display: LinearApolloDisplay,
95
+ transcript: AnnotationFeature,
96
+ ): AnnotationFeature[] {
97
+ const { children } = transcript
98
+ if (!children) {
99
+ return []
100
+ }
101
+ const { session } = display
102
+ return [...children.values()].filter(
103
+ (child) => !isExonFeature(child, session),
104
+ )
105
+ }
106
+
107
+ function getRowCount(display: LinearApolloDisplay, feature: AnnotationFeature) {
108
+ return getLayout(display, feature).byRow.length
109
+ }
110
+
111
+ function draw(
112
+ display: LinearApolloDisplay,
113
+ ctx: CanvasRenderingContext2D,
114
+ transcript: AnnotationFeature,
115
+ row: number,
116
+ rowInFeature: number,
117
+ block: ContentBlock,
118
+ ) {
119
+ drawTranscriptLine(display, ctx, transcript, row, block)
120
+ const { selectedFeature } = display
121
+ if (isSelectedFeature(transcript, selectedFeature)) {
122
+ drawOverlay(display, ctx, transcript, row, block, 'select')
123
+ }
124
+ }
125
+
126
+ function drawOverlay(
127
+ display: LinearApolloDisplay,
128
+ overlayCtx: CanvasRenderingContext2D,
129
+ transcript: AnnotationFeature,
130
+ row: number,
131
+ block: ContentBlock,
132
+ overlayType: OverlayType,
133
+ ) {
134
+ const { apolloRowHeight } = display
135
+ const [top, left, width] = getFeatureBox(display, transcript, row, block)
136
+ const height = apolloRowHeight * getRowCount(display, transcript)
137
+ drawOverlayBox(
138
+ display,
139
+ overlayCtx,
140
+ left,
141
+ top,
142
+ width,
143
+ height,
144
+ transcript,
145
+ overlayType,
146
+ )
147
+ }
148
+
149
+ function getLayout(display: LinearApolloDisplay, feature: AnnotationFeature) {
150
+ const layout = {
151
+ byFeature: new Map([[feature._id, 0]]),
152
+ byRow: [[{ feature, rowInFeature: 0 }]],
153
+ min: feature.min,
154
+ max: feature.max,
155
+ }
156
+ const { children } = feature
157
+ if (!children) {
158
+ return layout
159
+ }
160
+ layout.byRow = []
161
+ const exons = getExonChildren(display, feature)
162
+ const nonExonChildren = getNonExonChildren(display, feature)
163
+ layout.byFeature.set(feature._id, 0)
164
+ // Usually non-coding (no CDS) transcript
165
+ if (nonExonChildren.length === 0) {
166
+ const row: LayoutRow = []
167
+ row.push({ feature, rowInFeature: 0 })
168
+ for (const exon of exons) {
169
+ row.push({ feature: exon, rowInFeature: 0 })
170
+ layout.byFeature.set(exon._id, 0)
171
+ }
172
+ layout.byRow.push(row)
173
+ return layout
174
+ }
175
+ // eslint-disable-next-line @typescript-eslint/unbound-method
176
+ const { getGlyph, session } = display
177
+ let extraOffset = 0
178
+ for (const [idx, child] of nonExonChildren.entries()) {
179
+ const row: LayoutRow = []
180
+ row.push({ feature, rowInFeature: idx + extraOffset })
181
+ if (isCDSFeature(child, session)) {
182
+ for (const exon of exons) {
183
+ row.push({ feature: exon, rowInFeature: extraOffset })
184
+ layout.byFeature.set(exon._id, extraOffset)
185
+ }
186
+ row.push({ feature: child, rowInFeature: extraOffset })
187
+ layout.byFeature.set(child._id, extraOffset)
188
+ } else {
189
+ const glyph = getGlyph(child)
190
+ const rowCount = glyph.getLayout(display, child).byRow.length
191
+ for (let i = 0; i < rowCount; i++) {
192
+ row.push({ feature: child, rowInFeature: i })
193
+ layout.byFeature.set(child._id, i)
194
+ }
195
+ extraOffset += rowCount - 1
196
+ }
197
+ layout.byRow.push(row)
198
+ }
199
+ return layout
200
+ }
201
+
202
+ function getContextMenuItems(
203
+ display: LinearApolloDisplay,
204
+ feature: AnnotationFeature,
205
+ ): MenuItem[] {
206
+ const { changeManager, regions, selectedFeature, session } = display
207
+ const [region] = regions
208
+ const currentAssemblyId = display.getAssemblyId(region.assemblyName)
209
+ const menuItems: MenuItem[] = []
210
+ if (isSessionModelWithWidgets(session)) {
211
+ menuItems.splice(1, 0, {
212
+ label: 'Open transcript editor',
213
+ onClick: () => {
214
+ const apolloTranscriptWidget = session.addWidget(
215
+ 'ApolloTranscriptDetails',
216
+ 'apolloTranscriptDetails',
217
+ {
218
+ feature,
219
+ assembly: currentAssemblyId,
220
+ changeManager,
221
+ refName: region.refName,
222
+ },
223
+ )
224
+ session.showWidget(apolloTranscriptWidget)
225
+ },
226
+ })
227
+ }
228
+ menuItems.push(
229
+ {
230
+ label: 'Merge transcript',
231
+ onClick: () => {
232
+ ;(session as unknown as AbstractSessionModel).queueDialog(
233
+ (doneCallback) => [
234
+ MergeTranscripts,
235
+ {
236
+ session,
237
+ handleClose: () => {
238
+ doneCallback()
239
+ },
240
+ changeManager,
241
+ sourceFeature: feature,
242
+ sourceAssemblyId: currentAssemblyId,
243
+ selectedFeature,
244
+ setSelectedFeature: (feature?: AnnotationFeature) => {
245
+ display.setSelectedFeature(feature)
246
+ },
247
+ },
248
+ ],
249
+ )
250
+ },
251
+ },
252
+ {
253
+ label: 'Duplicate feature',
254
+ onClick: () => {
255
+ ;(session as unknown as AbstractSessionModel).queueDialog(
256
+ (doneCallback) => [
257
+ DuplicateTranscript,
258
+ {
259
+ session,
260
+ handleClose: () => {
261
+ doneCallback()
262
+ },
263
+ changeManager,
264
+ sourceFeature: feature,
265
+ sourceAssemblyId: currentAssemblyId,
266
+ selectedFeature,
267
+ setSelectedFeature: (feature?: AnnotationFeature) => {
268
+ display.setSelectedFeature(feature)
269
+ },
270
+ },
271
+ ],
272
+ )
273
+ },
274
+ },
275
+ )
276
+ return menuItems
277
+ }
278
+
279
+ // False positive here, none of these functions use "this"
280
+ /* eslint-disable @typescript-eslint/unbound-method */
281
+ const { drawDragPreview } = boxGlyph
282
+ /* eslint-enable @typescript-eslint/unbound-method */
283
+
284
+ export const transcriptGlyph: Glyph = {
285
+ draw,
286
+ drawDragPreview,
287
+ drawOverlay,
288
+ getContextMenuItems,
289
+ getLayout,
290
+ isDraggable: false,
291
+ }
@@ -1,6 +1,12 @@
1
+ import type { AnnotationFeature } from '@apollo-annotation/mst'
1
2
  import type { ContentBlock } from '@jbrowse/core/util/blockTypes'
3
+ import type {} from '../../util'
4
+ import { alpha } from '@mui/material'
2
5
 
3
6
  import type { LinearApolloDisplay } from '../stateModel'
7
+ import type { MousePosition } from '../stateModel/mouseEvents'
8
+
9
+ import type { OverlayType } from './Glyph'
4
10
 
5
11
  export function getLeftPx(
6
12
  display: LinearApolloDisplay,
@@ -18,6 +24,60 @@ export function getLeftPx(
18
24
  return blockLeftPx + featureLeftPxDistanceFromBlockLeftPx
19
25
  }
20
26
 
27
+ export function getFeatureBox(
28
+ display: LinearApolloDisplay,
29
+ feature: { max: number; min: number },
30
+ row: number,
31
+ block: ContentBlock,
32
+ ): [number, number, number, number] {
33
+ const { apolloRowHeight, lgv } = display
34
+ const { bpPerPx } = lgv
35
+ const left = Math.round(getLeftPx(display, feature, block))
36
+ const top = row * apolloRowHeight
37
+ const width = Math.round((feature.max - feature.min) / bpPerPx)
38
+ const height = apolloRowHeight
39
+ return [top, left, width, height]
40
+ }
41
+
42
+ function getOverlayColor(
43
+ display: LinearApolloDisplay,
44
+ feature: AnnotationFeature,
45
+ overlayType: OverlayType,
46
+ ): string | undefined {
47
+ const { theme } = display
48
+ switch (overlayType) {
49
+ case 'select': {
50
+ return theme.palette.action.disabled
51
+ }
52
+ case 'hover': {
53
+ return theme.palette.action.focus
54
+ }
55
+ case 'highlight': {
56
+ const { attributes } = feature
57
+ const colorAttribute = attributes.get('apollo_color')
58
+ return colorAttribute?.[0]
59
+ }
60
+ }
61
+ }
62
+
63
+ export function drawOverlayBox(
64
+ display: LinearApolloDisplay,
65
+ ctx: CanvasRenderingContext2D,
66
+ left: number,
67
+ top: number,
68
+ width: number,
69
+ height: number,
70
+ feature: AnnotationFeature,
71
+ overlayType: OverlayType,
72
+ ) {
73
+ const color = getOverlayColor(display, feature, overlayType)
74
+ if (!color) {
75
+ return
76
+ }
77
+ ctx.fillStyle = alpha(color, 0.3)
78
+ ctx.fillRect(left, top, width, height)
79
+ }
80
+
21
81
  /**
22
82
  * Perform a canvas strokeRect, but have the stroke be contained within the
23
83
  * given rect instead of centered on it.
@@ -34,3 +94,30 @@ export function strokeRectInner(
34
94
  ctx.lineWidth = 1
35
95
  ctx.strokeRect(left + 0.5, top + 0.5, width - 1, height - 1)
36
96
  }
97
+
98
+ /** @returns undefined if mouse not on the edge of this feature, otherwise 'start' or 'end' depending on which edge */
99
+ export function isMouseOnFeatureEdge(
100
+ mousePosition: MousePosition,
101
+ feature: { min: number; max: number },
102
+ stateModel: LinearApolloDisplay,
103
+ ) {
104
+ const { refName, regionNumber, x } = mousePosition
105
+ const { lgv } = stateModel
106
+ const { offsetPx } = lgv
107
+ const minPxInfo = lgv.bpToPx({ refName, coord: feature.min, regionNumber })
108
+ const maxPxInfo = lgv.bpToPx({ refName, coord: feature.max, regionNumber })
109
+ if (minPxInfo !== undefined && maxPxInfo !== undefined) {
110
+ const minPx = minPxInfo.offsetPx - offsetPx
111
+ const maxPx = maxPxInfo.offsetPx - offsetPx
112
+ if (Math.abs(maxPx - minPx) < 8) {
113
+ return
114
+ }
115
+ if (Math.abs(minPx - x) < 4) {
116
+ return 'min'
117
+ }
118
+ if (Math.abs(maxPx - x) < 4) {
119
+ return 'max'
120
+ }
121
+ }
122
+ return
123
+ }
@@ -27,10 +27,18 @@ import {
27
27
  types,
28
28
  } from '@jbrowse/mobx-state-tree'
29
29
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
30
+ import FactCheckIcon from '@mui/icons-material/FactCheck'
31
+ import TrackChangesIcon from '@mui/icons-material/TrackChanges'
30
32
  import { autorun } from 'mobx'
31
33
 
32
34
  import type { ApolloInternetAccountModel } from '../../ApolloInternetAccount/model'
35
+ import {
36
+ DownloadGFF3,
37
+ Export as ExportIcon,
38
+ } from '../../components/DownloadGFF3'
33
39
  import { FilterFeatures } from '../../components/FilterFeatures'
40
+ import { ViewChangeLog } from '../../components/ViewChangeLog'
41
+ import { ViewCheckResults } from '../../components/ViewCheckResults'
34
42
  import type { ApolloSessionModel, HoveredFeature } from '../../session'
35
43
  import type { ApolloRootModel } from '../../types'
36
44
  import { EditZoomThresholdDialog } from '../../util/displayUtils'
@@ -276,6 +284,81 @@ export function baseModelFactory(
276
284
  )
277
285
  },
278
286
  },
287
+ {
288
+ label: 'Export annotations',
289
+ icon: ExportIcon,
290
+ onClick: () => {
291
+ const [region] = self.regions
292
+ const { assemblyName } = region
293
+ const assembly = self.getAssemblyId(assemblyName)
294
+ if (!assembly) {
295
+ return
296
+ }
297
+ const session = self.session as unknown as ApolloSessionModel
298
+ ;(session as unknown as AbstractSessionModel).queueDialog(
299
+ (doneCallback) => [
300
+ DownloadGFF3,
301
+ {
302
+ session,
303
+ handleClose: () => {
304
+ doneCallback()
305
+ },
306
+ assembly,
307
+ },
308
+ ],
309
+ )
310
+ },
311
+ },
312
+ {
313
+ label: 'View Change Log',
314
+ icon: TrackChangesIcon,
315
+ onClick: () => {
316
+ const [region] = self.regions
317
+ const { assemblyName } = region
318
+ const assembly = self.getAssemblyId(assemblyName)
319
+ if (!assembly) {
320
+ return
321
+ }
322
+ const session = self.session as unknown as ApolloSessionModel
323
+ ;(session as unknown as AbstractSessionModel).queueDialog(
324
+ (doneCallback) => [
325
+ ViewChangeLog,
326
+ {
327
+ session,
328
+ handleClose: () => {
329
+ doneCallback()
330
+ },
331
+ assembly,
332
+ },
333
+ ],
334
+ )
335
+ },
336
+ },
337
+ {
338
+ label: 'View Check Results',
339
+ icon: FactCheckIcon,
340
+ onClick: () => {
341
+ const [region] = self.regions
342
+ const { assemblyName } = region
343
+ const assembly = self.getAssemblyId(assemblyName)
344
+ if (!assembly) {
345
+ return
346
+ }
347
+ const session = self.session as unknown as ApolloSessionModel
348
+ ;(session as unknown as AbstractSessionModel).queueDialog(
349
+ (doneCallback) => [
350
+ ViewCheckResults,
351
+ {
352
+ session,
353
+ handleClose: () => {
354
+ doneCallback()
355
+ },
356
+ assembly,
357
+ },
358
+ ],
359
+ )
360
+ },
361
+ },
279
362
  ]
280
363
  },
281
364
  }