@apollo-annotation/jbrowse-plugin-apollo 0.3.7 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/index.esm.js +2371 -1642
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +2384 -1641
  4. package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
  5. package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
  6. package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
  7. package/dist/jbrowse-plugin-apollo.umd.development.js +4387 -2952
  8. package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
  9. package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
  10. package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
  11. package/package.json +15 -15
  12. package/src/ApolloInternetAccount/model.ts +48 -13
  13. package/src/BackendDrivers/CollaborationServerDriver.ts +23 -2
  14. package/src/ChangeManager.ts +33 -13
  15. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +64 -5
  16. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +70 -73
  17. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +33 -31
  18. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +60 -72
  19. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +50 -194
  20. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +441 -180
  21. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +53 -34
  22. package/src/LinearApolloDisplay/glyphs/Glyph.ts +7 -9
  23. package/src/LinearApolloDisplay/stateModel/base.ts +34 -43
  24. package/src/LinearApolloDisplay/stateModel/layouts.ts +3 -2
  25. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +32 -261
  26. package/src/LinearApolloDisplay/stateModel/rendering.ts +43 -343
  27. package/src/LinearApolloReferenceSequenceDisplay/components/LinearApolloReferenceSequenceDisplay.tsx +87 -0
  28. package/src/LinearApolloReferenceSequenceDisplay/components/index.ts +1 -0
  29. package/src/LinearApolloReferenceSequenceDisplay/configSchema.ts +7 -0
  30. package/src/LinearApolloReferenceSequenceDisplay/index.ts +3 -0
  31. package/src/LinearApolloReferenceSequenceDisplay/stateModel/base.ts +227 -0
  32. package/src/LinearApolloReferenceSequenceDisplay/stateModel/index.ts +25 -0
  33. package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +481 -0
  34. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +95 -38
  35. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +221 -201
  36. package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +12 -8
  37. package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +42 -4
  38. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +4 -8
  39. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +73 -97
  40. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +49 -61
  41. package/src/TabularEditor/HybridGrid/Feature.tsx +16 -14
  42. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +7 -5
  43. package/src/components/AddAssembly.tsx +1 -1
  44. package/src/components/AddAssemblyAliases.tsx +1 -1
  45. package/src/components/AddChildFeature.tsx +5 -2
  46. package/src/components/AddFeature.tsx +9 -3
  47. package/src/components/AddRefSeqAliases.tsx +9 -9
  48. package/src/components/CopyFeature.tsx +3 -1
  49. package/src/components/CreateApolloAnnotation.tsx +1 -0
  50. package/src/components/DeleteAssembly.tsx +1 -1
  51. package/src/components/EditZoomThresholdDialog.tsx +69 -0
  52. package/src/components/FilterFeatures.tsx +7 -7
  53. package/src/components/FilterTranscripts.tsx +6 -6
  54. package/src/components/ImportFeatures.tsx +1 -1
  55. package/src/components/ManageChecks.tsx +1 -1
  56. package/src/components/MergeTranscripts.tsx +12 -15
  57. package/src/components/OntologyTermMultiSelect.tsx +11 -11
  58. package/src/components/OpenLocalFile.tsx +11 -7
  59. package/src/components/ViewCheckResults.tsx +1 -1
  60. package/src/components/index.ts +1 -0
  61. package/src/config.ts +6 -0
  62. package/src/index.ts +42 -105
  63. package/src/makeDisplayComponent.tsx +0 -1
  64. package/src/menus/index.ts +1 -0
  65. package/src/{ApolloInternetAccount/addMenuItems.ts → menus/topLevelMenu.ts} +56 -47
  66. package/src/menus/topLevelMenuAdmin.ts +154 -0
  67. package/src/session/session.ts +162 -116
  68. package/src/util/annotationFeatureUtils.ts +15 -21
  69. package/src/util/displayUtils.ts +149 -0
  70. package/src/util/glyphUtils.ts +152 -0
  71. package/src/util/mouseEventsUtils.ts +32 -0
