@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.
Files changed (131) hide show
  1. package/dist/index.esm.js +5466 -4490
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +5283 -4318
  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 +6806 -4088
  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 +4 -4
  12. package/src/ApolloInternetAccount/addMenuItems.ts +5 -2
  13. package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -0
  14. package/src/ApolloInternetAccount/components/LoginButtons.tsx +1 -1
  15. package/src/ApolloInternetAccount/components/LoginIcons.tsx +1 -1
  16. package/src/ApolloInternetAccount/configSchema.ts +1 -1
  17. package/src/ApolloInternetAccount/model.ts +11 -10
  18. package/src/ApolloJobModel.ts +1 -1
  19. package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +8 -6
  20. package/src/ApolloRefNameAliasAdapter/index.ts +2 -2
  21. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +17 -4
  22. package/src/ApolloSequenceAdapter/index.ts +1 -1
  23. package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +8 -7
  24. package/src/ApolloTextSearchAdapter/index.ts +1 -1
  25. package/src/BackendDrivers/BackendDriver.ts +7 -7
  26. package/src/BackendDrivers/CollaborationServerDriver.ts +14 -10
  27. package/src/BackendDrivers/DesktopFileDriver.ts +11 -10
  28. package/src/BackendDrivers/InMemoryFileDriver.ts +10 -6
  29. package/src/ChangeManager.ts +5 -5
  30. package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +92 -20
  31. package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +170 -27
  32. package/src/FeatureDetailsWidget/AttributeKey.tsx +50 -0
  33. package/src/FeatureDetailsWidget/AttributeKeySelector.tsx +104 -0
  34. package/src/FeatureDetailsWidget/Attributes.tsx +213 -320
  35. package/src/FeatureDetailsWidget/BasicInformation.tsx +8 -9
  36. package/src/FeatureDetailsWidget/DefaultAttributeEditor.tsx +104 -0
  37. package/src/FeatureDetailsWidget/DefaultAttributeViewer.tsx +22 -0
  38. package/src/FeatureDetailsWidget/FeatureDetailsNavigation.tsx +10 -8
  39. package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -1
  40. package/src/FeatureDetailsWidget/Sequence.tsx +18 -35
  41. package/src/FeatureDetailsWidget/StringTextField.tsx +1 -1
  42. package/src/FeatureDetailsWidget/TranscriptSequence.tsx +140 -95
  43. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +600 -0
  44. package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +54 -0
  45. package/src/FeatureDetailsWidget/model.ts +8 -3
  46. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +19 -12
  47. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +19 -41
  48. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +44 -22
  49. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +6 -5
  50. package/src/LinearApolloDisplay/glyphs/Glyph.ts +7 -7
  51. package/src/LinearApolloDisplay/stateModel/base.ts +52 -10
  52. package/src/LinearApolloDisplay/stateModel/index.ts +4 -3
  53. package/src/LinearApolloDisplay/stateModel/layouts.ts +8 -34
  54. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +13 -12
  55. package/src/LinearApolloDisplay/stateModel/rendering.ts +63 -31
  56. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +221 -0
  57. package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +40 -0
  58. package/src/LinearApolloSixFrameDisplay/components/index.ts +2 -0
  59. package/src/LinearApolloSixFrameDisplay/configSchema.ts +7 -0
  60. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +821 -0
  61. package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +63 -0
  62. package/src/LinearApolloSixFrameDisplay/glyphs/index.ts +1 -0
  63. package/src/LinearApolloSixFrameDisplay/index.ts +2 -0
  64. package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +261 -0
  65. package/src/LinearApolloSixFrameDisplay/stateModel/index.ts +27 -0
  66. package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +236 -0
  67. package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +349 -0
  68. package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +199 -0
  69. package/src/LinearApolloSixFrameDisplay/types.ts +1 -0
  70. package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +10 -1
  71. package/src/OntologyManager/OntologyStore/fulltext.test.ts +1 -1
  72. package/src/OntologyManager/OntologyStore/fulltext.ts +8 -3
  73. package/src/OntologyManager/OntologyStore/index.test.ts +4 -1
  74. package/src/OntologyManager/OntologyStore/index.ts +19 -14
  75. package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +6 -5
  76. package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +11 -5
  77. package/src/OntologyManager/index.ts +10 -6
  78. package/src/OntologyManager/util.ts +3 -2
  79. package/src/TabularEditor/HybridGrid/ChangeHandling.ts +2 -2
  80. package/src/TabularEditor/HybridGrid/Feature.tsx +9 -8
  81. package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +1 -1
  82. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +3 -2
  83. package/src/TabularEditor/HybridGrid/NumberCell.tsx +8 -1
  84. package/src/TabularEditor/HybridGrid/ToolBar.tsx +15 -13
  85. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +9 -33
  86. package/src/TabularEditor/TabularEditorPane.tsx +1 -1
  87. package/src/TabularEditor/model.ts +2 -2
  88. package/src/TabularEditor/types.ts +5 -2
  89. package/src/components/AddAssembly.tsx +611 -291
  90. package/src/components/AddChildFeature.tsx +6 -5
  91. package/src/components/AddFeature.tsx +211 -38
  92. package/src/components/AddRefSeqAliases.tsx +14 -12
  93. package/src/components/CopyFeature.tsx +8 -7
  94. package/src/components/CreateApolloAnnotation.tsx +154 -46
  95. package/src/components/DeleteAssembly.tsx +9 -8
  96. package/src/components/DeleteFeature.tsx +5 -4
  97. package/src/components/Dialog.tsx +1 -1
  98. package/src/components/DownloadGFF3.tsx +11 -10
  99. package/src/components/FilterFeatures.tsx +6 -4
  100. package/src/components/ImportFeatures.tsx +7 -6
  101. package/src/components/LogOut.tsx +5 -4
  102. package/src/components/ManageChecks.tsx +9 -8
  103. package/src/components/ManageUsers.tsx +11 -10
  104. package/src/components/OntologyTermAutocomplete.tsx +5 -5
  105. package/src/components/OntologyTermMultiSelect.tsx +9 -6
  106. package/src/components/OpenLocalFile.tsx +4 -3
  107. package/src/components/ViewChangeLog.tsx +7 -6
  108. package/src/components/ViewCheckResults.tsx +8 -7
  109. package/src/components/index.ts +0 -1
  110. package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -0
  111. package/src/extensions/annotationFromJBrowseFeature.ts +14 -12
  112. package/src/extensions/annotationFromPileup.ts +6 -6
  113. package/src/index.ts +33 -50
  114. package/src/makeDisplayComponent.tsx +93 -41
  115. package/src/session/ClientDataStore.ts +21 -17
  116. package/src/session/session.ts +20 -26
  117. package/src/types.ts +4 -4
  118. package/src/util/annotationFeatureUtils.ts +53 -0
  119. package/src/util/index.ts +4 -3
  120. package/src/util/loadAssemblyIntoClient.ts +10 -3
  121. package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +0 -13
  122. package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +0 -707
  123. package/src/ApolloSixFrameRenderer/configSchema.ts +0 -7
  124. package/src/ApolloSixFrameRenderer/index.ts +0 -3
  125. package/src/FeatureDetailsWidget/TranscriptBasic.tsx +0 -200
  126. package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +0 -19
  127. package/src/SixFrameFeatureDisplay/components/index.ts +0 -1
  128. package/src/SixFrameFeatureDisplay/configSchema.ts +0 -21
  129. package/src/SixFrameFeatureDisplay/index.ts +0 -2
  130. package/src/SixFrameFeatureDisplay/stateModel.ts +0 -439
  131. 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>
