@apollo-annotation/jbrowse-plugin-apollo 0.1.18 → 0.1.20
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/dist/index.esm.js +3189 -3575
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +3185 -3570
- package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.development.js +14884 -15905
- package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
- package/package.json +33 -33
- package/src/ApolloInternetAccount/addMenuItems.ts +18 -0
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -0
- package/src/ApolloInternetAccount/configSchema.ts +5 -2
- package/src/ApolloInternetAccount/model.ts +14 -5
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +94 -0
- package/src/ApolloRefNameAliasAdapter/configSchema.ts +12 -0
- package/src/ApolloRefNameAliasAdapter/index.ts +21 -0
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +1 -0
- package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +10 -10
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +35 -32
- package/src/BackendDrivers/BackendDriver.ts +8 -0
- package/src/BackendDrivers/CollaborationServerDriver.ts +49 -1
- package/src/BackendDrivers/DesktopFileDriver.ts +14 -1
- package/src/BackendDrivers/InMemoryFileDriver.ts +17 -1
- package/src/ChangeManager.ts +1 -1
- package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +5 -25
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +82 -0
- package/src/FeatureDetailsWidget/Attributes.tsx +11 -3
- package/src/FeatureDetailsWidget/BasicInformation.tsx +38 -30
- package/src/FeatureDetailsWidget/Sequence.tsx +7 -7
- package/src/FeatureDetailsWidget/TranscriptBasic.tsx +446 -0
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +365 -0
- package/src/FeatureDetailsWidget/index.ts +2 -0
- package/src/FeatureDetailsWidget/model.ts +77 -9
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +0 -2
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +453 -380
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +520 -0
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +138 -134
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +38 -370
- package/src/LinearApolloDisplay/glyphs/index.ts +1 -2
- package/src/LinearApolloDisplay/stateModel/base.ts +3 -6
- package/src/LinearApolloDisplay/stateModel/getGlyph.ts +30 -30
- package/src/LinearApolloDisplay/stateModel/index.ts +5 -1
- package/src/LinearApolloDisplay/stateModel/layouts.ts +32 -24
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +206 -217
- package/src/LinearApolloDisplay/stateModel/rendering.ts +43 -67
- package/src/OntologyManager/OntologyStore/fulltext.ts +1 -1
- package/src/OntologyManager/OntologyStore/index.ts +2 -1
- package/src/OntologyManager/index.ts +6 -2
- package/src/OntologyManager/util.ts +2 -2
- package/src/SixFrameFeatureDisplay/stateModel.ts +15 -10
- package/src/TabularEditor/HybridGrid/ChangeHandling.ts +21 -46
- package/src/TabularEditor/HybridGrid/Feature.tsx +31 -82
- package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +3 -2
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +2 -3
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +1 -0
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +46 -5
- package/src/TabularEditor/model.ts +5 -3
- package/src/components/AddAssembly.tsx +15 -9
- package/src/components/AddChildFeature.tsx +7 -73
- package/src/components/AddFeature.tsx +2 -57
- package/src/components/AddRefSeqAliases.tsx +285 -0
- package/src/components/CopyFeature.tsx +16 -33
- package/src/components/DeleteFeature.tsx +4 -6
- package/src/components/ImportFeatures.tsx +6 -3
- package/src/components/LogOut.tsx +105 -0
- package/src/components/ManageChecks.tsx +1 -0
- package/src/components/ManageUsers.tsx +21 -1
- package/src/components/ModifyFeatureAttribute.tsx +2 -2
- package/src/components/OntologyTermAutocomplete.tsx +0 -2
- package/src/components/OntologyTermMultiSelect.tsx +1 -0
- package/src/components/OpenLocalFile.tsx +6 -5
- package/src/components/ViewChangeLog.tsx +1 -0
- package/src/components/ViewCheckResults.tsx +1 -0
- package/src/components/index.ts +4 -0
- package/src/extensions/annotationFromPileup.ts +10 -16
- package/src/index.ts +57 -3
- package/src/session/ClientDataStore.ts +49 -46
- package/src/session/session.ts +186 -114
- package/src/util/loadAssemblyIntoClient.ts +4 -210
- package/src/FeatureDetailsWidget/RelatedFeature.tsx +0 -97
- package/src/LinearApolloDisplay/glyphs/CanonicalGeneGlyph.ts +0 -1204
- package/src/LinearApolloDisplay/glyphs/ImplicitExonGeneGlyph.ts +0 -716
- package/src/LinearApolloDisplay/stateModel/glyphs.ts +0 -47
|
@@ -1,405 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
4
|
-
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
5
|
-
import { AnnotationFeatureI } from '@apollo-annotation/mst'
|
|
1
|
+
import { AnnotationFeature } from '@apollo-annotation/mst'
|
|
6
2
|
import { MenuItem } from '@jbrowse/core/ui'
|
|
7
|
-
import { AbstractSessionModel, SessionWithWidgets } from '@jbrowse/core/util'
|
|
8
|
-
import { alpha } from '@mui/material'
|
|
9
3
|
|
|
10
|
-
import {
|
|
11
|
-
AddChildFeature,
|
|
12
|
-
CopyFeature,
|
|
13
|
-
DeleteFeature,
|
|
14
|
-
ModifyFeatureAttribute,
|
|
15
|
-
} from '../../components'
|
|
16
4
|
import {
|
|
17
5
|
LinearApolloDisplayMouseEvents,
|
|
18
|
-
|
|
6
|
+
MousePositionWithFeatureAndGlyph,
|
|
19
7
|
} from '../stateModel/mouseEvents'
|
|
20
8
|
import { LinearApolloDisplayRendering } from '../stateModel/rendering'
|
|
21
9
|
import { CanvasMouseEvent } from '../types'
|
|
22
10
|
|
|
23
|
-
export
|
|
11
|
+
export interface Glyph {
|
|
24
12
|
/** @returns number of layout rows used by this glyph with this feature and zoom level */
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
getRowCount(feature: AnnotationFeature, bpPerPx: number): number
|
|
27
14
|
/** draw the feature's primary rendering on the canvas */
|
|
28
|
-
|
|
29
|
-
display: LinearApolloDisplayRendering,
|
|
15
|
+
draw(
|
|
30
16
|
ctx: CanvasRenderingContext2D,
|
|
31
|
-
feature:
|
|
32
|
-
xOffset: number,
|
|
17
|
+
feature: AnnotationFeature,
|
|
33
18
|
row: number,
|
|
34
|
-
|
|
19
|
+
stateModel: LinearApolloDisplayRendering,
|
|
20
|
+
displayedRegionIndex: number,
|
|
35
21
|
): void
|
|
36
|
-
|
|
37
22
|
/** @returns the feature or subfeature at the given bp and row number in this glyph's layout */
|
|
38
|
-
|
|
39
|
-
feature:
|
|
23
|
+
getFeatureFromLayout(
|
|
24
|
+
feature: AnnotationFeature,
|
|
40
25
|
bp: number,
|
|
41
26
|
row: number,
|
|
42
|
-
):
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
childFeature: AnnotationFeatureI,
|
|
27
|
+
): AnnotationFeature | undefined
|
|
28
|
+
getRowForFeature(
|
|
29
|
+
feature: AnnotationFeature,
|
|
30
|
+
childFeature: AnnotationFeature,
|
|
47
31
|
): number | undefined
|
|
48
32
|
|
|
49
|
-
abstract continueDrag(
|
|
50
|
-
display: LinearApolloDisplayRendering,
|
|
51
|
-
currentMousePosition: MousePosition,
|
|
52
|
-
): void
|
|
53
|
-
|
|
54
33
|
drawHover(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
_xOffset?: number,
|
|
59
|
-
_reversed?: boolean,
|
|
60
|
-
) {
|
|
61
|
-
return
|
|
62
|
-
}
|
|
34
|
+
display: LinearApolloDisplayMouseEvents,
|
|
35
|
+
overlayCtx: CanvasRenderingContext2D,
|
|
36
|
+
): void
|
|
63
37
|
|
|
64
38
|
drawDragPreview(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
68
|
-
return
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** @returns true if the current drag that is starting is valid */
|
|
72
|
-
startDrag(
|
|
73
|
-
_display: LinearApolloDisplayMouseEvents,
|
|
74
|
-
_event: CanvasMouseEvent,
|
|
75
|
-
): boolean {
|
|
76
|
-
return false
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
executeDrag(
|
|
80
|
-
_display: LinearApolloDisplayMouseEvents,
|
|
81
|
-
_event: CanvasMouseEvent,
|
|
82
|
-
): void {
|
|
83
|
-
return
|
|
84
|
-
}
|
|
39
|
+
display: LinearApolloDisplayMouseEvents,
|
|
40
|
+
ctx: CanvasRenderingContext2D,
|
|
41
|
+
): void
|
|
85
42
|
|
|
86
43
|
onMouseDown(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
44
|
+
display: LinearApolloDisplayMouseEvents,
|
|
45
|
+
currentMousePosition: MousePositionWithFeatureAndGlyph,
|
|
46
|
+
event: CanvasMouseEvent,
|
|
47
|
+
): void
|
|
92
48
|
|
|
93
49
|
onMouseMove(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
50
|
+
display: LinearApolloDisplayMouseEvents,
|
|
51
|
+
currentMousePosition: MousePositionWithFeatureAndGlyph,
|
|
52
|
+
event: CanvasMouseEvent,
|
|
53
|
+
): void
|
|
99
54
|
|
|
100
55
|
onMouseLeave(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
56
|
+
display: LinearApolloDisplayMouseEvents,
|
|
57
|
+
currentMousePosition: MousePositionWithFeatureAndGlyph,
|
|
58
|
+
event: CanvasMouseEvent,
|
|
59
|
+
): void
|
|
106
60
|
|
|
107
61
|
onMouseUp(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
onContextMenu(
|
|
115
|
-
_display: LinearApolloDisplayMouseEvents,
|
|
116
|
-
_event: CanvasMouseEvent,
|
|
117
|
-
): void {
|
|
118
|
-
return
|
|
119
|
-
}
|
|
62
|
+
display: LinearApolloDisplayMouseEvents,
|
|
63
|
+
currentMousePosition: MousePositionWithFeatureAndGlyph,
|
|
64
|
+
event: CanvasMouseEvent,
|
|
65
|
+
): void
|
|
120
66
|
|
|
121
67
|
drawTooltip(
|
|
122
68
|
display: LinearApolloDisplayMouseEvents,
|
|
123
69
|
context: CanvasRenderingContext2D,
|
|
124
|
-
): void
|
|
125
|
-
const { apolloHover, apolloRowHeight, displayedRegions, lgv, theme } =
|
|
126
|
-
display
|
|
127
|
-
if (!apolloHover) {
|
|
128
|
-
return
|
|
129
|
-
}
|
|
130
|
-
const { feature, mousePosition } = apolloHover
|
|
131
|
-
if (!(feature && mousePosition)) {
|
|
132
|
-
return
|
|
133
|
-
}
|
|
134
|
-
const { regionNumber, y } = mousePosition
|
|
135
|
-
const displayedRegion = displayedRegions[regionNumber]
|
|
136
|
-
const { refName, reversed } = displayedRegion
|
|
137
|
-
const { bpPerPx, bpToPx, offsetPx } = lgv
|
|
138
|
-
|
|
139
|
-
const { discontinuousLocations } = feature
|
|
140
|
-
let start: number, end: number, length: number
|
|
141
|
-
let location = 'Loc: '
|
|
142
|
-
if (discontinuousLocations && discontinuousLocations.length > 0) {
|
|
143
|
-
const lastLoc = discontinuousLocations.at(-1)
|
|
144
|
-
if (!lastLoc) {
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
;({ start } = lastLoc)
|
|
148
|
-
;({ end } = lastLoc)
|
|
149
|
-
length = lastLoc.end - lastLoc.start
|
|
150
|
-
|
|
151
|
-
if (discontinuousLocations.length <= 2) {
|
|
152
|
-
for (const [i, loc] of discontinuousLocations.entries()) {
|
|
153
|
-
location += `${loc.start + 1}–${loc.end}`
|
|
154
|
-
if (i !== discontinuousLocations.length - 1) {
|
|
155
|
-
location += ','
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
const [firstLoc] = discontinuousLocations
|
|
160
|
-
location += `${firstLoc.start + 1}–${firstLoc.end},…,${
|
|
161
|
-
lastLoc.start + 1
|
|
162
|
-
}–${lastLoc.end}`
|
|
163
|
-
}
|
|
164
|
-
} else {
|
|
165
|
-
;({ end, length, start } = feature)
|
|
166
|
-
location += `${start + 1}–${end}`
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
let startPx =
|
|
170
|
-
(bpToPx({ refName, coord: reversed ? end : start, regionNumber })
|
|
171
|
-
?.offsetPx ?? 0) - offsetPx
|
|
172
|
-
const row = Math.floor(y / apolloRowHeight)
|
|
173
|
-
const top = row * apolloRowHeight
|
|
174
|
-
const widthPx = length / bpPerPx
|
|
175
|
-
|
|
176
|
-
const featureType = `Type: ${feature.type}`
|
|
177
|
-
const { attributes } = feature
|
|
178
|
-
const featureName = attributes.get('gff_name')?.find((name) => name !== '')
|
|
179
|
-
const textWidth = [
|
|
180
|
-
context.measureText(featureType).width,
|
|
181
|
-
context.measureText(location).width,
|
|
182
|
-
]
|
|
183
|
-
if (featureName) {
|
|
184
|
-
textWidth.push(context.measureText(`Name: ${featureName}`).width)
|
|
185
|
-
}
|
|
186
|
-
const maxWidth = Math.max(...textWidth)
|
|
187
|
-
|
|
188
|
-
startPx = startPx + widthPx + 5
|
|
189
|
-
context.fillStyle = alpha(
|
|
190
|
-
theme?.palette.text.primary ?? 'rgb(1, 1, 1)',
|
|
191
|
-
0.7,
|
|
192
|
-
)
|
|
193
|
-
context.fillRect(
|
|
194
|
-
startPx,
|
|
195
|
-
top,
|
|
196
|
-
maxWidth + 4,
|
|
197
|
-
textWidth.length === 3 ? 45 : 35,
|
|
198
|
-
)
|
|
199
|
-
context.beginPath()
|
|
200
|
-
context.moveTo(startPx, top)
|
|
201
|
-
context.lineTo(startPx - 5, top + 5)
|
|
202
|
-
context.lineTo(startPx, top + 10)
|
|
203
|
-
context.fill()
|
|
204
|
-
context.fillStyle =
|
|
205
|
-
theme?.palette.background.default ?? 'rgba(255, 255, 255)'
|
|
206
|
-
let textTop = top + 12
|
|
207
|
-
context.fillText(featureType, startPx + 2, textTop)
|
|
208
|
-
if (featureName) {
|
|
209
|
-
textTop = textTop + 12
|
|
210
|
-
context.fillText(`Name: ${featureName}`, startPx + 2, textTop)
|
|
211
|
-
}
|
|
212
|
-
textTop = textTop + 12
|
|
213
|
-
context.fillText(location, startPx + 2, textTop)
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
getAdjacentFeatures(
|
|
217
|
-
feature?: AnnotationFeatureI,
|
|
218
|
-
parentFeature?: AnnotationFeatureI,
|
|
219
|
-
): {
|
|
220
|
-
prevFeature?: AnnotationFeatureI
|
|
221
|
-
nextFeature?: AnnotationFeatureI
|
|
222
|
-
} {
|
|
223
|
-
let prevFeature: AnnotationFeatureI | undefined
|
|
224
|
-
let nextFeature: AnnotationFeatureI | undefined
|
|
225
|
-
let i = 0
|
|
226
|
-
if (!feature || !(parentFeature && parentFeature.children)) {
|
|
227
|
-
return { prevFeature, nextFeature }
|
|
228
|
-
}
|
|
229
|
-
for (const [, f] of parentFeature.children) {
|
|
230
|
-
if (f._id === feature._id) {
|
|
231
|
-
break
|
|
232
|
-
}
|
|
233
|
-
i++
|
|
234
|
-
}
|
|
235
|
-
const keys = [...parentFeature.children.keys()]
|
|
236
|
-
if (i > 0) {
|
|
237
|
-
const key = keys[i - 1]
|
|
238
|
-
prevFeature = parentFeature.children.get(key)
|
|
239
|
-
}
|
|
240
|
-
if (i < keys.length - 1) {
|
|
241
|
-
const key = keys[i + 1]
|
|
242
|
-
nextFeature = parentFeature.children.get(key)
|
|
243
|
-
}
|
|
244
|
-
return { prevFeature, nextFeature }
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
getParentFeature(
|
|
248
|
-
feature?: AnnotationFeatureI,
|
|
249
|
-
topLevelFeature?: AnnotationFeatureI,
|
|
250
|
-
) {
|
|
251
|
-
let parentFeature
|
|
252
|
-
|
|
253
|
-
if (!feature || !(topLevelFeature && topLevelFeature.children)) {
|
|
254
|
-
return parentFeature
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
for (const [, f] of topLevelFeature.children) {
|
|
258
|
-
if (f._id === feature._id) {
|
|
259
|
-
parentFeature = topLevelFeature
|
|
260
|
-
break
|
|
261
|
-
}
|
|
262
|
-
if (!f?.children) {
|
|
263
|
-
continue
|
|
264
|
-
}
|
|
265
|
-
for (const [, cf] of f.children) {
|
|
266
|
-
if (cf._id === feature._id) {
|
|
267
|
-
parentFeature = f
|
|
268
|
-
break
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
if (parentFeature) {
|
|
272
|
-
break
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
return parentFeature
|
|
276
|
-
}
|
|
70
|
+
): void
|
|
277
71
|
|
|
278
|
-
getContextMenuItems(display: LinearApolloDisplayMouseEvents): MenuItem[]
|
|
279
|
-
const {
|
|
280
|
-
apolloHover,
|
|
281
|
-
apolloInternetAccount: internetAccount,
|
|
282
|
-
changeManager,
|
|
283
|
-
getAssemblyId,
|
|
284
|
-
regions,
|
|
285
|
-
selectedFeature,
|
|
286
|
-
session,
|
|
287
|
-
setSelectedFeature,
|
|
288
|
-
} = display
|
|
289
|
-
const { feature: sourceFeature } = apolloHover ?? {}
|
|
290
|
-
const role = internetAccount ? internetAccount.role : 'admin'
|
|
291
|
-
const admin = role === 'admin'
|
|
292
|
-
const readOnly = !(role && ['admin', 'user'].includes(role))
|
|
293
|
-
const menuItems: MenuItem[] = []
|
|
294
|
-
if (sourceFeature) {
|
|
295
|
-
const [region] = regions
|
|
296
|
-
const sourceAssemblyId = getAssemblyId(region.assemblyName)
|
|
297
|
-
const currentAssemblyId = getAssemblyId(region.assemblyName)
|
|
298
|
-
menuItems.push(
|
|
299
|
-
{
|
|
300
|
-
label: 'Add child feature',
|
|
301
|
-
disabled: readOnly,
|
|
302
|
-
onClick: () => {
|
|
303
|
-
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
304
|
-
(doneCallback) => [
|
|
305
|
-
AddChildFeature,
|
|
306
|
-
{
|
|
307
|
-
session,
|
|
308
|
-
handleClose: () => {
|
|
309
|
-
doneCallback()
|
|
310
|
-
},
|
|
311
|
-
changeManager,
|
|
312
|
-
sourceFeature,
|
|
313
|
-
sourceAssemblyId,
|
|
314
|
-
internetAccount,
|
|
315
|
-
},
|
|
316
|
-
],
|
|
317
|
-
)
|
|
318
|
-
},
|
|
319
|
-
},
|
|
320
|
-
{
|
|
321
|
-
label: 'Copy features and annotations',
|
|
322
|
-
disabled: readOnly,
|
|
323
|
-
onClick: () => {
|
|
324
|
-
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
325
|
-
(doneCallback) => [
|
|
326
|
-
CopyFeature,
|
|
327
|
-
{
|
|
328
|
-
session,
|
|
329
|
-
handleClose: () => {
|
|
330
|
-
doneCallback()
|
|
331
|
-
},
|
|
332
|
-
changeManager,
|
|
333
|
-
sourceFeature,
|
|
334
|
-
sourceAssemblyId: currentAssemblyId,
|
|
335
|
-
},
|
|
336
|
-
],
|
|
337
|
-
)
|
|
338
|
-
},
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
label: 'Delete feature',
|
|
342
|
-
disabled: !admin,
|
|
343
|
-
onClick: () => {
|
|
344
|
-
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
345
|
-
(doneCallback) => [
|
|
346
|
-
DeleteFeature,
|
|
347
|
-
{
|
|
348
|
-
session,
|
|
349
|
-
handleClose: () => {
|
|
350
|
-
doneCallback()
|
|
351
|
-
},
|
|
352
|
-
changeManager,
|
|
353
|
-
sourceFeature,
|
|
354
|
-
sourceAssemblyId: currentAssemblyId,
|
|
355
|
-
selectedFeature,
|
|
356
|
-
setSelectedFeature,
|
|
357
|
-
},
|
|
358
|
-
],
|
|
359
|
-
)
|
|
360
|
-
},
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
label: 'Modify feature attribute',
|
|
364
|
-
disabled: readOnly,
|
|
365
|
-
onClick: () => {
|
|
366
|
-
;(session as unknown as AbstractSessionModel).queueDialog(
|
|
367
|
-
(doneCallback) => [
|
|
368
|
-
ModifyFeatureAttribute,
|
|
369
|
-
{
|
|
370
|
-
session,
|
|
371
|
-
handleClose: () => {
|
|
372
|
-
doneCallback()
|
|
373
|
-
},
|
|
374
|
-
changeManager,
|
|
375
|
-
sourceFeature,
|
|
376
|
-
sourceAssemblyId: currentAssemblyId,
|
|
377
|
-
},
|
|
378
|
-
],
|
|
379
|
-
)
|
|
380
|
-
},
|
|
381
|
-
},
|
|
382
|
-
{
|
|
383
|
-
label: 'Edit feature details',
|
|
384
|
-
onClick: () => {
|
|
385
|
-
const apolloFeatureWidget = (
|
|
386
|
-
session as unknown as SessionWithWidgets
|
|
387
|
-
).addWidget(
|
|
388
|
-
'ApolloFeatureDetailsWidget',
|
|
389
|
-
'apolloFeatureDetailsWidget',
|
|
390
|
-
{
|
|
391
|
-
feature: sourceFeature,
|
|
392
|
-
assembly: currentAssemblyId,
|
|
393
|
-
refName: region.refName,
|
|
394
|
-
},
|
|
395
|
-
)
|
|
396
|
-
;(session as unknown as SessionWithWidgets).showWidget(
|
|
397
|
-
apolloFeatureWidget,
|
|
398
|
-
)
|
|
399
|
-
},
|
|
400
|
-
},
|
|
401
|
-
)
|
|
402
|
-
}
|
|
403
|
-
return menuItems
|
|
404
|
-
}
|
|
72
|
+
getContextMenuItems(display: LinearApolloDisplayMouseEvents): MenuItem[]
|
|
405
73
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
4
4
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
5
5
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
6
|
-
import {
|
|
6
|
+
import { AnnotationFeature } from '@apollo-annotation/mst'
|
|
7
7
|
import { ConfigurationReference, getConf } from '@jbrowse/core/configuration'
|
|
8
8
|
import { AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
|
|
9
9
|
import { BaseDisplay } from '@jbrowse/core/pluggableElementTypes'
|
|
@@ -75,9 +75,6 @@ export function baseModelFactory(
|
|
|
75
75
|
)
|
|
76
76
|
return regions
|
|
77
77
|
},
|
|
78
|
-
get displayedRegions() {
|
|
79
|
-
return self.lgv.displayedRegions
|
|
80
|
-
},
|
|
81
78
|
regionCannotBeRendered(/* region */) {
|
|
82
79
|
if (self.lgv && self.lgv.bpPerPx >= 200) {
|
|
83
80
|
return 'Zoom in to see annotations'
|
|
@@ -117,13 +114,13 @@ export function baseModelFactory(
|
|
|
117
114
|
}
|
|
118
115
|
return assembly.name
|
|
119
116
|
},
|
|
120
|
-
get selectedFeature():
|
|
117
|
+
get selectedFeature(): AnnotationFeature | undefined {
|
|
121
118
|
return (self.session as unknown as ApolloSessionModel)
|
|
122
119
|
.apolloSelectedFeature
|
|
123
120
|
},
|
|
124
121
|
}))
|
|
125
122
|
.actions((self) => ({
|
|
126
|
-
setSelectedFeature(feature?:
|
|
123
|
+
setSelectedFeature(feature?: AnnotationFeature) {
|
|
127
124
|
;(
|
|
128
125
|
self.session as unknown as ApolloSessionModel
|
|
129
126
|
).apolloSetSelectedFeature(feature)
|
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
import { AnnotationFeatureI } from '@apollo-annotation/mst'
|
|
1
|
+
import { AnnotationFeature } from '@apollo-annotation/mst'
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
BoxGlyph,
|
|
6
|
-
CanonicalGeneGlyph,
|
|
7
|
-
GenericChildGlyph,
|
|
8
|
-
ImplicitExonGeneGlyph,
|
|
9
|
-
} from '../glyphs'
|
|
3
|
+
import { boxGlyph, geneGlyph, genericChildGlyph } from '../glyphs'
|
|
10
4
|
import { Glyph } from '../glyphs/Glyph'
|
|
11
5
|
|
|
12
|
-
const boxGlyph = new BoxGlyph()
|
|
13
|
-
const canonicalGeneGlyph = new CanonicalGeneGlyph()
|
|
14
|
-
const genericChildGlyph = new GenericChildGlyph()
|
|
15
|
-
const implicitExonGeneGlyph = new ImplicitExonGeneGlyph()
|
|
16
|
-
|
|
17
6
|
/** get the appropriate glyph for the given top-level feature */
|
|
18
|
-
export function getGlyph(feature:
|
|
19
|
-
if (feature
|
|
20
|
-
|
|
21
|
-
for (const [, mrna] of feature.children ?? new Map()) {
|
|
22
|
-
if (mrna.type !== 'mRNA') {
|
|
23
|
-
continue
|
|
24
|
-
}
|
|
25
|
-
for (const [, possibleExon] of mrna.children ?? new Map()) {
|
|
26
|
-
if (possibleExon.type === 'exon') {
|
|
27
|
-
hasExon = true
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (hasExon) {
|
|
32
|
-
return canonicalGeneGlyph
|
|
33
|
-
}
|
|
34
|
-
return implicitExonGeneGlyph
|
|
7
|
+
export function getGlyph(feature: AnnotationFeature): Glyph {
|
|
8
|
+
if (looksLikeGene(feature)) {
|
|
9
|
+
return geneGlyph
|
|
35
10
|
}
|
|
36
11
|
if (feature.children?.size) {
|
|
37
12
|
return genericChildGlyph
|
|
38
13
|
}
|
|
39
14
|
return boxGlyph
|
|
40
15
|
}
|
|
16
|
+
|
|
17
|
+
function looksLikeGene(feature: AnnotationFeature) {
|
|
18
|
+
const { children } = feature
|
|
19
|
+
if (!children?.size) {
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
for (const [, child] of children) {
|
|
23
|
+
if (child.type === 'mRNA') {
|
|
24
|
+
const { children: grandChildren } = child
|
|
25
|
+
if (!grandChildren?.size) {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
const hasCDS = [...grandChildren.values()].some(
|
|
29
|
+
(grandchild) => grandchild.type === 'CDS',
|
|
30
|
+
)
|
|
31
|
+
const hasExon = [...grandChildren.values()].some(
|
|
32
|
+
(grandchild) => grandchild.type === 'exon',
|
|
33
|
+
)
|
|
34
|
+
if (hasCDS && hasExon) {
|
|
35
|
+
return true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
@@ -17,4 +17,8 @@ export function stateModelFactory(
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export type LinearApolloDisplayStateModel = ReturnType<typeof stateModelFactory>
|
|
20
|
-
|
|
20
|
+
// eslint disable because of
|
|
21
|
+
// https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
23
|
+
export interface LinearApolloDisplay
|
|
24
|
+
extends Instance<LinearApolloDisplayStateModel> {}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { AnnotationFeatureI } from '@apollo-annotation/mst'
|
|
2
|
+
|
|
3
|
+
import { AnnotationFeature } from '@apollo-annotation/mst'
|
|
5
4
|
import { AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
|
|
6
5
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
7
6
|
import { AbstractSessionModel, doesIntersect2 } from '@jbrowse/core/util'
|
|
@@ -23,13 +22,13 @@ export function layoutsModelFactory(
|
|
|
23
22
|
featuresMinMaxLimit: 500_000,
|
|
24
23
|
})
|
|
25
24
|
.volatile(() => ({
|
|
26
|
-
seenFeatures: observable.map<string,
|
|
25
|
+
seenFeatures: observable.map<string, AnnotationFeature>(),
|
|
27
26
|
}))
|
|
28
27
|
.views((self) => ({
|
|
29
28
|
get featuresMinMax() {
|
|
30
29
|
const { assemblyManager } =
|
|
31
30
|
self.session as unknown as AbstractSessionModel
|
|
32
|
-
return self.displayedRegions.map((region) => {
|
|
31
|
+
return self.lgv.displayedRegions.map((region) => {
|
|
33
32
|
const assembly = assemblyManager.get(region.assemblyName)
|
|
34
33
|
let min: number | undefined
|
|
35
34
|
let max: number | undefined
|
|
@@ -48,10 +47,10 @@ export function layoutsModelFactory(
|
|
|
48
47
|
if (max === undefined) {
|
|
49
48
|
;({ max } = feature)
|
|
50
49
|
}
|
|
51
|
-
if (feature.
|
|
50
|
+
if (feature.minWithChildren < min) {
|
|
52
51
|
;({ min } = feature)
|
|
53
52
|
}
|
|
54
|
-
if (feature.
|
|
53
|
+
if (feature.maxWithChildren > max) {
|
|
55
54
|
;({ max } = feature)
|
|
56
55
|
}
|
|
57
56
|
}
|
|
@@ -63,7 +62,7 @@ export function layoutsModelFactory(
|
|
|
63
62
|
},
|
|
64
63
|
}))
|
|
65
64
|
.actions((self) => ({
|
|
66
|
-
addSeenFeature(feature:
|
|
65
|
+
addSeenFeature(feature: AnnotationFeature) {
|
|
67
66
|
self.seenFeatures.set(feature._id, feature)
|
|
68
67
|
},
|
|
69
68
|
deleteSeenFeature(featureId: string) {
|
|
@@ -74,12 +73,9 @@ export function layoutsModelFactory(
|
|
|
74
73
|
get featureLayouts() {
|
|
75
74
|
const { assemblyManager } =
|
|
76
75
|
self.session as unknown as AbstractSessionModel
|
|
77
|
-
return self.displayedRegions.map((region, idx) => {
|
|
76
|
+
return self.lgv.displayedRegions.map((region, idx) => {
|
|
78
77
|
const assembly = assemblyManager.get(region.assemblyName)
|
|
79
|
-
const featureLayout = new Map<
|
|
80
|
-
number,
|
|
81
|
-
[number, AnnotationFeatureI][]
|
|
82
|
-
>()
|
|
78
|
+
const featureLayout = new Map<number, [number, AnnotationFeature][]>()
|
|
83
79
|
const minMax = self.featuresMinMax[idx]
|
|
84
80
|
if (!minMax) {
|
|
85
81
|
return featureLayout
|
|
@@ -98,7 +94,7 @@ export function layoutsModelFactory(
|
|
|
98
94
|
) {
|
|
99
95
|
continue
|
|
100
96
|
}
|
|
101
|
-
const rowCount = getGlyph(feature
|
|
97
|
+
const rowCount = getGlyph(feature).getRowCount(
|
|
102
98
|
feature,
|
|
103
99
|
self.lgv.bpPerPx,
|
|
104
100
|
)
|
|
@@ -160,9 +156,9 @@ export function layoutsModelFactory(
|
|
|
160
156
|
return featureLayout
|
|
161
157
|
})
|
|
162
158
|
},
|
|
163
|
-
getFeatureLayoutPosition(feature:
|
|
159
|
+
getFeatureLayoutPosition(feature: AnnotationFeature) {
|
|
164
160
|
const { featureLayouts } = this
|
|
165
|
-
for (const layout of featureLayouts) {
|
|
161
|
+
for (const [idx, layout] of featureLayouts.entries()) {
|
|
166
162
|
for (const [layoutRowNum, layoutRow] of layout) {
|
|
167
163
|
for (const [featureRowNum, layoutFeature] of layoutRow) {
|
|
168
164
|
if (featureRowNum !== 0) {
|
|
@@ -171,15 +167,23 @@ export function layoutsModelFactory(
|
|
|
171
167
|
continue
|
|
172
168
|
}
|
|
173
169
|
if (feature._id === layoutFeature._id) {
|
|
174
|
-
return {
|
|
170
|
+
return {
|
|
171
|
+
layoutIndex: idx,
|
|
172
|
+
layoutRow: layoutRowNum,
|
|
173
|
+
featureRow: featureRowNum,
|
|
174
|
+
}
|
|
175
175
|
}
|
|
176
176
|
if (layoutFeature.hasDescendant(feature._id)) {
|
|
177
|
-
const row = getGlyph(
|
|
177
|
+
const row = getGlyph(layoutFeature).getRowForFeature(
|
|
178
178
|
layoutFeature,
|
|
179
|
-
|
|
180
|
-
)
|
|
179
|
+
feature,
|
|
180
|
+
)
|
|
181
181
|
if (row !== undefined) {
|
|
182
|
-
return {
|
|
182
|
+
return {
|
|
183
|
+
layoutIndex: idx,
|
|
184
|
+
layoutRow: layoutRowNum,
|
|
185
|
+
featureRow: row,
|
|
186
|
+
}
|
|
183
187
|
}
|
|
184
188
|
}
|
|
185
189
|
}
|
|
@@ -210,13 +214,17 @@ export function layoutsModelFactory(
|
|
|
210
214
|
self.session as unknown as ApolloSessionModel
|
|
211
215
|
).apolloDataStore.assemblies.get(region.assemblyName)
|
|
212
216
|
const ref = assembly?.getByRefName(region.refName)
|
|
213
|
-
|
|
217
|
+
const features = ref?.features
|
|
218
|
+
if (!features) {
|
|
219
|
+
continue
|
|
220
|
+
}
|
|
221
|
+
for (const [, feature] of features) {
|
|
214
222
|
if (
|
|
215
223
|
doesIntersect2(
|
|
216
224
|
region.start,
|
|
217
225
|
region.end,
|
|
218
|
-
feature.
|
|
219
|
-
feature.
|
|
226
|
+
feature.min,
|
|
227
|
+
feature.max,
|
|
220
228
|
) &&
|
|
221
229
|
!self.seenFeatures.has(feature._id)
|
|
222
230
|
) {
|