@@ -1,10 +1,8 @@
1
1
  import { type AnnotationFeature } from '@apollo-annotation/mst'
2
2
  import { type MenuItem } from '@jbrowse/core/ui'
3
3
 
4
- import {
5
- type LinearApolloSixFrameDisplayMouseEvents,
6
- type MousePositionWithFeatureAndGlyph,
7
- } from '../stateModel/mouseEvents'
4
+ import { type MousePositionWithFeature } from '../../util'
5
+ import { type LinearApolloSixFrameDisplayMouseEvents } from '../stateModel/mouseEvents'
8
6
  import { type LinearApolloSixFrameDisplayRendering } from '../stateModel/rendering'
9
7
  import { type CanvasMouseEvent } from '../types'
10
8
 
@@ -30,25 +28,25 @@ export interface Glyph {
30
28
 
31
29
  onMouseDown(
32
30
  display: LinearApolloSixFrameDisplayMouseEvents,
33
- currentMousePosition: MousePositionWithFeatureAndGlyph,
31
+ currentMousePosition: MousePositionWithFeature,
34
32
  event: CanvasMouseEvent,
35
33
  ): void
36
34
 
37
35
  onMouseMove(
38
36
  display: LinearApolloSixFrameDisplayMouseEvents,
39
- currentMousePosition: MousePositionWithFeatureAndGlyph,
37
+ currentMousePosition: MousePositionWithFeature,
40
38
  event: CanvasMouseEvent,
41
39
  ): void
42
40
 
43
41
  onMouseLeave(
44
42
  display: LinearApolloSixFrameDisplayMouseEvents,
45
- currentMousePosition: MousePositionWithFeatureAndGlyph,
43
+ currentMousePosition: MousePositionWithFeature,
46
44
  event: CanvasMouseEvent,
47
45
  ): void
48
46
 
49
47
  onMouseUp(
50
48
  display: LinearApolloSixFrameDisplayMouseEvents,
51
- currentMousePosition: MousePositionWithFeatureAndGlyph,
49
+ currentMousePosition: MousePositionWithFeature,
52
50
  event: CanvasMouseEvent,
53
51
  ): void
54
52
 
@@ -57,7 +55,13 @@ export interface Glyph {
57
55
  context: CanvasRenderingContext2D,
58
56
  ): void
59
57
 
58
+ getContextMenuItemsForFeature(
59
+ display: LinearApolloSixFrameDisplayMouseEvents,
60
+ sourceFeature: AnnotationFeature,
61
+ ): MenuItem[]
62
+
60
63
  getContextMenuItems(
61
64
  display: LinearApolloSixFrameDisplayMouseEvents,
65
+ currentMousePosition: MousePositionWithFeature,
62
66
  ): MenuItem[]
63
67
  }
@@ -22,8 +22,9 @@ import { addDisposer, cast, getRoot, getSnapshot, types } from 'mobx-state-tree'
22
22
 
23
23
  import { type ApolloInternetAccountModel } from '../../ApolloInternetAccount/model'
24
24
  import { FilterFeatures } from '../../components/FilterFeatures'
25
- import { type ApolloSessionModel } from '../../session'
25
+ import { type ApolloSessionModel, type HoveredFeature } from '../../session'
26
26
  import { type ApolloRootModel } from '../../types'
27
+ import { EditZoomThresholdDialog } from '../../util/displayUtils'
27
28
 
28
29
  const minDisplayHeight = 20
29
30
 
@@ -38,6 +39,8 @@ export function baseModelFactory(
38
39
  graphical: true,
39
40
  table: false,
40
41
  showFeatureLabels: true,
42
+ showCheckResults: true,
43
+ zoomThreshold: 200,
41
44
  heightPreConfig: types.maybe(
42
45
  types.refinement(
43
46
  'displayHeight',
@@ -74,10 +77,13 @@ export function baseModelFactory(
74
77
  return 500
75
78
  }
76
79
  if (self.graphical) {
77
- return 200
80
+ return self.showFeatureLabels ? 400 : 200
78
81
  }
79
82
  return 300
80
83
  },
84
+ get zoomThresholdSetting() {
85
+ return self.zoomThreshold ?? getConf(self, 'zoomThreshold')
86
+ },
81
87
  }))
