@apollo-annotation/jbrowse-plugin-apollo 0.1.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.
Files changed (116) hide show
  1. package/README.md +76 -0
  2. package/dist/index.esm.js +10248 -0
  3. package/dist/index.esm.js.map +1 -0
  4. package/dist/index.js +7 -0
  5. package/dist/jbrowse-plugin-apollo.cjs.development.js +10298 -0
  6. package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -0
  7. package/dist/jbrowse-plugin-apollo.cjs.production.min.js +2 -0
  8. package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -0
  9. package/dist/jbrowse-plugin-apollo.umd.development.js +46957 -0
  10. package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -0
  11. package/dist/jbrowse-plugin-apollo.umd.production.min.js +2 -0
  12. package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -0
  13. package/package.json +130 -0
  14. package/src/ApolloInternetAccount/addMenuItems.ts +94 -0
  15. package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +121 -0
  16. package/src/ApolloInternetAccount/components/LoginButtons.tsx +62 -0
  17. package/src/ApolloInternetAccount/components/LoginIcons.tsx +74 -0
  18. package/src/ApolloInternetAccount/configSchema.ts +26 -0
  19. package/src/ApolloInternetAccount/index.ts +2 -0
  20. package/src/ApolloInternetAccount/model.ts +448 -0
  21. package/src/ApolloJobModel.ts +117 -0
  22. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +186 -0
  23. package/src/ApolloSequenceAdapter/configSchema.ts +12 -0
  24. package/src/ApolloSequenceAdapter/index.ts +21 -0
  25. package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +12 -0
  26. package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +692 -0
  27. package/src/ApolloSixFrameRenderer/configSchema.ts +7 -0
  28. package/src/ApolloSixFrameRenderer/index.ts +3 -0
  29. package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +64 -0
  30. package/src/ApolloTextSearchAdapter/configSchema.ts +24 -0
  31. package/src/ApolloTextSearchAdapter/index.ts +18 -0
  32. package/src/BackendDrivers/BackendDriver.ts +31 -0
  33. package/src/BackendDrivers/CollaborationServerDriver.ts +318 -0
  34. package/src/BackendDrivers/DesktopFileDriver.ts +170 -0
  35. package/src/BackendDrivers/InMemoryFileDriver.ts +76 -0
  36. package/src/BackendDrivers/index.ts +4 -0
  37. package/src/ChangeManager.ts +148 -0
  38. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +248 -0
  39. package/src/LinearApolloDisplay/components/index.ts +1 -0
  40. package/src/LinearApolloDisplay/configSchema.ts +16 -0
  41. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +422 -0
  42. package/src/LinearApolloDisplay/glyphs/CanonicalGeneGlyph.ts +1191 -0
  43. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +151 -0
  44. package/src/LinearApolloDisplay/glyphs/Glyph.ts +382 -0
  45. package/src/LinearApolloDisplay/glyphs/ImplicitExonGeneGlyph.ts +697 -0
  46. package/src/LinearApolloDisplay/glyphs/index.ts +4 -0
  47. package/src/LinearApolloDisplay/index.ts +2 -0
  48. package/src/LinearApolloDisplay/stateModel/base.ts +146 -0
  49. package/src/LinearApolloDisplay/stateModel/getGlyph.ts +39 -0
  50. package/src/LinearApolloDisplay/stateModel/glyphs.ts +45 -0
  51. package/src/LinearApolloDisplay/stateModel/index.ts +20 -0
  52. package/src/LinearApolloDisplay/stateModel/layouts.ts +230 -0
  53. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +513 -0
  54. package/src/LinearApolloDisplay/stateModel/rendering.ts +441 -0
  55. package/src/LinearApolloDisplay/stateModel/trackHeightMixin.ts +43 -0
  56. package/src/LinearApolloDisplay/types.ts +1 -0
  57. package/src/OntologyManager/OntologyStore/__snapshots__/fulltext.test.ts.snap +208 -0
  58. package/src/OntologyManager/OntologyStore/__snapshots__/index.test.ts.snap +18846 -0
  59. package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +137 -0
  60. package/src/OntologyManager/OntologyStore/fulltext.test.ts +94 -0
  61. package/src/OntologyManager/OntologyStore/fulltext.ts +264 -0
  62. package/src/OntologyManager/OntologyStore/index.test.ts +130 -0
  63. package/src/OntologyManager/OntologyStore/index.ts +526 -0
  64. package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +89 -0
  65. package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +180 -0
  66. package/src/OntologyManager/OntologyStore/obo-graph-json-schema.ts +110 -0
  67. package/src/OntologyManager/OntologyStore/prefixes.ts +35 -0
  68. package/src/OntologyManager/index.ts +173 -0
  69. package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +19 -0
  70. package/src/SixFrameFeatureDisplay/components/index.ts +1 -0
  71. package/src/SixFrameFeatureDisplay/configSchema.ts +21 -0
  72. package/src/SixFrameFeatureDisplay/index.ts +2 -0
  73. package/src/SixFrameFeatureDisplay/stateModel.ts +413 -0
  74. package/src/TabularEditor/HybridGrid/ChangeHandling.ts +88 -0
  75. package/src/TabularEditor/HybridGrid/Feature.tsx +346 -0
  76. package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +34 -0
  77. package/src/TabularEditor/HybridGrid/Highlight.tsx +40 -0
  78. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +138 -0
  79. package/src/TabularEditor/HybridGrid/NumberCell.tsx +77 -0
  80. package/src/TabularEditor/HybridGrid/ToolBar.tsx +59 -0
  81. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +119 -0
  82. package/src/TabularEditor/HybridGrid/index.ts +1 -0
  83. package/src/TabularEditor/TabularEditorPane.tsx +34 -0
  84. package/src/TabularEditor/index.ts +3 -0
  85. package/src/TabularEditor/model.ts +44 -0
  86. package/src/TabularEditor/types.ts +3 -0
  87. package/src/components/AddAssembly.tsx +464 -0
  88. package/src/components/AddChildFeature.tsx +247 -0
  89. package/src/components/AddFeature.tsx +252 -0
  90. package/src/components/CopyFeature.tsx +328 -0
  91. package/src/components/DeleteAssembly.tsx +185 -0
  92. package/src/components/DeleteFeature.tsx +90 -0
  93. package/src/components/Dialog.tsx +47 -0
  94. package/src/components/DownloadGFF3.tsx +213 -0
  95. package/src/components/ImportFeatures.tsx +295 -0
  96. package/src/components/ManageChecks.tsx +280 -0
  97. package/src/components/ManageUsers.tsx +218 -0
  98. package/src/components/ModifyFeatureAttribute.tsx +457 -0
  99. package/src/components/OntologyTermAutocomplete.tsx +240 -0
  100. package/src/components/OntologyTermMultiSelect.tsx +349 -0
  101. package/src/components/OpenLocalFile.tsx +178 -0
  102. package/src/components/ViewChangeLog.tsx +208 -0
  103. package/src/components/ViewCheckResults.tsx +151 -0
  104. package/src/components/index.ts +12 -0
  105. package/src/config.ts +10 -0
  106. package/src/declare.d.ts +3 -0
  107. package/src/extensions/annotationFromPileup.ts +208 -0
  108. package/src/extensions/index.ts +1 -0
  109. package/src/index.ts +394 -0
  110. package/src/makeDisplayComponent.tsx +244 -0
  111. package/src/session/ClientDataStore.ts +282 -0
  112. package/src/session/index.ts +1 -0
  113. package/src/session/session.ts +373 -0
  114. package/src/types.ts +10 -0
  115. package/src/util/index.ts +31 -0
  116. package/src/util/loadAssemblyIntoClient.ts +291 -0
