@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
@@ -6,110 +6,22 @@ import {
6
6
  import type PluginManager from '@jbrowse/core/PluginManager'
7
7
  import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
8
8
  import { type MenuItem } from '@jbrowse/core/ui'
9
- import { type Frame, getFrame } from '@jbrowse/core/util'
10
- import { type LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
11
- import { type Theme } from '@mui/material'
12
9
  import { autorun } from 'mobx'
13
10
  import { type Instance, addDisposer } from 'mobx-state-tree'
14
11
  import { type CSSProperties } from 'react'
15
12
 
16
- import { type Edge, getPropagatedLocationChanges } from '../../util'
17
- import { type Glyph } from '../glyphs/Glyph'
13
+ import {
14
+ type Edge,
15
+ type MousePosition,
16
+ type MousePositionWithFeature,
17
+ getMousePosition,
18
+ getPropagatedLocationChanges,
19
+ isMousePositionWithFeature,
20
+ } from '../../util'
18
21
  import { type CanvasMouseEvent } from '../types'
19
22
 
20
23
  import { renderingModelFactory } from './rendering'
21
24
 
22
- export interface FeatureAndGlyphUnderMouse {
23
- feature: AnnotationFeature
24
- topLevelFeature: AnnotationFeature
25
- glyph: Glyph
26
- }
27
-
28
- /** extended information about the position of the mouse on the canvas, including the refName, bp, and displayedRegion number */
29
- export interface MousePosition {
30
- x: number
31
- y: number
32
- refName: string
33
- bp: number
34
- regionNumber: number
35
- featureAndGlyphUnderMouse?: FeatureAndGlyphUnderMouse
36
- }
37
-
38
- export type MousePositionWithFeatureAndGlyph = Required<MousePosition>
39
-
40
- export function isMousePositionWithFeatureAndGlyph(
41
- mousePosition: MousePosition,
42
- ): mousePosition is MousePositionWithFeatureAndGlyph {
43
- return 'featureAndGlyphUnderMouse' in mousePosition
44
- }
45
-
46
- function getMousePosition(
47
- event: React.MouseEvent,
48
- lgv: LinearGenomeViewModel,
49
- ): MousePosition {
50
- const canvas = event.currentTarget
51
- const { clientX, clientY } = event
52
- const { left, top } = canvas.getBoundingClientRect()
53
- const x = clientX - left
54
- const y = clientY - top
55
- const { coord: bp, index: regionNumber, refName } = lgv.pxToBp(x)
56
- return { x, y, refName, bp, regionNumber }
57
- }
58
-
59
- function getTranslationRow(frame: Frame, bpPerPx: number) {
60
- const offset = bpPerPx <= 1 ? 2 : 0
61
- switch (frame) {
62
- case 3: {
63
- return 0
64
- }
65
- case 2: {
66
- return 1
67
- }
68
- case 1: {
69
- return 2
70
- }
71
- case -1: {
72
- return 3 + offset
73
- }
74
- case -2: {
75
- return 4 + offset
76
- }
77
- case -3: {
78
- return 5 + offset
79
- }
80
- }
81
- }
82
-
83
- function getSeqRow(
84
- strand: 1 | -1 | undefined,
85
- bpPerPx: number,
86
- ): number | undefined {
87
- if (bpPerPx > 1 || strand === undefined) {
88
- return
89
- }
90
- return strand === 1 ? 3 : 4
91
- }
92
-
93
- function highlightSeq(
94
- seqTrackOverlayctx: CanvasRenderingContext2D,
95
- theme: Theme | undefined,
96
- startPx: number,
97
- sequenceRowHeight: number,
98
- row: number | undefined,
99
- widthPx: number,
100
- ) {
101
- if (row !== undefined) {
102
- seqTrackOverlayctx.fillStyle =
103
- theme?.palette.action.focus ?? 'rgba(0,0,0,0.04)'
104
- seqTrackOverlayctx.fillRect(
105
- startPx,
106
- sequenceRowHeight * row,
107
- widthPx,
108
- sequenceRowHeight,
109
- )
110
- }
111
- }
112
-
113
25
  export function mouseEventsModelIntermediateFactory(
114
26
  pluginManager: PluginManager,
115
27
  configSchema: AnyConfigurationSchemaType,
@@ -129,7 +41,6 @@ export function mouseEventsModelIntermediateFactory(
129
41
  shrinkParent: boolean
130
42
  } | null,
131
43
  cursor: undefined as CSSProperties['cursor'] | undefined,
132
- apolloHover: undefined as FeatureAndGlyphUnderMouse | undefined,
133
44
  }))
134
45
  .views((self) => ({
135
46
  getMousePosition(event: React.MouseEvent): MousePosition {
@@ -170,7 +81,7 @@ export function mouseEventsModelIntermediateFactory(
170
81
  }
171
82
  return {
172
83
  ...mousePosition,
173
- featureAndGlyphUnderMouse: { feature, topLevelFeature, glyph },
84
+ feature,
174
85
  }
175
86
  },
176
87
  }))
