@apollo-annotation/jbrowse-plugin-apollo 0.3.4 → 0.3.6
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 +5466 -4490
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +5283 -4318
- 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 +6806 -4088
- 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 +4 -4
- package/src/ApolloInternetAccount/addMenuItems.ts +5 -2
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -0
- package/src/ApolloInternetAccount/components/LoginButtons.tsx +1 -1
- package/src/ApolloInternetAccount/components/LoginIcons.tsx +1 -1
- package/src/ApolloInternetAccount/configSchema.ts +1 -1
- package/src/ApolloInternetAccount/model.ts +11 -10
- package/src/ApolloJobModel.ts +1 -1
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +8 -6
- package/src/ApolloRefNameAliasAdapter/index.ts +2 -2
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +17 -4
- package/src/ApolloSequenceAdapter/index.ts +1 -1
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +8 -7
- package/src/ApolloTextSearchAdapter/index.ts +1 -1
- package/src/BackendDrivers/BackendDriver.ts +7 -7
- package/src/BackendDrivers/CollaborationServerDriver.ts +14 -10
- package/src/BackendDrivers/DesktopFileDriver.ts +11 -10
- package/src/BackendDrivers/InMemoryFileDriver.ts +10 -6
- package/src/ChangeManager.ts +5 -5
- package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +92 -20
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +170 -27
- package/src/FeatureDetailsWidget/AttributeKey.tsx +50 -0
- package/src/FeatureDetailsWidget/AttributeKeySelector.tsx +104 -0
- package/src/FeatureDetailsWidget/Attributes.tsx +213 -320
- package/src/FeatureDetailsWidget/BasicInformation.tsx +8 -9
- package/src/FeatureDetailsWidget/DefaultAttributeEditor.tsx +104 -0
- package/src/FeatureDetailsWidget/DefaultAttributeViewer.tsx +22 -0
- package/src/FeatureDetailsWidget/FeatureDetailsNavigation.tsx +10 -8
- package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -1
- package/src/FeatureDetailsWidget/Sequence.tsx +18 -35
- package/src/FeatureDetailsWidget/StringTextField.tsx +1 -1
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +140 -95
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +600 -0
- package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +54 -0
- package/src/FeatureDetailsWidget/model.ts +8 -3
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +19 -12
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +19 -41
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +44 -22
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +6 -5
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +7 -7
- package/src/LinearApolloDisplay/stateModel/base.ts +52 -10
- package/src/LinearApolloDisplay/stateModel/index.ts +4 -3
- package/src/LinearApolloDisplay/stateModel/layouts.ts +8 -34
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +13 -12
- package/src/LinearApolloDisplay/stateModel/rendering.ts +63 -31
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +221 -0
- package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +40 -0
- package/src/LinearApolloSixFrameDisplay/components/index.ts +2 -0
- package/src/LinearApolloSixFrameDisplay/configSchema.ts +7 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +821 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +63 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/index.ts +1 -0
- package/src/LinearApolloSixFrameDisplay/index.ts +2 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +261 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/index.ts +27 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +236 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +349 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +199 -0
- package/src/LinearApolloSixFrameDisplay/types.ts +1 -0
- package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +10 -1
- package/src/OntologyManager/OntologyStore/fulltext.test.ts +1 -1
- package/src/OntologyManager/OntologyStore/fulltext.ts +8 -3
- package/src/OntologyManager/OntologyStore/index.test.ts +4 -1
- package/src/OntologyManager/OntologyStore/index.ts +19 -14
- package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +6 -5
- package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +11 -5
- package/src/OntologyManager/index.ts +10 -6
- package/src/OntologyManager/util.ts +3 -2
- package/src/TabularEditor/HybridGrid/ChangeHandling.ts +2 -2
- package/src/TabularEditor/HybridGrid/Feature.tsx +9 -8
- package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +1 -1
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +3 -2
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +8 -1
- package/src/TabularEditor/HybridGrid/ToolBar.tsx +15 -13
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +9 -33
- package/src/TabularEditor/TabularEditorPane.tsx +1 -1
- package/src/TabularEditor/model.ts +2 -2
- package/src/TabularEditor/types.ts +5 -2
- package/src/components/AddAssembly.tsx +611 -291
- package/src/components/AddChildFeature.tsx +6 -5
- package/src/components/AddFeature.tsx +211 -38
- package/src/components/AddRefSeqAliases.tsx +14 -12
- package/src/components/CopyFeature.tsx +8 -7
- package/src/components/CreateApolloAnnotation.tsx +154 -46
- package/src/components/DeleteAssembly.tsx +9 -8
- package/src/components/DeleteFeature.tsx +5 -4
- package/src/components/Dialog.tsx +1 -1
- package/src/components/DownloadGFF3.tsx +11 -10
- package/src/components/FilterFeatures.tsx +6 -4
- package/src/components/ImportFeatures.tsx +7 -6
- package/src/components/LogOut.tsx +5 -4
- package/src/components/ManageChecks.tsx +9 -8
- package/src/components/ManageUsers.tsx +11 -10
- package/src/components/OntologyTermAutocomplete.tsx +5 -5
- package/src/components/OntologyTermMultiSelect.tsx +9 -6
- package/src/components/OpenLocalFile.tsx +4 -3
- package/src/components/ViewChangeLog.tsx +7 -6
- package/src/components/ViewCheckResults.tsx +8 -7
- package/src/components/index.ts +0 -1
- package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -0
- package/src/extensions/annotationFromJBrowseFeature.ts +14 -12
- package/src/extensions/annotationFromPileup.ts +6 -6
- package/src/index.ts +33 -50
- package/src/makeDisplayComponent.tsx +93 -41
- package/src/session/ClientDataStore.ts +21 -17
- package/src/session/session.ts +20 -26
- package/src/types.ts +4 -4
- package/src/util/annotationFeatureUtils.ts +53 -0
- package/src/util/index.ts +4 -3
- package/src/util/loadAssemblyIntoClient.ts +10 -3
- package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +0 -13
- package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +0 -707
- package/src/ApolloSixFrameRenderer/configSchema.ts +0 -7
- package/src/ApolloSixFrameRenderer/index.ts +0 -3
- package/src/FeatureDetailsWidget/TranscriptBasic.tsx +0 -200
- package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +0 -19
- package/src/SixFrameFeatureDisplay/components/index.ts +0 -1
- package/src/SixFrameFeatureDisplay/configSchema.ts +0 -21
- package/src/SixFrameFeatureDisplay/index.ts +0 -2
- package/src/SixFrameFeatureDisplay/stateModel.ts +0 -439
- package/src/components/ModifyFeatureAttribute.tsx +0 -460
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AnnotationFeature,
|
|
3
|
+
type TranscriptPartCoding,
|
|
4
|
+
} from '@apollo-annotation/mst'
|
|
5
|
+
import {
|
|
6
|
+
LocationEndChange,
|
|
7
|
+
LocationStartChange,
|
|
8
|
+
} from '@apollo-annotation/shared'
|
|
9
|
+
import type PluginManager from '@jbrowse/core/PluginManager'
|
|
10
|
+
import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
|
|
11
|
+
import { type MenuItem } from '@jbrowse/core/ui'
|
|
12
|
+
import { type LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
13
|
+
import { autorun } from 'mobx'
|
|
14
|
+
import { type Instance, addDisposer } from 'mobx-state-tree'
|
|
15
|
+
import { type CSSProperties } from 'react'
|
|
16
|
+
|
|
17
|
+
import { type Coord } from '../components'
|
|
18
|
+
import { type Glyph } from '../glyphs/Glyph'
|
|
19
|
+
import { type CanvasMouseEvent } from '../types'
|
|
20
|
+
|
|
21
|
+
import { renderingModelFactory } from './rendering'
|
|
22
|
+
|
|
23
|
+
export interface FeatureAndGlyphUnderMouse {
|
|
24
|
+
cds: TranscriptPartCoding | null
|
|
25
|
+
feature: AnnotationFeature
|
|
26
|
+
topLevelFeature: AnnotationFeature
|
|
27
|
+
glyph: Glyph
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** extended information about the position of the mouse on the canvas, including the refName, bp, and displayedRegion number */
|
|
31
|
+
export interface MousePosition {
|
|
32
|
+
x: number
|
|
33
|
+
y: number
|
|
34
|
+
refName: string
|
|
35
|
+
bp: number
|
|
36
|
+
regionNumber: number
|
|
37
|
+
featureAndGlyphUnderMouse?: FeatureAndGlyphUnderMouse
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type MousePositionWithFeatureAndGlyph = Required<MousePosition>
|
|
41
|
+
|
|
42
|
+
export function isMousePositionWithFeatureAndGlyph(
|
|
43
|
+
mousePosition: MousePosition,
|
|
44
|
+
): mousePosition is MousePositionWithFeatureAndGlyph {
|
|
45
|
+
return 'featureAndGlyphUnderMouse' in mousePosition
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getMousePosition(
|
|
49
|
+
event: CanvasMouseEvent,
|
|
50
|
+
lgv: LinearGenomeViewModel,
|
|
51
|
+
): MousePosition {
|
|
52
|
+
const canvas = event.currentTarget
|
|
53
|
+
const { clientX, clientY } = event
|
|
54
|
+
const { left, top } = canvas.getBoundingClientRect()
|
|
55
|
+
const x = clientX - left
|
|
56
|
+
const y = clientY - top
|
|
57
|
+
const { coord: bp, index: regionNumber, refName } = lgv.pxToBp(x)
|
|
58
|
+
return { x, y, refName, bp, regionNumber }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function mouseEventsModelIntermediateFactory(
|
|
62
|
+
pluginManager: PluginManager,
|
|
63
|
+
configSchema: AnyConfigurationSchemaType,
|
|
64
|
+
) {
|
|
65
|
+
const LinearApolloSixFrameDisplayRendering = renderingModelFactory(
|
|
66
|
+
pluginManager,
|
|
67
|
+
configSchema,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
return LinearApolloSixFrameDisplayRendering.named(
|
|
71
|
+
'LinearApolloSixFrameDisplayMouseEvents',
|
|
72
|
+
)
|
|
73
|
+
.volatile(() => ({
|
|
74
|
+
apolloDragging: null as {
|
|
75
|
+
start: MousePosition
|
|
76
|
+
current: MousePosition
|
|
77
|
+
feature: AnnotationFeature
|
|
78
|
+
edge: 'min' | 'max'
|
|
79
|
+
} | null,
|
|
80
|
+
cursor: undefined as CSSProperties['cursor'] | undefined,
|
|
81
|
+
apolloHover: undefined as FeatureAndGlyphUnderMouse | undefined,
|
|
82
|
+
}))
|
|
83
|
+
.views((self) => ({
|
|
84
|
+
getMousePosition(event: CanvasMouseEvent): MousePosition {
|
|
85
|
+
const mousePosition = getMousePosition(event, self.lgv)
|
|
86
|
+
const { bp, regionNumber, y } = mousePosition
|
|
87
|
+
const row = Math.floor(y / self.apolloRowHeight) + 1
|
|
88
|
+
const featureLayout = self.featureLayouts[regionNumber]
|
|
89
|
+
const layoutRow = featureLayout.get(row)
|
|
90
|
+
if (!layoutRow) {
|
|
91
|
+
return mousePosition
|
|
92
|
+
}
|
|
93
|
+
let foundFeature
|
|
94
|
+
if ([4, 5].includes(row)) {
|
|
95
|
+
foundFeature = layoutRow.find(
|
|
96
|
+
(f) =>
|
|
97
|
+
f.feature.type == 'exon' &&
|
|
98
|
+
bp >= f.feature.min &&
|
|
99
|
+
bp <= f.feature.max,
|
|
100
|
+
)
|
|
101
|
+
if (!foundFeature) {
|
|
102
|
+
foundFeature = layoutRow.find(
|
|
103
|
+
(f) => bp >= f.feature.min && bp <= f.feature.max,
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
foundFeature = layoutRow.find(
|
|
108
|
+
(f) => f.cds != null && bp >= f.cds.min && bp <= f.cds.max,
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
if (!foundFeature) {
|
|
112
|
+
return mousePosition
|
|
113
|
+
}
|
|
114
|
+
const { feature, cds } = foundFeature
|
|
115
|
+
const { topLevelFeature } = feature
|
|
116
|
+
const glyph = self.getGlyph(feature)
|
|
117
|
+
return {
|
|
118
|
+
...mousePosition,
|
|
119
|
+
featureAndGlyphUnderMouse: { cds, feature, topLevelFeature, glyph },
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
}))
|
|
123
|
+
.actions((self) => ({
|
|
124
|
+
continueDrag(mousePosition: MousePosition, event: CanvasMouseEvent) {
|
|
125
|
+
if (!self.apolloDragging) {
|
|
126
|
+
throw new Error(
|
|
127
|
+
'continueDrag() called with no current drag in progress',
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
event.stopPropagation()
|
|
131
|
+
self.apolloDragging = { ...self.apolloDragging, current: mousePosition }
|
|
132
|
+
},
|
|
133
|
+
setDragging(dragInfo?: typeof self.apolloDragging) {
|
|
134
|
+
self.apolloDragging = dragInfo ?? null
|
|
135
|
+
},
|
|
136
|
+
}))
|
|
137
|
+
.actions((self) => ({
|
|
138
|
+
setApolloHover(n?: (typeof self)['apolloHover']) {
|
|
139
|
+
self.apolloHover = n
|
|
140
|
+
},
|
|
141
|
+
setCursor(cursor?: CSSProperties['cursor']) {
|
|
142
|
+
if (self.cursor !== cursor) {
|
|
143
|
+
self.cursor = cursor
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
}))
|
|
147
|
+
.actions(() => ({
|
|
148
|
+
// onClick(event: CanvasMouseEvent) {
|
|
149
|
+
onClick() {
|
|
150
|
+
// TODO: set the selected feature
|
|
151
|
+
},
|
|
152
|
+
}))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function mouseEventsModelFactory(
|
|
156
|
+
pluginManager: PluginManager,
|
|
157
|
+
configSchema: AnyConfigurationSchemaType,
|
|
158
|
+
) {
|
|
159
|
+
const LinearApolloSixFrameDisplayMouseEvents =
|
|
160
|
+
mouseEventsModelIntermediateFactory(pluginManager, configSchema)
|
|
161
|
+
|
|
162
|
+
return LinearApolloSixFrameDisplayMouseEvents.views((self) => ({
|
|
163
|
+
contextMenuItems(contextCoord?: Coord): MenuItem[] {
|
|
164
|
+
const { apolloHover } = self
|
|
165
|
+
if (!(apolloHover && contextCoord)) {
|
|
166
|
+
return []
|
|
167
|
+
}
|
|
168
|
+
const { topLevelFeature } = apolloHover
|
|
169
|
+
const glyph = self.getGlyph(topLevelFeature)
|
|
170
|
+
return glyph.getContextMenuItems(self)
|
|
171
|
+
},
|
|
172
|
+
}))
|
|
173
|
+
.actions((self) => ({
|
|
174
|
+
// explicitly pass in a feature in case it's not the same as the one in
|
|
175
|
+
// mousePosition (e.g. if features are drawn overlapping).
|
|
176
|
+
startDrag(
|
|
177
|
+
mousePosition: MousePositionWithFeatureAndGlyph,
|
|
178
|
+
feature: AnnotationFeature,
|
|
179
|
+
edge: 'min' | 'max',
|
|
180
|
+
) {
|
|
181
|
+
self.apolloDragging = {
|
|
182
|
+
start: mousePosition,
|
|
183
|
+
current: mousePosition,
|
|
184
|
+
feature,
|
|
185
|
+
edge,
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
endDrag() {
|
|
189
|
+
if (!self.apolloDragging) {
|
|
190
|
+
throw new Error('endDrag() called with no current drag in progress')
|
|
191
|
+
}
|
|
192
|
+
const { current, edge, feature, start } = self.apolloDragging
|
|
193
|
+
// don't do anything if it was only dragged a tiny bit
|
|
194
|
+
if (Math.abs(current.x - start.x) <= 4) {
|
|
195
|
+
self.setDragging()
|
|
196
|
+
self.setCursor()
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
const { displayedRegions } = self.lgv
|
|
200
|
+
const region = displayedRegions[start.regionNumber]
|
|
201
|
+
const assembly = self.getAssemblyId(region.assemblyName)
|
|
202
|
+
|
|
203
|
+
let change: LocationEndChange | LocationStartChange
|
|
204
|
+
if (edge === 'max') {
|
|
205
|
+
const featureId = feature._id
|
|
206
|
+
const oldEnd = feature.max
|
|
207
|
+
const newEnd = current.bp
|
|
208
|
+
change = new LocationEndChange({
|
|
209
|
+
typeName: 'LocationEndChange',
|
|
210
|
+
changedIds: [featureId],
|
|
211
|
+
featureId,
|
|
212
|
+
oldEnd,
|
|
213
|
+
newEnd,
|
|
214
|
+
assembly,
|
|
215
|
+
})
|
|
216
|
+
} else {
|
|
217
|
+
const featureId = feature._id
|
|
218
|
+
const oldStart = feature.min
|
|
219
|
+
const newStart = current.bp
|
|
220
|
+
change = new LocationStartChange({
|
|
221
|
+
typeName: 'LocationStartChange',
|
|
222
|
+
changedIds: [featureId],
|
|
223
|
+
featureId,
|
|
224
|
+
oldStart,
|
|
225
|
+
newStart,
|
|
226
|
+
assembly,
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
void self.changeManager.submit(change)
|
|
230
|
+
self.setDragging()
|
|
231
|
+
self.setCursor()
|
|
232
|
+
},
|
|
233
|
+
}))
|
|
234
|
+
.actions((self) => ({
|
|
235
|
+
onMouseDown(event: CanvasMouseEvent) {
|
|
236
|
+
const mousePosition = self.getMousePosition(event)
|
|
237
|
+
if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
|
|
238
|
+
mousePosition.featureAndGlyphUnderMouse.glyph.onMouseDown(
|
|
239
|
+
self,
|
|
240
|
+
mousePosition,
|
|
241
|
+
event,
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
onMouseMove(event: CanvasMouseEvent) {
|
|
246
|
+
const mousePosition = self.getMousePosition(event)
|
|
247
|
+
if (self.apolloDragging) {
|
|
248
|
+
self.setCursor('col-resize')
|
|
249
|
+
self.continueDrag(mousePosition, event)
|
|
250
|
+
return
|
|
251
|
+
}
|
|
252
|
+
if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
|
|
253
|
+
mousePosition.featureAndGlyphUnderMouse.glyph.onMouseMove(
|
|
254
|
+
self,
|
|
255
|
+
mousePosition,
|
|
256
|
+
event,
|
|
257
|
+
)
|
|
258
|
+
} else {
|
|
259
|
+
self.setApolloHover()
|
|
260
|
+
self.setCursor()
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
onMouseLeave(event: CanvasMouseEvent) {
|
|
264
|
+
self.setDragging()
|
|
265
|
+
self.setApolloHover()
|
|
266
|
+
|
|
267
|
+
const mousePosition = self.getMousePosition(event)
|
|
268
|
+
if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
|
|
269
|
+
mousePosition.featureAndGlyphUnderMouse.glyph.onMouseLeave(
|
|
270
|
+
self,
|
|
271
|
+
mousePosition,
|
|
272
|
+
event,
|
|
273
|
+
)
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
onMouseUp(event: CanvasMouseEvent) {
|
|
277
|
+
const mousePosition = self.getMousePosition(event)
|
|
278
|
+
if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
|
|
279
|
+
mousePosition.featureAndGlyphUnderMouse.glyph.onMouseUp(
|
|
280
|
+
self,
|
|
281
|
+
mousePosition,
|
|
282
|
+
event,
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (self.apolloDragging) {
|
|
287
|
+
self.endDrag()
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
}))
|
|
291
|
+
.actions((self) => ({
|
|
292
|
+
afterAttach() {
|
|
293
|
+
addDisposer(
|
|
294
|
+
self,
|
|
295
|
+
autorun(
|
|
296
|
+
() => {
|
|
297
|
+
// This type is wrong in @jbrowse/core
|
|
298
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
299
|
+
if (!self.lgv.initialized || self.regionCannotBeRendered()) {
|
|
300
|
+
return
|
|
301
|
+
}
|
|
302
|
+
const ctx = self.overlayCanvas?.getContext('2d')
|
|
303
|
+
if (!ctx) {
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
ctx.clearRect(
|
|
307
|
+
0,
|
|
308
|
+
0,
|
|
309
|
+
self.lgv.dynamicBlocks.totalWidthPx,
|
|
310
|
+
self.featuresHeight,
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
const { apolloDragging, apolloHover } = self
|
|
314
|
+
if (!apolloHover) {
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
const { glyph } = apolloHover
|
|
318
|
+
|
|
319
|
+
// draw mouseover hovers
|
|
320
|
+
glyph.drawHover(self, ctx)
|
|
321
|
+
|
|
322
|
+
// draw tooltip on hover
|
|
323
|
+
glyph.drawTooltip(self, ctx)
|
|
324
|
+
|
|
325
|
+
// dragging previews
|
|
326
|
+
if (apolloDragging) {
|
|
327
|
+
// NOTE: the glyph where the drag started is responsible for drawing the preview.
|
|
328
|
+
// it can call methods in other glyphs to help with this though.
|
|
329
|
+
const glyph = self.getGlyph(
|
|
330
|
+
apolloDragging.feature.topLevelFeature,
|
|
331
|
+
)
|
|
332
|
+
glyph.drawDragPreview(self, ctx)
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
{ name: 'LinearApolloSixFrameDisplayRenderMouseoverAndDrag' },
|
|
336
|
+
),
|
|
337
|
+
)
|
|
338
|
+
},
|
|
339
|
+
}))
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export type LinearApolloSixFrameDisplayMouseEventsModel = ReturnType<
|
|
343
|
+
typeof mouseEventsModelIntermediateFactory
|
|
344
|
+
>
|
|
345
|
+
// eslint disable because of
|
|
346
|
+
// https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time
|
|
347
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
348
|
+
export interface LinearApolloSixFrameDisplayMouseEvents
|
|
349
|
+
extends Instance<LinearApolloSixFrameDisplayMouseEventsModel> {}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
2
|
+
import type PluginManager from '@jbrowse/core/PluginManager'
|
|
3
|
+
import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
|
|
4
|
+
import { doesIntersect2 } from '@jbrowse/core/util'
|
|
5
|
+
import { type Theme } from '@mui/material'
|
|
6
|
+
import { autorun } from 'mobx'
|
|
7
|
+
import { type Instance, addDisposer } from 'mobx-state-tree'
|
|
8
|
+
|
|
9
|
+
import { type ApolloSessionModel } from '../../session'
|
|
10
|
+
|
|
11
|
+
import { layoutsModelFactory } from './layouts'
|
|
12
|
+
|
|
13
|
+
export function renderingModelIntermediateFactory(
|
|
14
|
+
pluginManager: PluginManager,
|
|
15
|
+
configSchema: AnyConfigurationSchemaType,
|
|
16
|
+
) {
|
|
17
|
+
const LinearApolloSixFrameDisplayLayouts = layoutsModelFactory(
|
|
18
|
+
pluginManager,
|
|
19
|
+
configSchema,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
return LinearApolloSixFrameDisplayLayouts.named(
|
|
23
|
+
'LinearApolloSixFrameDisplayRendering',
|
|
24
|
+
)
|
|
25
|
+
.props({
|
|
26
|
+
sequenceRowHeight: 15,
|
|
27
|
+
apolloRowHeight: 20,
|
|
28
|
+
detailsMinHeight: 200,
|
|
29
|
+
detailsHeight: 200,
|
|
30
|
+
lastRowTooltipBufferHeight: 80,
|
|
31
|
+
isShown: true,
|
|
32
|
+
})
|
|
33
|
+
.volatile(() => ({
|
|
34
|
+
canvas: null as HTMLCanvasElement | null,
|
|
35
|
+
overlayCanvas: null as HTMLCanvasElement | null,
|
|
36
|
+
collaboratorCanvas: null as HTMLCanvasElement | null,
|
|
37
|
+
theme: undefined as Theme | undefined,
|
|
38
|
+
}))
|
|
39
|
+
.views((self) => ({
|
|
40
|
+
get featuresHeight() {
|
|
41
|
+
return (
|
|
42
|
+
(self.highestRow + 1) * self.apolloRowHeight +
|
|
43
|
+
self.lastRowTooltipBufferHeight
|
|
44
|
+
)
|
|
45
|
+
},
|
|
46
|
+
}))
|
|
47
|
+
.actions((self) => ({
|
|
48
|
+
toggleShown() {
|
|
49
|
+
self.isShown = !self.isShown
|
|
50
|
+
},
|
|
51
|
+
setDetailsHeight(newHeight: number) {
|
|
52
|
+
self.detailsHeight = self.isShown
|
|
53
|
+
? Math.max(
|
|
54
|
+
Math.min(newHeight, self.height - 100),
|
|
55
|
+
Math.min(self.height, self.detailsMinHeight),
|
|
56
|
+
)
|
|
57
|
+
: newHeight
|
|
58
|
+
},
|
|
59
|
+
setCanvas(canvas: HTMLCanvasElement | null) {
|
|
60
|
+
self.canvas = canvas
|
|
61
|
+
},
|
|
62
|
+
setOverlayCanvas(canvas: HTMLCanvasElement | null) {
|
|
63
|
+
self.overlayCanvas = canvas
|
|
64
|
+
},
|
|
65
|
+
setCollaboratorCanvas(canvas: HTMLCanvasElement | null) {
|
|
66
|
+
self.collaboratorCanvas = canvas
|
|
67
|
+
},
|
|
68
|
+
setTheme(theme: Theme) {
|
|
69
|
+
self.theme = theme
|
|
70
|
+
},
|
|
71
|
+
afterAttach() {
|
|
72
|
+
addDisposer(
|
|
73
|
+
self,
|
|
74
|
+
autorun(
|
|
75
|
+
() => {
|
|
76
|
+
if (!self.lgv.initialized || self.regionCannotBeRendered()) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
const ctx = self.collaboratorCanvas?.getContext('2d')
|
|
80
|
+
if (!ctx) {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
ctx.clearRect(
|
|
84
|
+
0,
|
|
85
|
+
0,
|
|
86
|
+
self.lgv.dynamicBlocks.totalWidthPx,
|
|
87
|
+
self.featuresHeight,
|
|
88
|
+
)
|
|
89
|
+
for (const collaborator of (
|
|
90
|
+
self.session as unknown as ApolloSessionModel
|
|
91
|
+
).collaborators) {
|
|
92
|
+
const { locations } = collaborator
|
|
93
|
+
if (locations.length === 0) {
|
|
94
|
+
continue
|
|
95
|
+
}
|
|
96
|
+
let idx = 0
|
|
97
|
+
for (const displayedRegion of self.lgv.displayedRegions) {
|
|
98
|
+
for (const location of locations) {
|
|
99
|
+
if (location.refSeq !== displayedRegion.refName) {
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
const { end, refSeq, start } = location
|
|
103
|
+
const locationStartPxInfo = self.lgv.bpToPx({
|
|
104
|
+
refName: refSeq,
|
|
105
|
+
coord: start,
|
|
106
|
+
regionNumber: idx,
|
|
107
|
+
})
|
|
108
|
+
if (!locationStartPxInfo) {
|
|
109
|
+
continue
|
|
110
|
+
}
|
|
111
|
+
const locationStartPx =
|
|
112
|
+
locationStartPxInfo.offsetPx - self.lgv.offsetPx
|
|
113
|
+
const locationWidthPx = (end - start) / self.lgv.bpPerPx
|
|
114
|
+
ctx.fillStyle = 'rgba(0,255,0,.2)'
|
|
115
|
+
ctx.fillRect(locationStartPx, 1, locationWidthPx, 100)
|
|
116
|
+
ctx.fillStyle = 'black'
|
|
117
|
+
ctx.fillText(
|
|
118
|
+
collaborator.name,
|
|
119
|
+
locationStartPx + 1,
|
|
120
|
+
11,
|
|
121
|
+
locationWidthPx - 2,
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
idx++
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{ name: 'LinearApolloSixFrameDisplayRenderCollaborators' },
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
},
|
|
132
|
+
}))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function renderingModelFactory(
|
|
136
|
+
pluginManager: PluginManager,
|
|
137
|
+
configSchema: AnyConfigurationSchemaType,
|
|
138
|
+
) {
|
|
139
|
+
const LinearApolloSixFrameDisplayRendering =
|
|
140
|
+
renderingModelIntermediateFactory(pluginManager, configSchema)
|
|
141
|
+
|
|
142
|
+
return LinearApolloSixFrameDisplayRendering.actions((self) => ({
|
|
143
|
+
afterAttach() {
|
|
144
|
+
addDisposer(
|
|
145
|
+
self,
|
|
146
|
+
autorun(
|
|
147
|
+
() => {
|
|
148
|
+
const { canvas, featureLayouts, featuresHeight, lgv } = self
|
|
149
|
+
if (!lgv.initialized || self.regionCannotBeRendered()) {
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
const { displayedRegions, dynamicBlocks } = lgv
|
|
153
|
+
|
|
154
|
+
const ctx = canvas?.getContext('2d')
|
|
155
|
+
if (!ctx) {
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
ctx.clearRect(0, 0, dynamicBlocks.totalWidthPx, featuresHeight)
|
|
159
|
+
for (const [idx, featureLayout] of featureLayouts.entries()) {
|
|
160
|
+
const displayedRegion = displayedRegions[idx]
|
|
161
|
+
for (const [row, featureLayoutRow] of featureLayout.entries()) {
|
|
162
|
+
for (const { feature } of featureLayoutRow) {
|
|
163
|
+
if (!feature.looksLikeGene) {
|
|
164
|
+
continue
|
|
165
|
+
}
|
|
166
|
+
if (
|
|
167
|
+
!doesIntersect2(
|
|
168
|
+
displayedRegion.start,
|
|
169
|
+
displayedRegion.end,
|
|
170
|
+
feature.min,
|
|
171
|
+
feature.max,
|
|
172
|
+
)
|
|
173
|
+
) {
|
|
174
|
+
continue
|
|
175
|
+
}
|
|
176
|
+
const { topLevelFeature } = feature
|
|
177
|
+
const glyph = self.getGlyph(topLevelFeature)
|
|
178
|
+
if (glyph !== undefined) {
|
|
179
|
+
glyph.draw(ctx, topLevelFeature, row, self, idx)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
{ name: 'LinearApolloSixFrameDisplayRenderFeatures' },
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
},
|
|
189
|
+
}))
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export type LinearApolloSixFrameDisplayRenderingModel = ReturnType<
|
|
193
|
+
typeof renderingModelIntermediateFactory
|
|
194
|
+
>
|
|
195
|
+
// eslint disable because of
|
|
196
|
+
// https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
198
|
+
export interface LinearApolloSixFrameDisplayRendering
|
|
199
|
+
extends Instance<LinearApolloSixFrameDisplayRenderingModel> {}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type CanvasMouseEvent = React.MouseEvent<HTMLCanvasElement>
|
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
import { checkAbortSignal } from '@jbrowse/core/util/aborting'
|
|
6
6
|
import jsonpath from 'jsonpath'
|
|
7
7
|
|
|
8
|
+
import { type TextIndexFieldDefinition } from '..'
|
|
9
|
+
|
|
8
10
|
import { stopwords } from './fulltext-stopwords'
|
|
9
|
-
import { OntologyDBNode } from './indexeddb-schema'
|
|
11
|
+
import { type OntologyDBNode } from './indexeddb-schema'
|
|
10
12
|
import { applyPrefixes } from './prefixes'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
|
|
14
|
+
// eslint-disable-next-line import/no-duplicates
|
|
15
|
+
import type OntologyStore from '.'
|
|
16
|
+
// eslint-disable-next-line import/no-duplicates
|
|
17
|
+
import { type Transaction } from '.'
|
|
13
18
|
|
|
14
19
|
/** special value of jsonPath that gets the IRI (that is, ID) of the node with the configured prefixes applied */
|
|
15
20
|
export const PREFIXED_ID_PATH = '$PREFIXED_ID'
|
|
@@ -4,8 +4,9 @@ import path from 'node:path'
|
|
|
4
4
|
|
|
5
5
|
import { beforeAll, describe, expect, it, jest } from '@jest/globals'
|
|
6
6
|
|
|
7
|
+
import { type OntologyClass, isOntologyClass } from '..'
|
|
8
|
+
|
|
7
9
|
import OntologyStore from '.'
|
|
8
|
-
import { OntologyClass, isOntologyClass } from '..'
|
|
9
10
|
|
|
10
11
|
jest.setTimeout(1_000_000_000)
|
|
11
12
|
|
|
@@ -19,12 +20,14 @@ const prefixes = new Map([
|
|
|
19
20
|
// different "Object". This intercepts calls to "query" in this test and makes
|
|
20
21
|
// sure the main scope "Object" is used.
|
|
21
22
|
jest.mock('jsonpath', () => {
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
22
24
|
const original = jest.requireActual<typeof import('jsonpath')>('jsonpath')
|
|
23
25
|
return {
|
|
24
26
|
...original,
|
|
25
27
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
28
|
query: jest.fn((obj: any, pathExpression: string, count?: number) => {
|
|
27
29
|
const newObj =
|
|
30
|
+
// eslint-disable-next-line unicorn/prefer-structured-clone
|
|
28
31
|
obj instanceof Object ? obj : JSON.parse(JSON.stringify(obj))
|
|
29
32
|
return original.query(newObj, pathExpression, count)
|
|
30
33
|
}),
|
|
@@ -2,34 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
/* eslint-disable unicorn/no-await-expression-member */
|
|
4
4
|
import {
|
|
5
|
-
BlobLocation,
|
|
6
|
-
LocalPathLocation,
|
|
7
|
-
UriLocation,
|
|
5
|
+
type BlobLocation,
|
|
6
|
+
type LocalPathLocation,
|
|
7
|
+
type UriLocation,
|
|
8
8
|
isLocalPathLocation,
|
|
9
9
|
isUriLocation,
|
|
10
10
|
} from '@jbrowse/core/util'
|
|
11
11
|
import {
|
|
12
|
+
type IDBPTransaction,
|
|
13
|
+
type IndexNames,
|
|
14
|
+
type StoreNames,
|
|
12
15
|
deleteDB,
|
|
13
|
-
IDBPTransaction,
|
|
14
|
-
IndexNames,
|
|
15
|
-
StoreNames,
|
|
16
16
|
} from 'idb/with-async-ittr'
|
|
17
17
|
|
|
18
|
+
import {
|
|
19
|
+
type OntologyClass,
|
|
20
|
+
type OntologyProperty,
|
|
21
|
+
type OntologyTerm,
|
|
22
|
+
isOntologyClass,
|
|
23
|
+
isOntologyProperty,
|
|
24
|
+
} from '..'
|
|
25
|
+
|
|
18
26
|
import { textSearch } from './fulltext'
|
|
19
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
type OntologyDB,
|
|
29
|
+
type OntologyDBEdge,
|
|
30
|
+
isDeprecated,
|
|
31
|
+
} from './indexeddb-schema'
|
|
20
32
|
import {
|
|
21
33
|
getTextIndexFields,
|
|
22
34
|
isDatabaseCurrent,
|
|
23
35
|
loadOboGraphJson,
|
|
24
36
|
openDatabase,
|
|
25
37
|
} from './indexeddb-storage'
|
|
26
|
-
import {
|
|
27
|
-
OntologyClass,
|
|
28
|
-
OntologyProperty,
|
|
29
|
-
OntologyTerm,
|
|
30
|
-
isOntologyClass,
|
|
31
|
-
isOntologyProperty,
|
|
32
|
-
} from '..'
|
|
33
38
|
|
|
34
39
|
export type SourceLocation = UriLocation | LocalPathLocation | BlobLocation
|
|
35
40
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/** schema types used to strongly-type using the `idb` type system */
|
|
2
|
-
import { DBSchema } from 'idb/with-async-ittr'
|
|
2
|
+
import { type DBSchema } from 'idb/with-async-ittr'
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
-
Edge as OboGraphEdge,
|
|
6
|
-
Meta as OboGraphMeta,
|
|
7
|
-
Node as OboGraphNode,
|
|
5
|
+
type Edge as OboGraphEdge,
|
|
6
|
+
type Meta as OboGraphMeta,
|
|
7
|
+
type Node as OboGraphNode,
|
|
8
8
|
} from './obo-graph-json-schema'
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
import { type OntologyStoreOptions, type SourceLocation } from '.'
|
|
10
11
|
|
|
11
12
|
/** metadata about this IndexedDB ontology database */
|
|
12
13
|
export interface Meta {
|