@apollo-annotation/jbrowse-plugin-apollo 0.3.13 → 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.
- package/dist/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.d.ts +1 -1
- package/dist/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.d.ts.map +1 -1
- package/dist/BackendDrivers/BackendDriver.d.ts +29 -4
- package/dist/BackendDrivers/BackendDriver.d.ts.map +1 -1
- package/dist/BackendDrivers/CollaborationServerDriver.d.ts +3 -1
- package/dist/BackendDrivers/CollaborationServerDriver.d.ts.map +1 -1
- package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts +22 -0
- package/dist/BackendDrivers/LocalDriver/LocalDriver.d.ts.map +1 -0
- package/dist/BackendDrivers/LocalDriver/db.d.ts +4 -0
- package/dist/BackendDrivers/LocalDriver/db.d.ts.map +1 -0
- package/dist/BackendDrivers/index.d.ts +1 -2
- package/dist/BackendDrivers/index.d.ts.map +1 -1
- package/dist/ChangeManager.d.ts +3 -3
- package/dist/ChangeManager.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts +0 -6
- package/dist/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/TranscriptWidgetEditLocation.d.ts.map +1 -1
- package/dist/FeatureDetailsWidget/model.d.ts +0 -2
- package/dist/FeatureDetailsWidget/model.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/components/CheckResultWarnings.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/components/LinearApolloDisplay.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/components/OverlayCanvas.d.ts +7 -0
- package/dist/LinearApolloDisplay/components/OverlayCanvas.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/components/Tooltip.d.ts +10 -0
- package/dist/LinearApolloDisplay/components/Tooltip.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/BoxGlyph.d.ts +0 -1
- package/dist/LinearApolloDisplay/glyphs/BoxGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/CDSGlyph.d.ts +3 -0
- package/dist/LinearApolloDisplay/glyphs/CDSGlyph.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts +3 -0
- package/dist/LinearApolloDisplay/glyphs/ExonGlyph.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/GenericChildGlyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/Glyph.d.ts +26 -20
- package/dist/LinearApolloDisplay/glyphs/Glyph.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts +3 -0
- package/dist/LinearApolloDisplay/glyphs/TranscriptGlyph.d.ts.map +1 -0
- package/dist/LinearApolloDisplay/glyphs/util.d.ts +13 -0
- package/dist/LinearApolloDisplay/glyphs/util.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/base.d.ts +17 -0
- package/dist/LinearApolloDisplay/stateModel/base.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/index.d.ts +35 -17
- package/dist/LinearApolloDisplay/stateModel/index.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/layouts.d.ts +29 -7
- package/dist/LinearApolloDisplay/stateModel/layouts.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts +69 -23
- package/dist/LinearApolloDisplay/stateModel/mouseEvents.d.ts.map +1 -1
- package/dist/LinearApolloDisplay/stateModel/rendering.d.ts +26 -9
- package/dist/LinearApolloDisplay/stateModel/rendering.d.ts.map +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts +6 -0
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/base.d.ts.map +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts +6 -0
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/index.d.ts.map +1 -1
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts +6 -0
- package/dist/LinearApolloReferenceSequenceDisplay/stateModel/rendering.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/glyphs/Glyph.d.ts +1 -1
- package/dist/LinearApolloSixFrameDisplay/glyphs/Glyph.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/layouts.d.ts.map +1 -1
- package/dist/LinearApolloSixFrameDisplay/stateModel/rendering.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/fulltext.d.ts +1 -1
- package/dist/OntologyManager/OntologyStore/fulltext.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/index.d.ts +2 -2
- package/dist/OntologyManager/OntologyStore/index.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/indexeddb-storage.d.ts +1 -1
- package/dist/OntologyManager/OntologyStore/indexeddb-storage.d.ts.map +1 -1
- package/dist/OntologyManager/OntologyStore/types.d.ts +18 -0
- package/dist/OntologyManager/OntologyStore/types.d.ts.map +1 -0
- package/dist/TabularEditor/HybridGrid/featureContextMenuItems.d.ts.map +1 -1
- package/dist/components/AddChildFeature.d.ts.map +1 -1
- package/dist/components/ColorFeature.d.ts +13 -0
- package/dist/components/ColorFeature.d.ts.map +1 -0
- package/dist/components/CreateApolloAnnotation.d.ts.map +1 -1
- package/dist/components/DownloadGFF3.d.ts +4 -1
- package/dist/components/DownloadGFF3.d.ts.map +1 -1
- package/dist/components/DuplicateTranscript.d.ts.map +1 -1
- package/dist/components/ViewChangeLog.d.ts +2 -1
- package/dist/components/ViewChangeLog.d.ts.map +1 -1
- package/dist/components/ViewCheckResults.d.ts +2 -1
- package/dist/components/ViewCheckResults.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/extensions/annotationFromJBrowseFeature.d.ts.map +1 -1
- package/dist/extensions/annotationFromPileup.d.ts.map +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +6325 -5997
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +5869 -5541
- 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 +16782 -25897
- 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/dist/makeDisplayComponent.d.ts.map +1 -1
- package/dist/menus/Icons.d.ts +3 -0
- package/dist/menus/Icons.d.ts.map +1 -0
- package/dist/menus/topLevelMenu.d.ts.map +1 -1
- package/dist/session/changeHandlers.d.ts +9 -0
- package/dist/session/changeHandlers.d.ts.map +1 -0
- package/dist/util/annotationFeatureUtils.d.ts +2 -1
- package/dist/util/annotationFeatureUtils.d.ts.map +1 -1
- package/dist/util/glyphUtils.d.ts +3 -3
- package/dist/util/glyphUtils.d.ts.map +1 -1
- package/dist/util/index.d.ts +0 -1
- package/dist/util/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ApolloInternetAccount/model.ts +68 -4
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +6 -3
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +1 -1
- package/src/BackendDrivers/BackendDriver.ts +36 -3
- package/src/BackendDrivers/CollaborationServerDriver.ts +78 -23
- package/src/BackendDrivers/LocalDriver/LocalDriver.ts +367 -0
- package/src/BackendDrivers/LocalDriver/db.ts +37 -0
- package/src/BackendDrivers/index.ts +1 -2
- package/src/ChangeManager.ts +27 -25
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +1 -1
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +69 -53
- package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +1 -5
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +95 -115
- package/src/LinearApolloDisplay/components/OverlayCanvas.tsx +76 -0
- package/src/LinearApolloDisplay/components/Tooltip.tsx +42 -0
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +60 -302
- package/src/LinearApolloDisplay/glyphs/CDSGlyph.ts +145 -0
- package/src/LinearApolloDisplay/glyphs/ExonGlyph.ts +212 -0
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +65 -999
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +71 -181
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +42 -66
- package/src/LinearApolloDisplay/glyphs/TranscriptGlyph.ts +291 -0
- package/src/LinearApolloDisplay/glyphs/util.ts +87 -0
- package/src/LinearApolloDisplay/stateModel/base.ts +83 -0
- package/src/LinearApolloDisplay/stateModel/layouts.ts +198 -138
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +252 -158
- package/src/LinearApolloDisplay/stateModel/rendering.ts +103 -21
- package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +3 -3
- package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +20 -2
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +7 -2
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +8 -13
- package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +1 -1
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +4 -3
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +1 -1
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +2 -1
- package/src/OntologyManager/OntologyStore/__snapshots__/index.test.ts.snap +18262 -8519
- package/src/OntologyManager/OntologyStore/fulltext.ts +1 -2
- package/src/OntologyManager/OntologyStore/index.test.ts +5 -2
- package/src/OntologyManager/OntologyStore/index.ts +7 -8
- package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +2 -2
- package/src/OntologyManager/OntologyStore/types.ts +27 -0
- package/src/OntologyManager/index.ts +15 -26
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +4 -5
- package/src/components/AddChildFeature.tsx +15 -8
- package/src/components/ColorFeature.tsx +167 -0
- package/src/components/CreateApolloAnnotation.tsx +35 -9
- package/src/components/DownloadGFF3.tsx +92 -121
- package/src/components/DuplicateTranscript.tsx +10 -0
- package/src/components/ViewChangeLog.tsx +123 -83
- package/src/components/ViewCheckResults.tsx +15 -73
- package/src/components/index.ts +1 -1
- package/src/config.ts +37 -19
- package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -1
- package/src/extensions/annotationFromJBrowseFeature.ts +91 -63
- package/src/extensions/annotationFromPileup.ts +40 -40
- package/src/index.ts +45 -1
- package/src/makeDisplayComponent.tsx +10 -3
- package/src/menus/Icons.tsx +49 -0
- package/src/menus/topLevelMenu.ts +24 -96
- package/src/session/ClientDataStore.ts +16 -17
- package/src/session/changeHandlers.ts +261 -0
- package/src/session/session.ts +77 -46
- package/src/util/annotationFeatureUtils.ts +29 -1
- package/src/util/glyphUtils.ts +74 -31
- package/src/util/index.ts +0 -1
- package/dist/BackendDrivers/DesktopFileDriver.d.ts +0 -160
- package/dist/BackendDrivers/DesktopFileDriver.d.ts.map +0 -1
- package/dist/BackendDrivers/InMemoryFileDriver.d.ts +0 -162
- package/dist/BackendDrivers/InMemoryFileDriver.d.ts.map +0 -1
- package/dist/LinearApolloDisplay/glyphs/index.d.ts +0 -4
- package/dist/LinearApolloDisplay/glyphs/index.d.ts.map +0 -1
- package/dist/components/OpenLocalFile.d.ts +0 -15
- package/dist/components/OpenLocalFile.d.ts.map +0 -1
- package/dist/util/loadAssemblyIntoClient.d.ts +0 -5
- package/dist/util/loadAssemblyIntoClient.d.ts.map +0 -1
- package/src/BackendDrivers/DesktopFileDriver.ts +0 -184
- package/src/BackendDrivers/InMemoryFileDriver.ts +0 -107
- package/src/LinearApolloDisplay/glyphs/index.ts +0 -3
- package/src/components/OpenLocalFile.tsx +0 -189
- package/src/util/loadAssemblyIntoClient.ts +0 -94
|
@@ -6,22 +6,52 @@ import {
|
|
|
6
6
|
import type PluginManager from '@jbrowse/core/PluginManager'
|
|
7
7
|
import type { AnyConfigurationSchemaType } from '@jbrowse/core/configuration'
|
|
8
8
|
import type { MenuItem } from '@jbrowse/core/ui'
|
|
9
|
+
import { doesIntersect2 } from '@jbrowse/core/util'
|
|
9
10
|
import { type Instance, addDisposer } from '@jbrowse/mobx-state-tree'
|
|
11
|
+
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
10
12
|
import { autorun } from 'mobx'
|
|
11
13
|
import type { CSSProperties } from 'react'
|
|
12
14
|
|
|
13
15
|
import {
|
|
14
16
|
type Edge,
|
|
15
|
-
|
|
16
|
-
type MousePositionWithFeature,
|
|
17
|
-
getMousePosition,
|
|
17
|
+
getContextMenuItemsForFeature,
|
|
18
18
|
getPropagatedLocationChanges,
|
|
19
|
-
|
|
19
|
+
isCDSFeature,
|
|
20
|
+
isExonFeature,
|
|
21
|
+
selectFeatureAndOpenWidget,
|
|
20
22
|
} from '../../util'
|
|
23
|
+
import { isMouseOnFeatureEdge } from '../glyphs/util'
|
|
21
24
|
import type { CanvasMouseEvent } from '../types'
|
|
22
25
|
|
|
23
26
|
import { renderingModelFactory } from './rendering'
|
|
24
27
|
|
|
28
|
+
export interface MousePosition {
|
|
29
|
+
x: number
|
|
30
|
+
y: number
|
|
31
|
+
assemblyName: string
|
|
32
|
+
refName: string
|
|
33
|
+
bp: number
|
|
34
|
+
regionNumber: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getMousePosition(
|
|
38
|
+
event: React.MouseEvent,
|
|
39
|
+
lgv: LinearGenomeViewModel,
|
|
40
|
+
): MousePosition {
|
|
41
|
+
const canvas = event.currentTarget
|
|
42
|
+
const { clientX, clientY } = event
|
|
43
|
+
const { left, top } = canvas.getBoundingClientRect()
|
|
44
|
+
const x = clientX - left
|
|
45
|
+
const y = clientY - top
|
|
46
|
+
const {
|
|
47
|
+
coord: bp,
|
|
48
|
+
index: regionNumber,
|
|
49
|
+
assemblyName,
|
|
50
|
+
refName,
|
|
51
|
+
} = lgv.pxToBp(x)
|
|
52
|
+
return { x, y, assemblyName, refName, bp, regionNumber }
|
|
53
|
+
}
|
|
54
|
+
|
|
25
55
|
export function mouseEventsModelIntermediateFactory(
|
|
26
56
|
pluginManager: PluginManager,
|
|
27
57
|
configSchema: AnyConfigurationSchemaType,
|
|
@@ -44,45 +74,16 @@ export function mouseEventsModelIntermediateFactory(
|
|
|
44
74
|
}))
|
|
45
75
|
.views((self) => ({
|
|
46
76
|
getMousePosition(event: React.MouseEvent): MousePosition {
|
|
47
|
-
|
|
48
|
-
|
|
77
|
+
return getMousePosition(event, self.lgv)
|
|
78
|
+
},
|
|
79
|
+
getFeaturesAtMousePosition(mousePosition: MousePosition) {
|
|
80
|
+
const { bp, assemblyName, refName, y } = mousePosition
|
|
49
81
|
const row = Math.floor(y / self.apolloRowHeight)
|
|
50
|
-
const featureLayout = self.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return mousePosition
|
|
54
|
-
}
|
|
55
|
-
const foundFeature = layoutRow.find((f) => {
|
|
56
|
-
const feature = self.getAnnotationFeatureById(f[1])
|
|
57
|
-
return feature && bp >= feature.min && bp <= feature.max
|
|
58
|
-
})
|
|
59
|
-
if (!foundFeature) {
|
|
60
|
-
return mousePosition
|
|
61
|
-
}
|
|
62
|
-
const [featureRow, topLevelFeatureId] = foundFeature
|
|
63
|
-
const topLevelFeature = self.getAnnotationFeatureById(topLevelFeatureId)
|
|
64
|
-
if (!topLevelFeature) {
|
|
65
|
-
return mousePosition
|
|
66
|
-
}
|
|
67
|
-
const glyph = self.getGlyph(topLevelFeature)
|
|
68
|
-
const { featureTypeOntology } =
|
|
69
|
-
self.session.apolloDataStore.ontologyManager
|
|
70
|
-
if (!featureTypeOntology) {
|
|
71
|
-
throw new Error('featureTypeOntology is undefined')
|
|
72
|
-
}
|
|
73
|
-
const feature = glyph.getFeatureFromLayout(
|
|
74
|
-
topLevelFeature,
|
|
75
|
-
bp,
|
|
76
|
-
featureRow,
|
|
77
|
-
featureTypeOntology,
|
|
78
|
-
)
|
|
79
|
-
if (!feature) {
|
|
80
|
-
return mousePosition
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
...mousePosition,
|
|
84
|
-
feature,
|
|
82
|
+
const featureLayout = self.layouts.get(assemblyName)?.get(refName)
|
|
83
|
+
if (!featureLayout) {
|
|
84
|
+
return []
|
|
85
85
|
}
|
|
86
|
+
return self.getFeaturesAtPosition(assemblyName, refName, row, bp)
|
|
86
87
|
},
|
|
87
88
|
}))
|
|
88
89
|
.actions((self) => ({
|
|
@@ -129,91 +130,116 @@ export function mouseEventsModelFactory(
|
|
|
129
130
|
|
|
130
131
|
return LinearApolloDisplayMouseEvents.views((self) => ({
|
|
131
132
|
contextMenuItems(event: React.MouseEvent<HTMLDivElement>): MenuItem[] {
|
|
132
|
-
const { hoveredFeature } = self
|
|
133
|
-
if (!hoveredFeature) {
|
|
134
|
-
return []
|
|
135
|
-
}
|
|
136
133
|
const mousePosition = self.getMousePosition(event)
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return glyph.getContextMenuItems(self, mousePosition)
|
|
134
|
+
const features = self.getFeaturesAtMousePosition(mousePosition)
|
|
135
|
+
if (features.length === 1) {
|
|
136
|
+
return getContextMenuItemsForFeature(self, features[0])
|
|
141
137
|
}
|
|
142
|
-
|
|
138
|
+
const menuItems: MenuItem[] = []
|
|
139
|
+
for (const feature of features) {
|
|
140
|
+
const glyph = self.getGlyph(feature)
|
|
141
|
+
menuItems.push({
|
|
142
|
+
label: feature.type,
|
|
143
|
+
subMenu: [
|
|
144
|
+
...getContextMenuItemsForFeature(self, feature),
|
|
145
|
+
// @ts-expect-error ts doesn't understand mst extension
|
|
146
|
+
...glyph.getContextMenuItems(self, feature),
|
|
147
|
+
],
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
return menuItems
|
|
143
151
|
},
|
|
144
152
|
}))
|
|
145
|
-
.actions((self) =>
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
startDrag(
|
|
149
|
-
mousePosition: MousePositionWithFeature,
|
|
150
|
-
feature: AnnotationFeature,
|
|
151
|
-
edge: Edge,
|
|
152
|
-
shrinkParent = false,
|
|
153
|
-
) {
|
|
154
|
-
self.apolloDragging = {
|
|
155
|
-
start: mousePosition,
|
|
156
|
-
current: mousePosition,
|
|
157
|
-
feature,
|
|
158
|
-
edge,
|
|
159
|
-
shrinkParent,
|
|
160
|
-
}
|
|
161
|
-
},
|
|
162
|
-
endDrag() {
|
|
163
|
-
if (!self.apolloDragging) {
|
|
164
|
-
throw new Error('endDrag() called with no current drag in progress')
|
|
165
|
-
}
|
|
166
|
-
const { current, edge, feature, start, shrinkParent } =
|
|
167
|
-
self.apolloDragging
|
|
168
|
-
// don't do anything if it was only dragged a tiny bit
|
|
169
|
-
if (Math.abs(current.x - start.x) <= 4) {
|
|
153
|
+
.actions((self) => {
|
|
154
|
+
function cancelDragListener(event: KeyboardEvent) {
|
|
155
|
+
if (event.key === 'Escape') {
|
|
170
156
|
self.setDragging()
|
|
171
|
-
self.setCursor()
|
|
172
|
-
return
|
|
173
157
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
// explicitly pass in a feature in case it's not the same as the one in
|
|
161
|
+
// mousePosition (e.g. if features are drawn overlapping).
|
|
162
|
+
startDrag(
|
|
163
|
+
mousePosition: MousePosition,
|
|
164
|
+
feature: AnnotationFeature,
|
|
165
|
+
edge: Edge,
|
|
166
|
+
shrinkParent = false,
|
|
167
|
+
) {
|
|
168
|
+
globalThis.addEventListener('keydown', cancelDragListener, true)
|
|
169
|
+
self.apolloDragging = {
|
|
170
|
+
start: mousePosition,
|
|
171
|
+
current: mousePosition,
|
|
172
|
+
feature,
|
|
173
|
+
edge,
|
|
174
|
+
shrinkParent,
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
endDrag() {
|
|
178
|
+
globalThis.removeEventListener('keydown', cancelDragListener, true)
|
|
179
|
+
if (!self.apolloDragging) {
|
|
180
|
+
throw new Error('endDrag() called with no current drag in progress')
|
|
181
|
+
}
|
|
182
|
+
const { current, edge, feature, start, shrinkParent } =
|
|
183
|
+
self.apolloDragging
|
|
184
|
+
// don't do anything if it was only dragged a tiny bit
|
|
185
|
+
if (Math.abs(current.x - start.x) <= 4) {
|
|
186
|
+
self.setDragging()
|
|
187
|
+
self.setCursor()
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
const { displayedRegions } = self.lgv
|
|
191
|
+
const region = displayedRegions[start.regionNumber]
|
|
192
|
+
const assembly = self.getAssemblyId(region.assemblyName)
|
|
193
|
+
const changes = getPropagatedLocationChanges(
|
|
194
|
+
feature,
|
|
195
|
+
current.bp,
|
|
196
|
+
edge,
|
|
197
|
+
shrinkParent,
|
|
198
|
+
)
|
|
183
199
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
200
|
+
const change: LocationEndChange | LocationStartChange =
|
|
201
|
+
edge === 'max'
|
|
202
|
+
? new LocationEndChange({
|
|
203
|
+
typeName: 'LocationEndChange',
|
|
204
|
+
changedIds: changes.map((c) => c.featureId),
|
|
205
|
+
changes: changes.map((c) => ({
|
|
206
|
+
featureId: c.featureId,
|
|
207
|
+
oldEnd: c.oldLocation,
|
|
208
|
+
newEnd: c.newLocation,
|
|
209
|
+
})),
|
|
210
|
+
assembly,
|
|
211
|
+
})
|
|
212
|
+
: new LocationStartChange({
|
|
213
|
+
typeName: 'LocationStartChange',
|
|
214
|
+
changedIds: changes.map((c) => c.featureId),
|
|
215
|
+
changes: changes.map((c) => ({
|
|
216
|
+
featureId: c.featureId,
|
|
217
|
+
oldStart: c.oldLocation,
|
|
218
|
+
newStart: c.newLocation,
|
|
219
|
+
})),
|
|
220
|
+
assembly,
|
|
221
|
+
})
|
|
222
|
+
void self.changeManager.submit(change)
|
|
223
|
+
self.setDragging()
|
|
224
|
+
self.setCursor()
|
|
225
|
+
},
|
|
226
|
+
}
|
|
227
|
+
})
|
|
211
228
|
.actions((self) => ({
|
|
212
229
|
onMouseDown(event: CanvasMouseEvent) {
|
|
213
230
|
const mousePosition = self.getMousePosition(event)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
glyph.
|
|
231
|
+
const features = self.getFeaturesAtMousePosition(mousePosition)
|
|
232
|
+
for (const feature of features.toReversed()) {
|
|
233
|
+
const glyph = self.getGlyph(feature)
|
|
234
|
+
if (glyph.isDraggable) {
|
|
235
|
+
// @ts-expect-error ts doesn't understand mst extension
|
|
236
|
+
const edge = isMouseOnFeatureEdge(mousePosition, feature, self)
|
|
237
|
+
if (edge) {
|
|
238
|
+
event.stopPropagation()
|
|
239
|
+
self.startDrag(mousePosition, feature, edge, true)
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
}
|
|
217
243
|
}
|
|
218
244
|
},
|
|
219
245
|
onMouseMove(event: CanvasMouseEvent) {
|
|
@@ -223,36 +249,58 @@ export function mouseEventsModelFactory(
|
|
|
223
249
|
self.continueDrag(mousePosition, event)
|
|
224
250
|
return
|
|
225
251
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
252
|
+
const features = self.getFeaturesAtMousePosition(mousePosition)
|
|
253
|
+
let topFeature = features.at(-1)
|
|
254
|
+
// TODO: can we get this special case for CDS to fit nicely in the glyph?
|
|
255
|
+
if (topFeature && isCDSFeature(topFeature, self.session)) {
|
|
256
|
+
const nextFeature = features.at(-2)
|
|
257
|
+
if (nextFeature && !isExonFeature(nextFeature, self.session)) {
|
|
258
|
+
topFeature = nextFeature
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (topFeature) {
|
|
262
|
+
self.setHoveredFeature({ feature: topFeature, bp: mousePosition.bp })
|
|
229
263
|
} else {
|
|
230
264
|
self.setHoveredFeature()
|
|
231
|
-
self.setCursor()
|
|
232
265
|
}
|
|
266
|
+
for (const feature of features.toReversed()) {
|
|
267
|
+
const glyph = self.getGlyph(feature)
|
|
268
|
+
if (
|
|
269
|
+
glyph.isDraggable &&
|
|
270
|
+
// @ts-expect-error ts doesn't understand mst extension
|
|
271
|
+
isMouseOnFeatureEdge(mousePosition, feature, self)
|
|
272
|
+
) {
|
|
273
|
+
self.setCursor('col-resize')
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
self.setCursor()
|
|
233
278
|
},
|
|
234
|
-
onMouseLeave(
|
|
279
|
+
onMouseLeave(_event: CanvasMouseEvent) {
|
|
235
280
|
self.setDragging()
|
|
236
281
|
self.setHoveredFeature()
|
|
237
|
-
|
|
238
|
-
const mousePosition = self.getMousePosition(event)
|
|
239
|
-
if (isMousePositionWithFeature(mousePosition)) {
|
|
240
|
-
const glyph = self.getGlyph(mousePosition.feature)
|
|
241
|
-
glyph.onMouseLeave(self, mousePosition, event)
|
|
242
|
-
}
|
|
243
282
|
},
|
|
244
283
|
onMouseUp(event: CanvasMouseEvent) {
|
|
284
|
+
if (self.apolloDragging) {
|
|
285
|
+
self.endDrag()
|
|
286
|
+
return
|
|
287
|
+
}
|
|
245
288
|
const mousePosition = self.getMousePosition(event)
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
289
|
+
const features = self.getFeaturesAtMousePosition(mousePosition)
|
|
290
|
+
let topFeature = features.at(-1)
|
|
291
|
+
// TODO: can we get this special case for CDS to fit nicely in the glyph?
|
|
292
|
+
if (topFeature && isCDSFeature(topFeature, self.session)) {
|
|
293
|
+
const nextFeature = features.at(-2)
|
|
294
|
+
if (nextFeature && !isExonFeature(nextFeature, self.session)) {
|
|
295
|
+
topFeature = nextFeature
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if (topFeature) {
|
|
299
|
+
selectFeatureAndOpenWidget(self, topFeature)
|
|
300
|
+
self.setSelectedFeature(topFeature)
|
|
249
301
|
} else {
|
|
250
302
|
self.setSelectedFeature()
|
|
251
303
|
}
|
|
252
|
-
|
|
253
|
-
if (self.apolloDragging) {
|
|
254
|
-
self.endDrag()
|
|
255
|
-
}
|
|
256
304
|
},
|
|
257
305
|
}))
|
|
258
306
|
.actions((self) => ({
|
|
@@ -261,42 +309,88 @@ export function mouseEventsModelFactory(
|
|
|
261
309
|
self,
|
|
262
310
|
autorun(
|
|
263
311
|
() => {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
312
|
+
const { lgv, overlayCanvas } = self
|
|
313
|
+
if (
|
|
314
|
+
!lgv.initialized ||
|
|
315
|
+
// This type is wrong in @jbrowse/core
|
|
316
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
317
|
+
self.regionCannotBeRendered() ||
|
|
318
|
+
!overlayCanvas
|
|
319
|
+
) {
|
|
267
320
|
return
|
|
268
321
|
}
|
|
269
|
-
const
|
|
322
|
+
const { dynamicBlocks, offsetPx } = lgv
|
|
323
|
+
const ctx = overlayCanvas.getContext('2d')
|
|
270
324
|
if (!ctx) {
|
|
271
325
|
return
|
|
272
326
|
}
|
|
273
|
-
ctx.clearRect(
|
|
274
|
-
0,
|
|
275
|
-
0,
|
|
276
|
-
self.lgv.dynamicBlocks.totalWidthPx,
|
|
277
|
-
self.featuresHeight,
|
|
278
|
-
)
|
|
279
|
-
|
|
327
|
+
ctx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height)
|
|
280
328
|
const { apolloDragging, hoveredFeature } = self
|
|
281
329
|
if (!hoveredFeature) {
|
|
282
330
|
return
|
|
283
331
|
}
|
|
284
|
-
const
|
|
332
|
+
const { feature } = hoveredFeature
|
|
333
|
+
const glyph = self.getGlyph(feature)
|
|
334
|
+
const row = self.getRowForFeature(feature)
|
|
335
|
+
if (row === undefined) {
|
|
336
|
+
return
|
|
337
|
+
}
|
|
285
338
|
|
|
286
|
-
|
|
287
|
-
|
|
339
|
+
for (const block of dynamicBlocks.contentBlocks) {
|
|
340
|
+
const blockLeftPx = block.offsetPx - offsetPx
|
|
341
|
+
ctx.save()
|
|
342
|
+
ctx.beginPath()
|
|
343
|
+
ctx.rect(blockLeftPx, 0, block.widthPx, overlayCanvas.height)
|
|
344
|
+
ctx.clip()
|
|
345
|
+
if (
|
|
346
|
+
block.assemblyName === feature.assemblyId &&
|
|
347
|
+
doesIntersect2(
|
|
348
|
+
block.start,
|
|
349
|
+
block.end,
|
|
350
|
+
feature.min,
|
|
351
|
+
feature.max,
|
|
352
|
+
)
|
|
353
|
+
) {
|
|
354
|
+
// draw mouseover hovers
|
|
355
|
+
glyph.drawOverlay(
|
|
356
|
+
// @ts-expect-error ts doesn't understand mst extension
|
|
357
|
+
self,
|
|
358
|
+
ctx,
|
|
359
|
+
feature,
|
|
360
|
+
row,
|
|
361
|
+
block,
|
|
362
|
+
'hover',
|
|
363
|
+
)
|
|
364
|
+
}
|
|
365
|
+
if (apolloDragging) {
|
|
366
|
+
const {
|
|
367
|
+
current,
|
|
368
|
+
start,
|
|
369
|
+
feature: dragFeature,
|
|
370
|
+
} = apolloDragging
|
|
371
|
+
const dragMin = Math.min(current.bp, start.bp)
|
|
372
|
+
const dragMax = Math.max(current.bp, start.bp)
|
|
373
|
+
if (
|
|
374
|
+
doesIntersect2(block.start, block.end, dragMin, dragMax)
|
|
375
|
+
) {
|
|
376
|
+
const dragGlyph = self.getGlyph(dragFeature)
|
|
377
|
+
const row = self.getRowForFeature(dragFeature)
|
|
288
378
|
|
|
289
|
-
|
|
290
|
-
|
|
379
|
+
if (row !== undefined) {
|
|
380
|
+
// draw dragging previews
|
|
381
|
+
dragGlyph.drawDragPreview(
|
|
382
|
+
// @ts-expect-error ts doesn't understand mst extension
|
|
383
|
+
self,
|
|
384
|
+
ctx,
|
|
385
|
+
dragFeature,
|
|
386
|
+
row,
|
|
387
|
+
block,
|
|
388
|
+
)
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
291
392
|
|
|
292
|
-
|
|
293
|
-
if (apolloDragging) {
|
|
294
|
-
// NOTE: the glyph where the drag started is responsible for drawing the preview.
|
|
295
|
-
// it can call methods in other glyphs to help with this though.
|
|
296
|
-
const glyph = self.getGlyph(
|
|
297
|
-
apolloDragging.feature.topLevelFeature,
|
|
298
|
-
)
|
|
299
|
-
glyph.drawDragPreview(self, ctx)
|
|
393
|
+
ctx.restore()
|
|
300
394
|
}
|
|
301
395
|
},
|
|
302
396
|
{ name: 'LinearApolloDisplayRenderMouseoverAndDrag' },
|
|
@@ -24,7 +24,6 @@ export function renderingModelFactory(
|
|
|
24
24
|
apolloRowHeight: 20,
|
|
25
25
|
detailsMinHeight: 200,
|
|
26
26
|
detailsHeight: 200,
|
|
27
|
-
lastRowTooltipBufferHeight: 40,
|
|
28
27
|
isShown: true,
|
|
29
28
|
filteredTranscripts: types.array(types.string),
|
|
30
29
|
})
|
|
@@ -35,11 +34,51 @@ export function renderingModelFactory(
|
|
|
35
34
|
theme: createTheme(),
|
|
36
35
|
}))
|
|
37
36
|
.views((self) => ({
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
featuresHeight(assemblyName: string) {
|
|
38
|
+
return (self.highestRow(assemblyName) + 1) * self.apolloRowHeight
|
|
39
|
+
},
|
|
40
|
+
get canvasPatterns(): Record<
|
|
41
|
+
'forward' | 'backward',
|
|
42
|
+
CanvasPattern | null
|
|
43
|
+
> {
|
|
44
|
+
const patterns: Record<'forward' | 'backward', CanvasPattern | null> = {
|
|
45
|
+
forward: null,
|
|
46
|
+
backward: null,
|
|
47
|
+
}
|
|
48
|
+
const canvas = document.createElement('canvas')
|
|
49
|
+
const ctx = canvas?.getContext('2d')
|
|
50
|
+
if (!ctx) {
|
|
51
|
+
return patterns
|
|
52
|
+
}
|
|
53
|
+
const canvasSize = 10
|
|
54
|
+
canvas.width = canvas.height = canvasSize
|
|
55
|
+
const { theme } = self
|
|
56
|
+
const stripeColor1 =
|
|
57
|
+
theme.palette.mode === 'light' ? 'rgba(0,0,0,0)' : 'rgba(0,0,0,0.75)'
|
|
58
|
+
const stripeColor2 =
|
|
59
|
+
theme.palette.mode === 'light'
|
|
60
|
+
? 'rgba(255,255,255,0.25)'
|
|
61
|
+
: 'rgba(0,0,0,0.50)'
|
|
62
|
+
const directions = ['forward', 'backward'] as const
|
|
63
|
+
for (const direction of directions) {
|
|
64
|
+
const gradient =
|
|
65
|
+
direction === 'forward'
|
|
66
|
+
? ctx.createLinearGradient(0, canvasSize, canvasSize, 0)
|
|
67
|
+
: ctx.createLinearGradient(0, 0, canvasSize, canvasSize)
|
|
68
|
+
gradient.addColorStop(0, stripeColor1)
|
|
69
|
+
gradient.addColorStop(0.25, stripeColor1)
|
|
70
|
+
gradient.addColorStop(0.25, stripeColor2)
|
|
71
|
+
gradient.addColorStop(0.5, stripeColor2)
|
|
72
|
+
gradient.addColorStop(0.5, stripeColor1)
|
|
73
|
+
gradient.addColorStop(0.75, stripeColor1)
|
|
74
|
+
gradient.addColorStop(0.75, stripeColor2)
|
|
75
|
+
gradient.addColorStop(1, stripeColor2)
|
|
76
|
+
ctx.fillStyle = gradient
|
|
77
|
+
ctx.clearRect(0, 0, canvasSize, canvasSize)
|
|
78
|
+
ctx.fillRect(0, 0, canvasSize, canvasSize)
|
|
79
|
+
patterns[direction] = ctx.createPattern(canvas, 'repeat')
|
|
80
|
+
}
|
|
81
|
+
return patterns
|
|
43
82
|
},
|
|
44
83
|
}))
|
|
45
84
|
.actions((self) => ({
|
|
@@ -84,7 +123,7 @@ export function renderingModelFactory(
|
|
|
84
123
|
0,
|
|
85
124
|
0,
|
|
86
125
|
self.lgv.dynamicBlocks.totalWidthPx,
|
|
87
|
-
self.featuresHeight,
|
|
126
|
+
self.featuresHeight(self.lgv.assemblyNames[0]),
|
|
88
127
|
)
|
|
89
128
|
for (const collaborator of (
|
|
90
129
|
self.session as unknown as ApolloSessionModel
|
|
@@ -132,38 +171,81 @@ export function renderingModelFactory(
|
|
|
132
171
|
self,
|
|
133
172
|
autorun(
|
|
134
173
|
() => {
|
|
135
|
-
const { canvas,
|
|
136
|
-
if (
|
|
174
|
+
const { canvas, layouts, lgv } = self
|
|
175
|
+
if (
|
|
176
|
+
!lgv.initialized ||
|
|
177
|
+
self.regionCannotBeRendered() ||
|
|
178
|
+
!canvas
|
|
179
|
+
) {
|
|
137
180
|
return
|
|
138
181
|
}
|
|
139
|
-
const {
|
|
182
|
+
const { dynamicBlocks, offsetPx } = lgv
|
|
140
183
|
|
|
141
|
-
const ctx = canvas
|
|
184
|
+
const ctx = canvas.getContext('2d')
|
|
142
185
|
if (!ctx) {
|
|
143
186
|
return
|
|
144
187
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
188
|
+
const featureLayouts = layouts.get(lgv.assemblyNames[0])
|
|
189
|
+
if (!featureLayouts) {
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
|
193
|
+
for (const block of dynamicBlocks.contentBlocks) {
|
|
194
|
+
const blockLeftPx = block.offsetPx - offsetPx
|
|
195
|
+
ctx.save()
|
|
196
|
+
ctx.beginPath()
|
|
197
|
+
ctx.rect(blockLeftPx, 0, block.widthPx, canvas.height)
|
|
198
|
+
ctx.clip()
|
|
199
|
+
const layout = featureLayouts.get(block.refName)
|
|
200
|
+
if (!layout) {
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
const { byRow } = layout
|
|
204
|
+
for (const [row, layoutRow] of byRow.entries()) {
|
|
205
|
+
for (const layoutFeature of layoutRow) {
|
|
206
|
+
const { feature, rowInFeature } = layoutFeature
|
|
207
|
+
if (
|
|
208
|
+
!doesIntersect2(
|
|
209
|
+
block.start,
|
|
210
|
+
block.end,
|
|
211
|
+
feature.min,
|
|
212
|
+
feature.max,
|
|
213
|
+
)
|
|
214
|
+
) {
|
|
152
215
|
continue
|
|
153
216
|
}
|
|
217
|
+
self
|
|
218
|
+
.getGlyph(feature)
|
|
219
|
+
// @ts-expect-error ts doesn't understand mst extension
|
|
220
|
+
.draw(self, ctx, feature, row, rowInFeature, block)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
for (const [row, layoutRow] of byRow.entries()) {
|
|
224
|
+
for (const layoutFeature of layoutRow) {
|
|
225
|
+
const { feature, rowInFeature } = layoutFeature
|
|
154
226
|
if (
|
|
155
227
|
!doesIntersect2(
|
|
156
|
-
|
|
157
|
-
|
|
228
|
+
block.start,
|
|
229
|
+
block.end,
|
|
158
230
|
feature.min,
|
|
159
231
|
feature.max,
|
|
160
232
|
)
|
|
161
233
|
) {
|
|
162
234
|
continue
|
|
163
235
|
}
|
|
164
|
-
self.getGlyph(feature).
|
|
236
|
+
self.getGlyph(feature).drawOverlay(
|
|
237
|
+
// @ts-expect-error ts doesn't understand mst extension
|
|
238
|
+
self,
|
|
239
|
+
ctx,
|
|
240
|
+
feature,
|
|
241
|
+
row,
|
|
242
|
+
block,
|
|
243
|
+
'highlight',
|
|
244
|
+
rowInFeature,
|
|
245
|
+
)
|
|
165
246
|
}
|
|
166
247
|
}
|
|
248
|
+
ctx.restore()
|
|
167
249
|
}
|
|
168
250
|
},
|
|
169
251
|
{ name: 'LinearApolloDisplayRenderFeatures' },
|