@@ -189,9 +100,6 @@ export function mouseEventsModelIntermediateFactory(
189
100
  },
190
101
  }))
191
102
  .actions((self) => ({
192
- setApolloHover(n?: (typeof self)['apolloHover']) {
193
- self.apolloHover = n
194
- },
195
103
  setCursor(cursor?: CSSProperties['cursor']) {
196
104
  if (self.cursor !== cursor) {
197
105
  self.cursor = cursor
@@ -210,150 +118,25 @@ export function mouseEventsModelIntermediateFactory(
210
118
  }))
211
119
  }
212
120
 
213
- export function mouseEventsSeqHightlightModelFactory(
214
- pluginManager: PluginManager,
215
- configSchema: AnyConfigurationSchemaType,
216
- ) {
217
- const LinearApolloDisplayRendering = mouseEventsModelIntermediateFactory(
218
- pluginManager,
219
- configSchema,
220
- )
221
-
222
- return LinearApolloDisplayRendering.actions((self) => ({
223
- afterAttach() {
224
- addDisposer(
225
- self,
226
- autorun(
227
- () => {
228
- // This type is wrong in @jbrowse/core
229
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
230
- if (!self.lgv.initialized || self.regionCannotBeRendered()) {
231
- return
232
- }
233
- const seqTrackOverlayctx =
234
- self.seqTrackOverlayCanvas?.getContext('2d')
235
- if (!seqTrackOverlayctx) {
236
- return
237
- }
238
-
239
- seqTrackOverlayctx.clearRect(
240
- 0,
241
- 0,
242
- self.lgv.dynamicBlocks.totalWidthPx,
243
- self.lgv.bpPerPx <= 1 ? 125 : 95,
244
- )
245
-
246
- const {
247
- apolloHover,
248
- lgv,
249
- regions,
250
- sequenceRowHeight,
251
- session,
252
- theme,
253
- } = self
254
-
255
- if (!apolloHover) {
256
- return
257
- }
258
- const { feature } = apolloHover
259
-
260
- const { featureTypeOntology } =
261
- session.apolloDataStore.ontologyManager
262
- if (!featureTypeOntology) {
263
- throw new Error('featureTypeOntology is undefined')
264
- }
265
- for (const [idx, region] of regions.entries()) {
266
- if (featureTypeOntology.isTypeOf(feature.type, 'CDS')) {
267
- const parentFeature = feature.parent
268
- if (!parentFeature) {
269
- continue
270
- }
271
- const cdsLocs = parentFeature.cdsLocations.find(
272
- (loc) =>
273
- feature.min === loc.at(0)?.min &&
274
- feature.max === loc.at(-1)?.max,
275
- )
276
- if (!cdsLocs) {
277
- continue
278
- }
279
- for (const dl of cdsLocs) {
280
- const frame = getFrame(
281
- dl.min,
282
- dl.max,
283
- feature.strand ?? 1,
284
- dl.phase,
285
- )
286
- const row = getTranslationRow(frame, lgv.bpPerPx)
287
- const offset =
288
- (lgv.bpToPx({
289
- refName: region.refName,
290
- coord: dl.min,
291
- regionNumber: idx,
292
- })?.offsetPx ?? 0) - lgv.offsetPx
293
- const widthPx = (dl.max - dl.min) / lgv.bpPerPx
294
- const startPx = lgv.displayedRegions[idx].reversed
295
- ? offset - widthPx
296
- : offset
297
-
298
- highlightSeq(
299
- seqTrackOverlayctx,
300
- theme,
301
- startPx,
302
- sequenceRowHeight,
303
- row,
304
- widthPx,
305
- )
306
- }
307
- } else {
308
- const row = getSeqRow(feature.strand, lgv.bpPerPx)
309
- const offset =
310
- (lgv.bpToPx({
311
- refName: region.refName,
312
- coord: feature.min,
313
- regionNumber: idx,
314
- })?.offsetPx ?? 0) - lgv.offsetPx
315
- const widthPx = feature.length / lgv.bpPerPx
316
- const startPx = lgv.displayedRegions[idx].reversed
317
- ? offset - widthPx
318
- : offset
319
-
320
- highlightSeq(
321
- seqTrackOverlayctx,
322
- theme,
323
- startPx,
324
- sequenceRowHeight,
325
- row,
326
- widthPx,
327
- )
328
- }
329
- }
330
- },
331
- { name: 'LinearApolloDisplayRenderSeqHighlight' },
332
- ),
333
- )
334
- },
335
- }))
336
- }
337
-
338
121
  export function mouseEventsModelFactory(
339
122
  pluginManager: PluginManager,
340
123
  configSchema: AnyConfigurationSchemaType,
341
124
  ) {
342
- const LinearApolloDisplayMouseEvents = mouseEventsSeqHightlightModelFactory(
125
+ const LinearApolloDisplayMouseEvents = mouseEventsModelIntermediateFactory(
343
126
  pluginManager,
344
127
  configSchema,
345
128
  )
346
129
 
347
130
  return LinearApolloDisplayMouseEvents.views((self) => ({
348
131
  contextMenuItems(event: React.MouseEvent<HTMLDivElement>): MenuItem[] {
349
- const { apolloHover } = self
350
- if (!apolloHover) {
132
+ const { hoveredFeature } = self
133
+ if (!hoveredFeature) {
351
134
  return []
352
135
  }
353
136
  const mousePosition = self.getMousePosition(event)
354
- const { topLevelFeature } = apolloHover
137
+ const { topLevelFeature } = hoveredFeature.feature
355
138
  const glyph = self.getGlyph(topLevelFeature)
356
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
139
+ if (isMousePositionWithFeature(mousePosition)) {
357
140
  return glyph.getContextMenuItems(self, mousePosition)
358
141
  }
359
142
  return []
@@ -363,7 +146,7 @@ export function mouseEventsModelFactory(
363
146
  // explicitly pass in a feature in case it's not the same as the one in
364
147
  // mousePosition (e.g. if features are drawn overlapping).
365
148
  startDrag(
366
- mousePosition: MousePositionWithFeatureAndGlyph,
149
+ mousePosition: MousePositionWithFeature,
367
150
  feature: AnnotationFeature,
368
151
  edge: Edge,
369
152
  shrinkParent = false,
@@ -428,12 +211,9 @@ export function mouseEventsModelFactory(
428
211
  .actions((self) => ({
429
212
  onMouseDown(event: CanvasMouseEvent) {
430
213
  const mousePosition = self.getMousePosition(event)
431
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
432
- mousePosition.featureAndGlyphUnderMouse.glyph.onMouseDown(
433
- self,
434
- mousePosition,
435
- event,
436
- )
214
+ if (isMousePositionWithFeature(mousePosition)) {
215
+ const glyph = self.getGlyph(mousePosition.feature)
216
+ glyph.onMouseDown(self, mousePosition, event)
437
217
  }
438
218
  },
439
219
  onMouseMove(event: CanvasMouseEvent) {
@@ -443,38 +223,29 @@ export function mouseEventsModelFactory(
443
223
  self.continueDrag(mousePosition, event)
444
224
  return
445
225
  }
446
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
447
- mousePosition.featureAndGlyphUnderMouse.glyph.onMouseMove(
448
- self,
449
- mousePosition,
450
- event,
451
- )
226
+ if (isMousePositionWithFeature(mousePosition)) {
227
+ const glyph = self.getGlyph(mousePosition.feature)
228
+ glyph.onMouseMove(self, mousePosition, event)
452
229
  } else {
453
- self.setApolloHover()
230
+ self.setHoveredFeature()
454
231
  self.setCursor()
455
232
  }
456
233
  },
457
234
  onMouseLeave(event: CanvasMouseEvent) {
458
235
  self.setDragging()
459
- self.setApolloHover()
236
+ self.setHoveredFeature()
460
237
 
461
238
  const mousePosition = self.getMousePosition(event)
462
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
463
- mousePosition.featureAndGlyphUnderMouse.glyph.onMouseLeave(
464
- self,
465
- mousePosition,
466
- event,
467
- )
239
+ if (isMousePositionWithFeature(mousePosition)) {
240
+ const glyph = self.getGlyph(mousePosition.feature)
241
+ glyph.onMouseLeave(self, mousePosition, event)
468
242
  }
469
243
  },
470
244
  onMouseUp(event: CanvasMouseEvent) {
471
245
  const mousePosition = self.getMousePosition(event)
472
- if (isMousePositionWithFeatureAndGlyph(mousePosition)) {
473
- mousePosition.featureAndGlyphUnderMouse.glyph.onMouseUp(
474
- self,
475
- mousePosition,
476
- event,
477
- )
246
+ if (isMousePositionWithFeature(mousePosition)) {
247
+ const glyph = self.getGlyph(mousePosition.feature)
248
+ glyph.onMouseUp(self, mousePosition, event)
478
249
  } else {
479
250
  self.setSelectedFeature()
480
251
  }
@@ -506,11 +277,11 @@ export function mouseEventsModelFactory(
506
277
  self.featuresHeight,
507
278
  )
508
279
 
509
- const { apolloDragging, apolloHover } = self
510
- if (!apolloHover) {
280
+ const { apolloDragging, hoveredFeature } = self
281
+ if (!hoveredFeature) {
511
282
  return
512
283
  }
513
- const { glyph } = apolloHover
284
+ const glyph = self.getGlyph(hoveredFeature.feature)
514
285
 
515
286
  // draw mouseover hovers
516
287
  glyph.drawHover(self, ctx)