@@ -0,0 +1,146 @@
1
+ import { ConfigurationReference, getConf } from '@jbrowse/core/configuration'
2
+ import { AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
3
+ import { BaseDisplay } from '@jbrowse/core/pluggableElementTypes'
4
+ import PluginManager from '@jbrowse/core/PluginManager'
5
+ import {
6
+ AbstractSessionModel,
7
+ getContainingView,
8
+ getSession,
9
+ } from '@jbrowse/core/util'
10
+ import { getParentRenderProps } from '@jbrowse/core/util/tracks'
11
+ // import type LinearGenomeViewPlugin from '@jbrowse/plugin-linear-genome-view'
12
+ import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
13
+ import { AnnotationFeatureI } from 'apollo-mst'
14
+ import { autorun } from 'mobx'
15
+ import { addDisposer, getRoot, types } from 'mobx-state-tree'
16
+
17
+ import { ApolloInternetAccountModel } from '../../ApolloInternetAccount/model'
18
+ import { ApolloSessionModel } from '../../session'
19
+ import { ApolloRootModel } from '../../types'
20
+ import { TrackHeightMixin } from './trackHeightMixin'
21
+
22
+ export function baseModelFactory(
23
+ _pluginManager: PluginManager,
24
+ configSchema: AnyConfigurationSchemaType,
25
+ ) {
26
+ // TODO: Restore this when TRackHeightMixin is in LGV runtime exports
27
+
28
+ // const LGVPlugin = pluginManager.getPlugin(
29
+ // 'LinearGenomeViewPlugin',
30
+ // ) as LinearGenomeViewPlugin
31
+ // const { TrackHeightMixin } = LGVPlugin.exports
32
+
33
+ return types
34
+ .compose(BaseDisplay, TrackHeightMixin)
35
+ .named('BaseLinearApolloDisplay')
36
+ .props({
37
+ type: types.literal('LinearApolloDisplay'),
38
+ configuration: ConfigurationReference(configSchema),
39
+ })
40
+ .volatile((self) => ({
41
+ lgv: getContainingView(self) as unknown as LinearGenomeViewModel,
42
+ }))
43
+ .views((self) => {
44
+ const { configuration, renderProps: superRenderProps } = self
45
+ return {
46
+ renderProps() {
47
+ return {
48
+ ...superRenderProps(),
49
+ ...getParentRenderProps(self),
50
+ config: configuration.renderer,
51
+ }
52
+ },
53
+ }
54
+ })
55
+ .views((self) => ({
56
+ get rendererTypeName() {
57
+ return self.configuration.renderer.type
58
+ },
59
+ get session() {
60
+ return getSession(self) as unknown as ApolloSessionModel
61
+ },
62
+ get regions() {
63
+ const regions = self.lgv.dynamicBlocks.contentBlocks.map(
64
+ ({ assemblyName, end, refName, start }) => ({
65
+ assemblyName,
66
+ refName,
67
+ start: Math.round(start),
68
+ end: Math.round(end),
69
+ }),
70
+ )
71
+ return regions
72
+ },
73
+ get displayedRegions() {
74
+ return self.lgv.displayedRegions
75
+ },
76
+ regionCannotBeRendered(/* region */) {
77
+ if (self.lgv && self.lgv.bpPerPx >= 200) {
78
+ return 'Zoom in to see annotations'
79
+ }
80
+ return
81
+ },
82
+ }))
83
+ .views((self) => ({
84
+ get apolloInternetAccount() {
85
+ const [region] = self.regions
86
+ const { internetAccounts } = getRoot<ApolloRootModel>(self)
87
+ const { assemblyName } = region
88
+ const { assemblyManager } =
89
+ self.session as unknown as AbstractSessionModel
90
+ const assembly = assemblyManager.get(assemblyName)
91
+ if (!assembly) {
92
+ throw new Error(`No assembly found with name ${assemblyName}`)
93
+ }
94
+ const { internetAccountConfigId } = getConf(assembly, [
95
+ 'sequence',
96
+ 'metadata',
97
+ ]) as { internetAccountConfigId: string }
98
+ return internetAccounts.find(
99
+ (ia) => getConf(ia, 'internetAccountId') === internetAccountConfigId,
100
+ ) as ApolloInternetAccountModel | undefined
101
+ },
102
+ get changeManager() {
103
+ return (self.session as unknown as ApolloSessionModel).apolloDataStore
104
+ ?.changeManager
105
+ },
106
+ getAssemblyId(assemblyName: string) {
107
+ const { assemblyManager } =
108
+ self.session as unknown as AbstractSessionModel
109
+ const assembly = assemblyManager.get(assemblyName)
110
+ if (!assembly) {
111
+ throw new Error(`Could not find assembly named ${assemblyName}`)
112
+ }
113
+ return assembly.name
114
+ },
115
+ get selectedFeature(): AnnotationFeatureI | undefined {
116
+ return (self.session as unknown as ApolloSessionModel)
117
+ .apolloSelectedFeature
118
+ },
119
+ }))
120
+ .actions((self) => ({
121
+ setSelectedFeature(feature?: AnnotationFeatureI) {
122
+ return (
123
+ self.session as unknown as ApolloSessionModel
124
+ ).apolloSetSelectedFeature(feature)
125
+ },
126
+ afterAttach() {
127
+ addDisposer(
128
+ self,
129
+ autorun(
130
+ () => {
131
+ if (!self.lgv.initialized || self.regionCannotBeRendered()) {
132
+ return
133
+ }
134
+ void (
135
+ self.session as unknown as ApolloSessionModel
136
+ ).apolloDataStore.loadFeatures(self.regions)
137
+ void (
138
+ self.session as unknown as ApolloSessionModel
139
+ ).apolloDataStore.loadRefSeq(self.regions)
140
+ },
141
+ { name: 'LinearApolloDisplayLoadFeatures', delay: 1000 },
142
+ ),
143
+ )
144
+ },
145
+ }))
146
+ }
@@ -0,0 +1,39 @@
1
+ import { AnnotationFeatureI } from 'apollo-mst'
2
+
3
+ import {
4
+ BoxGlyph,
5
+ CanonicalGeneGlyph,
6
+ GenericChildGlyph,
7
+ ImplicitExonGeneGlyph,
8
+ } from '../glyphs'
9
+ import { Glyph } from '../glyphs/Glyph'
10
+
11
+ const boxGlyph = new BoxGlyph()
12
+ const canonicalGeneGlyph = new CanonicalGeneGlyph()
13
+ const genericChildGlyph = new GenericChildGlyph()
14
+ const implicitExonGeneGlyph = new ImplicitExonGeneGlyph()
15
+
16
+ /** get the appropriate glyph for the given top-level feature */
17
+ export function getGlyph(feature: AnnotationFeatureI, _bpPerPx: number): Glyph {
18
+ if (feature.type === 'gene') {
19
+ let hasExon = false
20
+ for (const [, mrna] of feature.children ?? new Map()) {
21
+ if (mrna.type !== 'mRNA') {
22
+ continue
23
+ }
24
+ for (const [, possibleExon] of mrna.children ?? new Map()) {
25
+ if (possibleExon.type === 'exon') {
26
+ hasExon = true
27
+ }
28
+ }
29
+ }
30
+ if (hasExon) {
31
+ return canonicalGeneGlyph
32
+ }
33
+ return implicitExonGeneGlyph
34
+ }
35
+ if (feature.children?.size) {
36
+ return genericChildGlyph
37
+ }
38
+ return boxGlyph
39
+ }
@@ -0,0 +1,45 @@
1
+ import { AnnotationFeatureI } from 'apollo-mst'
2
+ import { ObservableMap, observable } from 'mobx'
3
+ import { types } from 'mobx-state-tree'
4
+
5
+ import { BoxGlyph } from '../glyphs/BoxGlyph'
6
+ import { Glyph } from '../glyphs/Glyph'
7
+
8
+ export default function Glyphs() {
9
+ return types
10
+ .model({})
11
+ .volatile(() => ({
12
+ glyphs: observable.map<number, ObservableMap<string, Glyph>>(),
13
+ }))
14
+ .actions((s) => {
15
+ const self = s
16
+ return {
17
+ getGlyphsForZoomLevel(bpPerPx: number): ObservableMap<string, Glyph> {
18
+ const existingZoomLevel = self.glyphs.get(bpPerPx)
19
+ if (existingZoomLevel) {
20
+ return existingZoomLevel
21
+ }
22
+ const newZoomLevel = observable.map()
23
+ self.glyphs.set(bpPerPx, newZoomLevel)
24
+ return newZoomLevel
25
+ },
26
+ createGlyph() {
27
+ return new BoxGlyph()
28
+ },
29
+ /** get the appropriate glyph for the given top-level feature */
30
+ getGlyph(feature: AnnotationFeatureI, bpPerPx: number) {
31
+ const glyphsForZoomLevel = this.getGlyphsForZoomLevel(bpPerPx)
32
+ const glyphForFeature = glyphsForZoomLevel.get(feature._id)
33
+ if (glyphForFeature) {
34
+ return glyphForFeature
35
+ }
36
+ const newGlyph = this.createGlyph()
37
+ glyphsForZoomLevel.set(feature._id, newGlyph)
38
+ return newGlyph
39
+ },
40
+ afterAttach() {
41
+ // autorun to clean up old glyph zoom levels
42
+ },
43
+ }
44
+ })
45
+ }
@@ -0,0 +1,20 @@
1
+ import { AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ import { Instance, types } from 'mobx-state-tree'
4
+
5
+ import { TabularEditorStateModelType } from '../../TabularEditor'
6
+ import { mouseEventsModelFactory } from './mouseEvents'
7
+
8
+ export function stateModelFactory(
9
+ pluginManager: PluginManager,
10
+ configSchema: AnyConfigurationSchemaType,
11
+ ) {
12
+ // TODO: this needs to be refactored so that the final composition of the
13
+ // state model mixins happens here in one central place
14
+ return mouseEventsModelFactory(pluginManager, configSchema)
15
+ .props({ tabularEditor: types.optional(TabularEditorStateModelType, {}) })
16
+ .named('LinearApolloDisplay')
17
+ }
18
+
19
+ export type LinearApolloDisplayStateModel = ReturnType<typeof stateModelFactory>
20
+ export type LinearApolloDisplay = Instance<LinearApolloDisplayStateModel>
@@ -0,0 +1,230 @@
1
+ import { AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ import { AbstractSessionModel, doesIntersect2 } from '@jbrowse/core/util'
4
+ import { AnnotationFeatureI } from 'apollo-mst'
5
+ import { autorun, observable } from 'mobx'
6
+ import { addDisposer, isAlive } from 'mobx-state-tree'
7
+
8
+ import { ApolloSessionModel } from '../../session'
9
+ import { baseModelFactory } from './base'
10
+ import { getGlyph } from './getGlyph'
11
+
12
+ export function layoutsModelFactory(
13
+ pluginManager: PluginManager,
14
+ configSchema: AnyConfigurationSchemaType,
15
+ ) {
16
+ const BaseLinearApolloDisplay = baseModelFactory(pluginManager, configSchema)
17
+
18
+ return BaseLinearApolloDisplay.named('LinearApolloDisplayLayouts')
19
+ .props({
20
+ featuresMinMaxLimit: 500_000,
21
+ })
22
+ .volatile(() => ({
23
+ seenFeatures: observable.map<string, AnnotationFeatureI>(),
24
+ }))
25
+ .views((self) => ({
26
+ get featuresMinMax() {
27
+ const { assemblyManager } =
28
+ self.session as unknown as AbstractSessionModel
29
+ return self.displayedRegions.map((region) => {
30
+ const assembly = assemblyManager.get(region.assemblyName)
31
+ let min: number | undefined
32
+ let max: number | undefined
33
+ const { end, refName, start } = region
34
+ for (const [, feature] of self.seenFeatures) {
35
+ if (
36
+ refName !== assembly?.getCanonicalRefName(feature.refSeq) ||
37
+ !doesIntersect2(start, end, feature.min, feature.max) ||
38
+ feature.length > self.featuresMinMaxLimit
39
+ ) {
40
+ continue
41
+ }
42
+ if (min === undefined) {
43
+ ;({ min } = feature)
44
+ }
45
+ if (max === undefined) {
46
+ ;({ max } = feature)
47
+ }
48
+ if (feature.min < min) {
49
+ ;({ min } = feature)
50
+ }
51
+ if (feature.end > max) {
52
+ ;({ max } = feature)
53
+ }
54
+ }
55
+ if (min !== undefined && max !== undefined) {
56
+ return [min, max]
57
+ }
58
+ return
59
+ })
60
+ },
61
+ }))
62
+ .actions((self) => ({
63
+ addSeenFeature(feature: AnnotationFeatureI) {
64
+ self.seenFeatures.set(feature._id, feature)
65
+ },
66
+ deleteSeenFeature(featureId: string) {
67
+ self.seenFeatures.delete(featureId)
68
+ },
69
+ }))
70
+ .views((self) => ({
71
+ get featureLayouts() {
72
+ const { assemblyManager } =
73
+ self.session as unknown as AbstractSessionModel
74
+ return self.displayedRegions.map((region, idx) => {
75
+ const assembly = assemblyManager.get(region.assemblyName)
76
+ const featureLayout = new Map<
77
+ number,
78
+ [number, AnnotationFeatureI][]
79
+ >()
80
+ const minMax = self.featuresMinMax[idx]
81
+ if (!minMax) {
82
+ return featureLayout
83
+ }
84
+ const [min, max] = minMax
85
+ const rows: boolean[][] = []
86
+ const { end, refName, start } = region
87
+ for (const [id, feature] of self.seenFeatures.entries()) {
88
+ if (!isAlive(feature)) {
89
+ self.deleteSeenFeature(id)
90
+ continue
91
+ }
92
+ if (
93
+ refName !== assembly?.getCanonicalRefName(feature.refSeq) ||
94
+ !doesIntersect2(start, end, feature.min, feature.max)
95
+ ) {
96
+ continue
97
+ }
98
+ const rowCount = getGlyph(feature, self.lgv.bpPerPx).getRowCount(
99
+ feature,
100
+ self.lgv.bpPerPx,
101
+ )
102
+ let startingRow = 0
103
+ let placed = false
104
+ while (!placed) {
105
+ let rowsForFeature = rows.slice(
106
+ startingRow,
107
+ startingRow + rowCount,
108
+ )
109
+ if (rowsForFeature.length < rowCount) {
110
+ for (let i = 0; i < rowCount - rowsForFeature.length; i++) {
111
+ const newRowNumber = rows.length
112
+ rows[newRowNumber] = Array.from({ length: max - min })
113
+ featureLayout.set(newRowNumber, [])
114
+ }
115
+ rowsForFeature = rows.slice(startingRow, startingRow + rowCount)
116
+ }
117
+ if (
118
+ rowsForFeature
119
+ .map((rowForFeature) => {
120
+ // zero-length features are allowed in the spec
121
+ const featureMax =
122
+ feature.max - feature.min === 0
123
+ ? feature.min + 1
124
+ : feature.max
125
+ let start = feature.min - min,
126
+ end = featureMax - min
127
+ if (feature.min - min < 0) {
128
+ start = 0
129
+ end = featureMax - feature.min
130
+ }
131
+ return rowForFeature.slice(start, end).some(Boolean)
132
+ })
133
+ .some(Boolean)
134
+ ) {
135
+ startingRow += 1
136
+ continue
137
+ }
138
+ for (
139
+ let rowNum = startingRow;
140
+ rowNum < startingRow + rowCount;
141
+ rowNum++
142
+ ) {
143
+ const row = rows[rowNum]
144
+ let start = feature.min - min,
145
+ end = feature.max - min
146
+ if (feature.min - min < 0) {
147
+ start = 0
148
+ end = feature.max - feature.min
149
+ }
150
+ row.fill(true, start, end)
151
+ const layoutRow = featureLayout.get(rowNum)
152
+ layoutRow?.push([rowNum - startingRow, feature])
153
+ }
154
+ placed = true
155
+ }
156
+ }
157
+ return featureLayout
158
+ })
159
+ },
160
+ getFeatureLayoutPosition(feature: AnnotationFeatureI) {
161
+ const { featureLayouts } = this
162
+ for (const layout of featureLayouts) {
163
+ for (const [layoutRowNum, layoutRow] of layout) {
164
+ for (const [featureRowNum, layoutFeature] of layoutRow) {
165
+ if (featureRowNum !== 0) {
166
+ // Same top-level feature in all feature rows, so only need to
167
+ // check the first one
168
+ continue
169
+ }
170
+ if (feature._id === layoutFeature._id) {
171
+ return { layoutRow: layoutRowNum, featureRow: featureRowNum }
172
+ }
173
+ if (layoutFeature.hasDescendant(feature._id)) {
174
+ const row = getGlyph(
175
+ layoutFeature,
176
+ self.lgv.bpPerPx,
177
+ ).getRowForFeature(layoutFeature, feature)
178
+ if (row !== undefined) {
179
+ return { layoutRow: layoutRowNum, featureRow: row }
180
+ }
181
+ }
182
+ }
183
+ }
184
+ }
185
+ return
186
+ },
187
+ }))
188
+ .views((self) => ({
189
+ get highestRow() {
190
+ return Math.max(
191
+ 0,
192
+ ...self.featureLayouts.map((layout) => Math.max(...layout.keys())),
193
+ )
194
+ },
195
+ }))
196
+ .actions((self) => ({
197
+ afterAttach() {
198
+ addDisposer(
199
+ self,
200
+ autorun(
201
+ () => {
202
+ if (!self.lgv.initialized || self.regionCannotBeRendered()) {
203
+ return
204
+ }
205
+ for (const region of self.regions) {
206
+ const assembly = (
207
+ self.session as unknown as ApolloSessionModel
208
+ ).apolloDataStore.assemblies.get(region.assemblyName)
209
+ const ref = assembly?.getByRefName(region.refName)
210
+ for (const [, feature] of ref?.features ?? new Map()) {
211
+ if (
212
+ doesIntersect2(
213
+ region.start,
214
+ region.end,
215
+ feature.start,
216
+ feature.end,
217
+ ) &&
218
+ !self.seenFeatures.has(feature._id)
219
+ ) {
220
+ self.addSeenFeature(feature)
221
+ }
222
+ }
223
+ }
224
+ },
225
+ { name: 'LinearApolloDisplaySetSeenFeatures', delay: 1000 },
226
+ ),
227
+ )
228
+ },
229
+ }))
230
+ }