82
88
  .views((self) => ({
83
89
  get rendererTypeName() {
@@ -98,7 +104,7 @@ export function baseModelFactory(
98
104
  return regions
99
105
  },
100
106
  regionCannotBeRendered(/* region */) {
101
- if (self.lgv && self.lgv.bpPerPx >= 200) {
107
+ if (self.lgv && self.lgv.bpPerPx >= self.zoomThreshold) {
102
108
  return 'Zoom in to see annotations'
103
109
  }
104
110
  return
@@ -140,6 +146,10 @@ export function baseModelFactory(
140
146
  return (self.session as unknown as ApolloSessionModel)
141
147
  .apolloSelectedFeature
142
148
  },
149
+ get hoveredFeature(): HoveredFeature | undefined {
150
+ return (self.session as unknown as ApolloSessionModel)
151
+ .apolloHoveredFeature
152
+ },
143
153
  }))
144
154
  .actions((self) => ({
145
155
  setScrollTop(scrollTop: number) {
@@ -169,15 +179,21 @@ export function baseModelFactory(
169
179
  toggleShowFeatureLabels() {
170
180
  self.showFeatureLabels = !self.showFeatureLabels
171
181
  },
182
+ toggleShowCheckResults() {
183
+ self.showCheckResults = !self.showCheckResults
184
+ },
172
185
  updateFilteredFeatureTypes(types: string[]) {
173
186
  self.filteredFeatureTypes = cast(types)
174
187
  },
188
+ setZoomThresholdSetting({ zoomThreshold }: { zoomThreshold: number }) {
189
+ self.zoomThreshold = zoomThreshold
190
+ },
175
191
  }))
176
192
  .views((self) => {
177
193
  const { filteredFeatureTypes, trackMenuItems: superTrackMenuItems } = self
178
194
  return {
179
195
  trackMenuItems() {
180
- const { graphical, table, showFeatureLabels } = self
196
+ const { graphical, table, showFeatureLabels, showCheckResults } = self
181
197
  return [
182
198
  ...superTrackMenuItems(),
183
199
  {
@@ -216,6 +232,23 @@ export function baseModelFactory(
216
232
  self.toggleShowFeatureLabels()
217
233
  },
218
234
  },
235
+ {
236
+ label: 'Check Results',
237
+ type: 'checkbox',
238
+ checked: showCheckResults,
239
+ onClick: () => {
240
+ self.toggleShowCheckResults()
241
+ },
242
+ },
243
+ {
244
+ label: 'Change zoom threshold',
245
+ onClick: () => {
246
+ getSession(self).queueDialog((handleClose) => [
247
+ EditZoomThresholdDialog,
248
+ { model: self, handleClose },
249
+ ])
250
+ },
251
+ },
219
252
  ],
220
253
  },
221
254
  {
@@ -249,6 +282,11 @@ export function baseModelFactory(
249
282
  self.session as unknown as ApolloSessionModel
250
283
  ).apolloSetSelectedFeature(feature)
251
284
  },
285
+ setHoveredFeature(hoveredFeature?: HoveredFeature) {
286
+ ;(
287
+ self.session as unknown as ApolloSessionModel
288
+ ).apolloSetHoveredFeature(hoveredFeature)
289
+ },
252
290
  showFeatureDetailsWidget(
253
291
  feature: AnnotationFeature,
254
292
  customWidgetNameAndId?: [string, string],
@@ -1,9 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
2
2
 
3
- import {
4
- type AnnotationFeature,
5
- type TranscriptPartCoding,
6
- } from '@apollo-annotation/mst'
3
+ import { type AnnotationFeature } from '@apollo-annotation/mst'
7
4
  import type PluginManager from '@jbrowse/core/PluginManager'
8
5
  import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
9
6
  import {
@@ -22,7 +19,6 @@ import { baseModelFactory } from './base'
22
19
  export interface LayoutRow {
23
20
  rowNum: number
24
21
  feature: AnnotationFeature
25
- cds: TranscriptPartCoding | null
26
22
  }
27
23
 
28
24
  export function layoutsModelFactory(
@@ -136,7 +132,7 @@ export function layoutsModelFactory(
136
132
  featureLayout.set(rowNum, [])
137
133
  }
138
134
  const layoutRow = featureLayout.get(rowNum)
139
- layoutRow?.push({ rowNum, feature, cds: null })
135
+ layoutRow?.push({ rowNum, feature })
140
136
  const { children } = feature
141
137
  if (!children) {
142
138
  continue
@@ -158,7 +154,7 @@ export function layoutsModelFactory(
158
154
  ? self.geneTrackRowNums[0]
159
155
  : self.geneTrackRowNums[1]
160
156
  const layoutRow = featureLayout.get(rowNum)
161
- layoutRow?.push({ rowNum, feature: exon, cds: null })
157
+ layoutRow?.push({ rowNum, feature: exon })
162
158
  }
163
159
  }
164
160
  for (const cdsRow of cdsLocations) {
@@ -176,7 +172,7 @@ export function layoutsModelFactory(
176
172
  featureLayout.set(rowNum, [])
177
173
  }
178
174
  const layoutRow = featureLayout.get(rowNum)
179
- layoutRow?.push({ rowNum, feature: child, cds })
175
+ layoutRow?.push({ rowNum, feature: child })
180
176
  }
181
177
  }
182
178
  }
@@ -1,7 +1,4 @@
1
- import {
2
- type AnnotationFeature,
3
- type TranscriptPartCoding,
4
- } from '@apollo-annotation/mst'
1
+ import { type AnnotationFeature } from '@apollo-annotation/mst'
5
2
  import {
6
3
  LocationEndChange,
7
4
  LocationStartChange,
@@ -9,56 +6,23 @@ import {
9
6
  import type PluginManager from '@jbrowse/core/PluginManager'
10
7
  import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
11
8
  import { type MenuItem } from '@jbrowse/core/ui'
12
- import { type LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
9
+ import { getFrame } from '@jbrowse/core/util'
13
10
  import { autorun } from 'mobx'
14
11
  import { type Instance, addDisposer, cast } from 'mobx-state-tree'
15
12
  import { type CSSProperties } from 'react'
16
13
 
17
- import { type Edge, getPropagatedLocationChanges } from '../../util'
18
- import { type Coord } from '../components'
19
- import { type Glyph } from '../glyphs/Glyph'
14
+ import {
15
+ type Edge,
16
+ type MousePosition,
17
+ type MousePositionWithFeature,
18
+ getMousePosition,
19
+ getPropagatedLocationChanges,
20
+ isMousePositionWithFeature,
21
+ } from '../../util'
20
22
  import { type CanvasMouseEvent } from '../types'
21
23
 
22
24
  import { renderingModelFactory } from './rendering'
23
25
 
24
- export interface FeatureAndGlyphUnderMouse {
25
- cds: TranscriptPartCoding | null
26
- feature: AnnotationFeature
27
- topLevelFeature: AnnotationFeature
28
- glyph: Glyph
29
- }
30
-
31
- /** extended information about the position of the mouse on the canvas, including the refName, bp, and displayedRegion number */
32
- export interface MousePosition {
33
- x: number
34
- y: number
35
- refName: string
36
- bp: number
37
- regionNumber: number
38
- featureAndGlyphUnderMouse?: FeatureAndGlyphUnderMouse
39
- }
40
-
41
- export type MousePositionWithFeatureAndGlyph = Required<MousePosition>
42
-
43
- export function isMousePositionWithFeatureAndGlyph(
44
- mousePosition: MousePosition,
45
- ): mousePosition is MousePositionWithFeatureAndGlyph {
46
- return 'featureAndGlyphUnderMouse' in mousePosition
47
- }
48
-
49
- function getMousePosition(
50
- event: CanvasMouseEvent,
51
- lgv: LinearGenomeViewModel,
52
- ): MousePosition {
53
- const canvas = event.currentTarget
54
- const { clientX, clientY } = event
55
- const { left, top } = canvas.getBoundingClientRect()
56
- const x = clientX - left
57
- const y = clientY - top
58
- const { coord: bp, index: regionNumber, refName } = lgv.pxToBp(x)
59
- return { x, y, refName, bp, regionNumber }
60
- }
61
-
62
26
  export function mouseEventsModelIntermediateFactory(
63
27
  pluginManager: PluginManager,
64
28
  configSchema: AnyConfigurationSchemaType,
@@ -80,10 +44,9 @@ export function mouseEventsModelIntermediateFactory(
80
44
  shrinkParent: boolean
81
45
  } | null,
82
46
  cursor: undefined as CSSProperties['cursor'] | undefined,
83
- apolloHover: undefined as FeatureAndGlyphUnderMouse | undefined,
84
47
  }))
85
48
  .views((self) => ({
86
- getMousePosition(event: CanvasMouseEvent): MousePosition {
49
+ getMousePosition(event: React.MouseEvent): MousePosition {
87
50
  const mousePosition = getMousePosition(event, self.lgv)
88
51
  const { bp, regionNumber, y } = mousePosition
89
52
  const row = Math.floor(y / self.apolloRowHeight) + 1
@@ -92,6 +55,11 @@ export function mouseEventsModelIntermediateFactory(
92
55
  if (!layoutRow) {
93
56
  return mousePosition
94
57
  }
58
+ const { featureTypeOntology } =
59
+ self.session.apolloDataStore.ontologyManager
60
+ if (!featureTypeOntology) {
61
+ throw new Error('featureTypeOntology is undefined')
62
+ }
95
63
  let foundFeature
96
64
  if (self.geneTrackRowNums.includes(row)) {
97
65
  foundFeature = layoutRow.find(
@@ -107,25 +75,44 @@ export function mouseEventsModelIntermediateFactory(
107
75
  }
108
76
  } else {
109
77
  foundFeature = layoutRow.find((f) => {
110
- const featureID = f.feature.attributes.get('gff_id')?.toString()
111
- return (
112
- f.cds != null &&
113
- bp >= f.cds.min &&
114
- bp <= f.cds.max &&
115
- (featureID === undefined ||
116
- !self.filteredTranscripts.includes(featureID))
78
+ const { feature } = f
79
+ const featureID = feature.attributes.get('gff_id')?.toString()
80
+ const isTranscript = featureTypeOntology.isTypeOf(
81
+ feature.type,
82
+ 'transcript',
117
83
  )
84
+ if (!isTranscript) {
85
+ return false
86
+ }
87
+ for (const loc of feature.cdsLocations) {
88
+ for (const cds of loc) {
89
+ let rowNum: number = getFrame(
90
+ cds.min,
91
+ cds.max,
92
+ feature.strand ?? 1,
93
+ cds.phase,
94
+ )
95
+ rowNum = self.featureLabelSpacer(
96
+ rowNum < 0 ? -1 * rowNum + 5 : rowNum,
97
+ )
98
+ if (row === rowNum && bp >= cds.min && bp <= cds.max) {
99
+ return (
100
+ featureID === undefined ||
101
+ !self.filteredTranscripts.includes(featureID)
102
+ )
103
+ }
104
+ }
105
+ }
106
+ return false
118
107
  })
119
108
  }
120
109
  if (!foundFeature) {
121
110
  return mousePosition
122
111
  }
123
- const { feature, cds } = foundFeature
124
- const { topLevelFeature } = feature
125
- const glyph = self.getGlyph(feature)
112
+ const { feature } = foundFeature
126
113
  return {
127
114
  ...mousePosition,
128
- featureAndGlyphUnderMouse: { cds, feature, topLevelFeature, glyph },
115
+ feature,
129
116
  }
130
117
  },
131
118
  }))
@@ -144,9 +131,6 @@ export function mouseEventsModelIntermediateFactory(
144
131
  },
145
132
  }))
146
133
  .actions((self) => ({
147
- setApolloHover(n?: (typeof self)['apolloHover']) {
148
- self.apolloHover = n
149
- },
150
134
  setCursor(cursor?: CSSProperties['cursor']) {
151
135
  if (self.cursor !== cursor) {
152
136
  self.cursor = cursor
@@ -172,21 +156,25 @@ export function mouseEventsModelFactory(
172
156
  mouseEventsModelIntermediateFactory(pluginManager, configSchema)
173
157
 
174
158
  return LinearApolloSixFrameDisplayMouseEvents.views((self) => ({
175
- contextMenuItems(contextCoord?: Coord): MenuItem[] {
176
- const { apolloHover } = self
177
- if (!(apolloHover && contextCoord)) {
159
+ contextMenuItems(event: React.MouseEvent<HTMLDivElement>): MenuItem[] {
160
+ const { hoveredFeature } = self
161
+ if (!hoveredFeature) {
178
162
  return []
179
163
  }
180
- const { topLevelFeature } = apolloHover
164
+ const mousePosition = self.getMousePosition(event)
165
+ const { topLevelFeature } = hoveredFeature.feature
181
166
  const glyph = self.getGlyph(topLevelFeature)
182
- return glyph.getContextMenuItems(self)
167
+ if (isMousePositionWithFeature(mousePosition)) {
168
+ return glyph.getContextMenuItems(self, mousePosition)
169
+ }
170
+ return []
183
171
  },
184
172
  }))
185
173
  .actions((self) => ({
186
174
  // explicitly pass in a feature in case it's not the same as the one in
187
175
  // mousePosition (e.g. if features are drawn overlapping).
188
176
  startDrag(
189
- mousePosition: MousePositionWithFeatureAndGlyph,
177
+ mousePosition: MousePositionWithFeature,
190
178
  feature: AnnotationFeature,
191
179
  edge: Edge,
192
180
  shrinkParent = false,
@@ -251,12 +239,9 @@ export function mouseEventsModelFactory(
251
239
  .actions((self) => ({
252
240
  onMouseDown(event: CanvasMouseEvent) {
253
241
  const mousePosition = self.getMousePosition(event)
254
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
255
- mousePosition.featureAndGlyphUnderMouse.glyph.onMouseDown(
256
- self,
257
- mousePosition,
258
- event,
259
- )
242
+ if (isMousePositionWithFeature(mousePosition)) {
243
+ const glyph = self.getGlyph(mousePosition.feature)
244
+ glyph.onMouseDown(self, mousePosition, event)
260
245
  }
261
246
  },
262
247
  onMouseMove(event: CanvasMouseEvent) {
@@ -266,38 +251,29 @@ export function mouseEventsModelFactory(
266
251
  self.continueDrag(mousePosition, event)
267
252
  return
268
253
  }
269
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
270
- mousePosition.featureAndGlyphUnderMouse.glyph.onMouseMove(
271
- self,
272
- mousePosition,
273
- event,
274
- )
254
+ if (isMousePositionWithFeature(mousePosition)) {
255
+ const glyph = self.getGlyph(mousePosition.feature)
256
+ glyph.onMouseMove(self, mousePosition, event)
275
257
  } else {
276
- self.setApolloHover()
258
+ self.setHoveredFeature()
277
259
  self.setCursor()
278
260
  }
279
261
  },
280
262
  onMouseLeave(event: CanvasMouseEvent) {
281
263
  self.setDragging()
282
- self.setApolloHover()
264
+ self.setHoveredFeature()
283
265
 
284
266
  const mousePosition = self.getMousePosition(event)
285
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
286
- mousePosition.featureAndGlyphUnderMouse.glyph.onMouseLeave(
287
- self,
288
- mousePosition,
289
- event,
290
- )
267
+ if (isMousePositionWithFeature(mousePosition)) {
268
+ const glyph = self.getGlyph(mousePosition.feature)
269
+ glyph.onMouseLeave(self, mousePosition, event)
291
270
  }
292
271
  },
293
272
  onMouseUp(event: CanvasMouseEvent) {
294
273
  const mousePosition = self.getMousePosition(event)
295
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
296
- mousePosition.featureAndGlyphUnderMouse.glyph.onMouseUp(
297
- self,
298
- mousePosition,
299
- event,
300
- )
274
+ if (isMousePositionWithFeature(mousePosition)) {
275
+ const glyph = self.getGlyph(mousePosition.feature)
276
+ glyph.onMouseUp(self, mousePosition, event)
301
277
  } else {
302
278
  self.setSelectedFeature()
303
279
  }
@@ -329,11 +305,11 @@ export function mouseEventsModelFactory(
329
305
  self.featuresHeight,
330
306
  )
331
307
 
332
- const { apolloDragging, apolloHover } = self
333
- if (!apolloHover) {
308
+ const { apolloDragging, hoveredFeature } = self
309
+ if (!hoveredFeature) {
334
310
  return
335
311
  }
336
- const { glyph } = apolloHover
312
+ const glyph = self.getGlyph(hoveredFeature.feature)
337
313
 
338
314
  // draw mouseover hovers
339
315
  glyph.drawHover(self, ctx)
@@ -2,7 +2,7 @@
2
2
  import type PluginManager from '@jbrowse/core/PluginManager'
3
3
  import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
4
4
  import { doesIntersect2 } from '@jbrowse/core/util'
5
- import { type Theme } from '@mui/material'
5
+ import { type Theme, createTheme } from '@mui/material'
6
6
  import { autorun } from 'mobx'
7
7
  import { type Instance, addDisposer, types } from 'mobx-state-tree'
8
8
 
@@ -10,7 +10,7 @@ import { type ApolloSessionModel } from '../../session'
10
10
 
11
11
  import { layoutsModelFactory } from './layouts'
12
12
 
13
- export function renderingModelIntermediateFactory(
13
+ export function renderingModelFactory(
14
14
  pluginManager: PluginManager,
15
15
  configSchema: AnyConfigurationSchemaType,
16
16
  ) {
@@ -23,11 +23,10 @@ export function renderingModelIntermediateFactory(
23
23
  'LinearApolloSixFrameDisplayRendering',
24
24
  )
25
25
  .props({
26
- sequenceRowHeight: 15,
27
26
  apolloRowHeight: 20,
28
27
  detailsMinHeight: 200,
29
28
  detailsHeight: 200,
30
- lastRowTooltipBufferHeight: 80,
29
+ lastRowTooltipBufferHeight: 120,
31
30
  isShown: true,
32
31
  filteredTranscripts: types.array(types.string),
33
32
  })
@@ -35,7 +34,7 @@ export function renderingModelIntermediateFactory(
35
34
  canvas: null as HTMLCanvasElement | null,
36
35
  overlayCanvas: null as HTMLCanvasElement | null,
37
36
  collaboratorCanvas: null as HTMLCanvasElement | null,
38
- theme: undefined as Theme | undefined,
37
+ theme: createTheme(),
39
38
  }))
40
39
  .views((self) => ({
41
40
  get featuresHeight() {
@@ -70,6 +69,8 @@ export function renderingModelIntermediateFactory(
70
69
  setTheme(theme: Theme) {
71
70
  self.theme = theme
72
71
  },
72
+ }))
73
+ .actions((self) => ({
73
74
  afterAttach() {
74
75
  addDisposer(
75
76
  self,
@@ -130,69 +131,56 @@ export function renderingModelIntermediateFactory(
130
131
  { name: 'LinearApolloSixFrameDisplayRenderCollaborators' },
131
132
  ),
132
133
  )
133
- },
134
- }))
135
- }
136
-
137
- export function renderingModelFactory(
138
- pluginManager: PluginManager,
139
- configSchema: AnyConfigurationSchemaType,
140
- ) {
141
- const LinearApolloSixFrameDisplayRendering =
142
- renderingModelIntermediateFactory(pluginManager, configSchema)
143
-
144
- return LinearApolloSixFrameDisplayRendering.actions((self) => ({
145
- afterAttach() {
146
- addDisposer(
147
- self,
148
- autorun(
149
- () => {
150
- const { canvas, featureLayouts, featuresHeight, lgv } = self
151
- if (!lgv.initialized || self.regionCannotBeRendered()) {
152
- return
153
- }
154
- const { displayedRegions, dynamicBlocks } = lgv
134
+ addDisposer(
135
+ self,
136
+ autorun(
137
+ () => {
138
+ const { canvas, featureLayouts, featuresHeight, lgv } = self
139
+ if (!lgv.initialized || self.regionCannotBeRendered()) {
140
+ return
141
+ }
142
+ const { displayedRegions, dynamicBlocks } = lgv
155
143
 
156
- const ctx = canvas?.getContext('2d')
157
- if (!ctx) {
158
- return
159
- }
160
- ctx.clearRect(0, 0, dynamicBlocks.totalWidthPx, featuresHeight)
161
- for (const [idx, featureLayout] of featureLayouts.entries()) {
162
- const displayedRegion = displayedRegions[idx]
163
- for (const [row, featureLayoutRow] of featureLayout.entries()) {
164
- for (const { feature } of featureLayoutRow) {
165
- if (!feature.looksLikeGene) {
166
- continue
167
- }
168
- if (
169
- !doesIntersect2(
170
- displayedRegion.start,
171
- displayedRegion.end,
172
- feature.min,
173
- feature.max,
174
- )
175
- ) {
176
- continue
177
- }
178
- const { topLevelFeature } = feature
179
- const glyph = self.getGlyph(topLevelFeature)
180
- if (glyph !== undefined) {
181
- glyph.draw(ctx, topLevelFeature, row, self, idx)
144
+ const ctx = canvas?.getContext('2d')
145
+ if (!ctx) {
146
+ return
147
+ }
148
+ ctx.clearRect(0, 0, dynamicBlocks.totalWidthPx, featuresHeight)
149
+ for (const [idx, featureLayout] of featureLayouts.entries()) {
150
+ const displayedRegion = displayedRegions[idx]
151
+ for (const [row, featureLayoutRow] of featureLayout.entries()) {
152
+ for (const { feature } of featureLayoutRow) {
153
+ if (!feature.looksLikeGene) {
154
+ continue
155
+ }
156
+ if (
157
+ !doesIntersect2(
158
+ displayedRegion.start,
159
+ displayedRegion.end,
160
+ feature.min,
161
+ feature.max,
162
+ )
163
+ ) {
164
+ continue
165
+ }
166
+ const { topLevelFeature } = feature
167
+ const glyph = self.getGlyph(topLevelFeature)
168
+ if (glyph !== undefined) {
169
+ glyph.draw(ctx, topLevelFeature, row, self, idx)
170
+ }
182
171
  }
183
172
  }
184
173
  }
185
- }
186
- },
187
- { name: 'LinearApolloSixFrameDisplayRenderFeatures' },
188
- ),
189
- )
190
- },
191
- }))
174
+ },
175
+ { name: 'LinearApolloSixFrameDisplayRenderFeatures' },
176
+ ),
177
+ )
178
+ },
179
+ }))
192
180
  }
193
181
 
194
182
  export type LinearApolloSixFrameDisplayRenderingModel = ReturnType<
195
- typeof renderingModelIntermediateFactory
183
+ typeof renderingModelFactory
196
184
  >
197
185
  // eslint disable because of
198
186
  // https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time