@@ -127,7 +127,16 @@ export const genericEnglishStopwords = new Set([
127
127
  'don',
128
128
  'should',
129
129
  'now',
130
- ...'1234567890',
130
+ '0',
131
+ '1',
132
+ '2',
133
+ '3',
134
+ '4',
135
+ '5',
136
+ '6',
137
+ '7',
138
+ '8',
139
+ '9',
131
140
  ])
132
141
 
133
142
  /**
@@ -6,7 +6,7 @@ import {
6
6
  extractWords,
7
7
  getWords,
8
8
  } from './fulltext'
9
- import { OntologyDBNode } from './indexeddb-schema'
9
+ import { type OntologyDBNode } from './indexeddb-schema'
10
10
 
11
11
  const testNode: OntologyDBNode = {
12
12
  id: 'http://purl.obolibrary.org/obo/SO_0000001',
@@ -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
- import OntologyStore, { Transaction } from '.'
12
- import { TextIndexFieldDefinition } from '..'
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 { OntologyDB, OntologyDBEdge, isDeprecated } from './indexeddb-schema'
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
- import { OntologyStoreOptions, SourceLocation } from '.'
9
+
10
+ import { type OntologyStoreOptions, type SourceLocation } from '.'
10
11
 
11
12
  /** metadata about this IndexedDB ontology database */
12
13
  export interface Meta {