@apollo-annotation/jbrowse-plugin-apollo 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +317 -227
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +316 -226
- package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.development.js +316 -226
- package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
- package/package.json +4 -4
- package/src/FeatureDetailsWidget/model.ts +0 -2
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +20 -1
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +232 -117
- package/src/LinearApolloDisplay/stateModel/base.ts +15 -1
- package/src/LinearApolloDisplay/stateModel/layouts.ts +84 -85
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +9 -4
- package/src/LinearApolloDisplay/stateModel/rendering.ts +3 -2
- package/src/OntologyManager/index.ts +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apollo-annotation/jbrowse-plugin-apollo",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Apollo plugin for JBrowse 2",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@apollo-annotation/common": "^0.3.
|
|
52
|
-
"@apollo-annotation/mst": "^0.3.
|
|
53
|
-
"@apollo-annotation/shared": "^0.3.
|
|
51
|
+
"@apollo-annotation/common": "^0.3.4",
|
|
52
|
+
"@apollo-annotation/mst": "^0.3.4",
|
|
53
|
+
"@apollo-annotation/shared": "^0.3.4",
|
|
54
54
|
"@emotion/react": "^11.10.6",
|
|
55
55
|
"@emotion/styled": "^11.10.6",
|
|
56
56
|
"@gmod/gff": "1.2.0",
|
|
@@ -9,7 +9,6 @@ import { ElementId } from '@jbrowse/core/util/types/mst'
|
|
|
9
9
|
import { autorun } from 'mobx'
|
|
10
10
|
import { Instance, SnapshotIn, addDisposer, types } from 'mobx-state-tree'
|
|
11
11
|
|
|
12
|
-
import { ChangeManager } from '../ChangeManager'
|
|
13
12
|
import { ApolloSessionModel } from '../session'
|
|
14
13
|
|
|
15
14
|
export const ApolloFeatureDetailsWidgetModel = types
|
|
@@ -86,7 +85,6 @@ export const ApolloTranscriptDetailsModel = types
|
|
|
86
85
|
),
|
|
87
86
|
assembly: types.string,
|
|
88
87
|
refName: types.string,
|
|
89
|
-
changeManager: types.frozen<ChangeManager>(),
|
|
90
88
|
})
|
|
91
89
|
.volatile(() => ({
|
|
92
90
|
tryReload: undefined as string | undefined,
|
|
@@ -9,7 +9,13 @@ import {
|
|
|
9
9
|
} from '@jbrowse/core/util'
|
|
10
10
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
11
11
|
import ErrorIcon from '@mui/icons-material/Error'
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
Alert,
|
|
14
|
+
Avatar,
|
|
15
|
+
CircularProgress,
|
|
16
|
+
Tooltip,
|
|
17
|
+
useTheme,
|
|
18
|
+
} from '@mui/material'
|
|
13
19
|
import { observer } from 'mobx-react'
|
|
14
20
|
import React, { useEffect, useState } from 'react'
|
|
15
21
|
import { makeStyles } from 'tss-react/mui'
|
|
@@ -39,6 +45,13 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
39
45
|
color: theme.palette.warning.light,
|
|
40
46
|
backgroundColor: theme.palette.warning.contrastText,
|
|
41
47
|
},
|
|
48
|
+
loading: {
|
|
49
|
+
position: 'absolute',
|
|
50
|
+
right: theme.spacing(3),
|
|
51
|
+
zIndex: 10,
|
|
52
|
+
pointerEvents: 'none',
|
|
53
|
+
textAlign: 'right',
|
|
54
|
+
},
|
|
42
55
|
}))
|
|
43
56
|
|
|
44
57
|
export const LinearApolloDisplay = observer(function LinearApolloDisplay(
|
|
@@ -47,6 +60,7 @@ export const LinearApolloDisplay = observer(function LinearApolloDisplay(
|
|
|
47
60
|
const theme = useTheme()
|
|
48
61
|
const { model } = props
|
|
49
62
|
const {
|
|
63
|
+
loading,
|
|
50
64
|
apolloRowHeight,
|
|
51
65
|
contextMenuItems: getContextMenuItems,
|
|
52
66
|
cursor,
|
|
@@ -128,6 +142,11 @@ export const LinearApolloDisplay = observer(function LinearApolloDisplay(
|
|
|
128
142
|
}
|
|
129
143
|
}}
|
|
130
144
|
>
|
|
145
|
+
{loading ? (
|
|
146
|
+
<div className={classes.loading}>
|
|
147
|
+
<CircularProgress size="18px" />
|
|
148
|
+
</div>
|
|
149
|
+
) : null}
|
|
131
150
|
{message ? (
|
|
132
151
|
<Alert severity="warning" classes={{ message: classes.ellipses }}>
|
|
133
152
|
<Tooltip title={message}>
|
|
@@ -74,7 +74,6 @@ function draw(
|
|
|
74
74
|
const displayedRegion = displayedRegions[displayedRegionIndex]
|
|
75
75
|
const { refName, reversed } = displayedRegion
|
|
76
76
|
const rowHeight = apolloRowHeight
|
|
77
|
-
const exonHeight = Math.round(0.6 * rowHeight)
|
|
78
77
|
const cdsHeight = Math.round(0.9 * rowHeight)
|
|
79
78
|
const { children, min, strand } = feature
|
|
80
79
|
if (!children) {
|
|
@@ -121,29 +120,36 @@ function draw(
|
|
|
121
120
|
currentRow += 1
|
|
122
121
|
continue
|
|
123
122
|
}
|
|
124
|
-
const { children:
|
|
125
|
-
if (!
|
|
123
|
+
const { children: transcriptChildren } = transcript
|
|
124
|
+
if (!transcriptChildren) {
|
|
126
125
|
continue
|
|
127
126
|
}
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
|
|
128
|
+
const cdsCount = getCDSCount(transcript, featureTypeOntology)
|
|
129
|
+
for (const [, childFeature] of transcriptChildren) {
|
|
130
|
+
if (!featureTypeOntology.isTypeOf(childFeature.type, 'CDS')) {
|
|
130
131
|
continue
|
|
131
132
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
133
|
+
drawLine(
|
|
134
|
+
ctx,
|
|
135
|
+
stateModel,
|
|
136
|
+
displayedRegionIndex,
|
|
137
|
+
row,
|
|
138
|
+
transcript,
|
|
139
|
+
currentRow,
|
|
140
|
+
)
|
|
141
|
+
currentRow += 1
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (cdsCount === 0) {
|
|
145
|
+
drawLine(
|
|
146
|
+
ctx,
|
|
147
|
+
stateModel,
|
|
148
|
+
displayedRegionIndex,
|
|
149
|
+
row,
|
|
150
|
+
transcript,
|
|
151
|
+
currentRow,
|
|
152
|
+
)
|
|
147
153
|
currentRow += 1
|
|
148
154
|
}
|
|
149
155
|
}
|
|
@@ -160,120 +166,205 @@ function draw(
|
|
|
160
166
|
currentRow += 1
|
|
161
167
|
continue
|
|
162
168
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
for (const [, exon] of childrenOfTranscript) {
|
|
169
|
-
if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
|
|
169
|
+
const cdsCount = getCDSCount(child, featureTypeOntology)
|
|
170
|
+
if (cdsCount != 0) {
|
|
171
|
+
for (const cdsRow of child.cdsLocations) {
|
|
172
|
+
const { _id, children: transcriptChildren } = child
|
|
173
|
+
if (!transcriptChildren) {
|
|
170
174
|
continue
|
|
171
175
|
}
|
|
172
|
-
const
|
|
173
|
-
(
|
|
174
|
-
|
|
175
|
-
coord: exon.min,
|
|
176
|
-
regionNumber: displayedRegionIndex,
|
|
177
|
-
})?.offsetPx ?? 0) - offsetPx
|
|
178
|
-
const widthPx = exon.length / bpPerPx
|
|
179
|
-
const startPx = reversed ? minX - widthPx : minX
|
|
180
|
-
|
|
181
|
-
const top = (row + currentRow) * rowHeight
|
|
182
|
-
const exonTop = top + (rowHeight - exonHeight) / 2
|
|
183
|
-
ctx.fillStyle = theme?.palette.text.primary ?? 'black'
|
|
184
|
-
ctx.fillRect(startPx, exonTop, widthPx, exonHeight)
|
|
185
|
-
if (widthPx > 2) {
|
|
186
|
-
ctx.clearRect(startPx + 1, exonTop + 1, widthPx - 2, exonHeight - 2)
|
|
187
|
-
ctx.fillStyle =
|
|
188
|
-
apolloSelectedFeature && exon._id === apolloSelectedFeature._id
|
|
189
|
-
? 'rgb(0,0,0)'
|
|
190
|
-
: 'rgb(211,211,211)'
|
|
191
|
-
ctx.fillRect(startPx + 1, exonTop + 1, widthPx - 2, exonHeight - 2)
|
|
192
|
-
if (forwardFill && backwardFill && strand) {
|
|
193
|
-
const reversal = reversed ? -1 : 1
|
|
194
|
-
const [topFill, bottomFill] =
|
|
195
|
-
strand * reversal === 1
|
|
196
|
-
? [forwardFill, backwardFill]
|
|
197
|
-
: [backwardFill, forwardFill]
|
|
198
|
-
ctx.fillStyle = topFill
|
|
199
|
-
ctx.fillRect(
|
|
200
|
-
startPx + 1,
|
|
201
|
-
exonTop + 1,
|
|
202
|
-
widthPx - 2,
|
|
203
|
-
(exonHeight - 2) / 2,
|
|
204
|
-
)
|
|
205
|
-
ctx.fillStyle = bottomFill
|
|
206
|
-
ctx.fillRect(
|
|
207
|
-
startPx + 1,
|
|
208
|
-
exonTop + 1 + (exonHeight - 2) / 2,
|
|
209
|
-
widthPx - 2,
|
|
210
|
-
(exonHeight - 2) / 2,
|
|
211
|
-
)
|
|
176
|
+
for (const [, exon] of transcriptChildren) {
|
|
177
|
+
if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
|
|
178
|
+
continue
|
|
212
179
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const cdsStartPx = reversed ? minX - cdsWidthPx : minX
|
|
224
|
-
ctx.fillStyle = theme?.palette.text.primary ?? 'black'
|
|
225
|
-
const cdsTop =
|
|
226
|
-
(row + currentRow) * rowHeight + (rowHeight - cdsHeight) / 2
|
|
227
|
-
ctx.fillRect(cdsStartPx, cdsTop, cdsWidthPx, cdsHeight)
|
|
228
|
-
if (cdsWidthPx > 2) {
|
|
229
|
-
ctx.clearRect(
|
|
230
|
-
cdsStartPx + 1,
|
|
231
|
-
cdsTop + 1,
|
|
232
|
-
cdsWidthPx - 2,
|
|
233
|
-
cdsHeight - 2,
|
|
234
|
-
)
|
|
235
|
-
const frame = getFrame(cds.min, cds.max, child.strand ?? 1, cds.phase)
|
|
236
|
-
const frameColor = theme?.palette.framesCDS.at(frame)?.main
|
|
237
|
-
const cdsColorCode = frameColor ?? 'rgb(171,71,188)'
|
|
238
|
-
ctx.fillStyle =
|
|
239
|
-
apolloSelectedFeature && _id === apolloSelectedFeature._id
|
|
240
|
-
? 'rgb(0,0,0)'
|
|
241
|
-
: cdsColorCode
|
|
242
|
-
ctx.fillStyle = cdsColorCode
|
|
243
|
-
ctx.fillRect(
|
|
244
|
-
cdsStartPx + 1,
|
|
245
|
-
cdsTop + 1,
|
|
246
|
-
cdsWidthPx - 2,
|
|
247
|
-
cdsHeight - 2,
|
|
180
|
+
drawExon(
|
|
181
|
+
ctx,
|
|
182
|
+
stateModel,
|
|
183
|
+
displayedRegionIndex,
|
|
184
|
+
row,
|
|
185
|
+
exon,
|
|
186
|
+
currentRow,
|
|
187
|
+
strand,
|
|
188
|
+
forwardFill,
|
|
189
|
+
backwardFill,
|
|
248
190
|
)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
191
|
+
}
|
|
192
|
+
for (const cds of cdsRow) {
|
|
193
|
+
const cdsWidthPx = (cds.max - cds.min) / bpPerPx
|
|
194
|
+
const minX =
|
|
195
|
+
(lgv.bpToPx({
|
|
196
|
+
refName,
|
|
197
|
+
coord: cds.min,
|
|
198
|
+
regionNumber: displayedRegionIndex,
|
|
199
|
+
})?.offsetPx ?? 0) - offsetPx
|
|
200
|
+
const cdsStartPx = reversed ? minX - cdsWidthPx : minX
|
|
201
|
+
ctx.fillStyle = theme?.palette.text.primary ?? 'black'
|
|
202
|
+
const cdsTop =
|
|
203
|
+
(row + currentRow) * rowHeight + (rowHeight - cdsHeight) / 2
|
|
204
|
+
ctx.fillRect(cdsStartPx, cdsTop, cdsWidthPx, cdsHeight)
|
|
205
|
+
if (cdsWidthPx > 2) {
|
|
206
|
+
ctx.clearRect(
|
|
257
207
|
cdsStartPx + 1,
|
|
258
208
|
cdsTop + 1,
|
|
259
209
|
cdsWidthPx - 2,
|
|
260
|
-
|
|
210
|
+
cdsHeight - 2,
|
|
261
211
|
)
|
|
262
|
-
|
|
212
|
+
const frame = getFrame(
|
|
213
|
+
cds.min,
|
|
214
|
+
cds.max,
|
|
215
|
+
child.strand ?? 1,
|
|
216
|
+
cds.phase,
|
|
217
|
+
)
|
|
218
|
+
const frameColor = theme?.palette.framesCDS.at(frame)?.main
|
|
219
|
+
const cdsColorCode = frameColor ?? 'rgb(171,71,188)'
|
|
220
|
+
ctx.fillStyle =
|
|
221
|
+
apolloSelectedFeature && _id === apolloSelectedFeature._id
|
|
222
|
+
? 'rgb(0,0,0)'
|
|
223
|
+
: cdsColorCode
|
|
224
|
+
ctx.fillStyle = cdsColorCode
|
|
263
225
|
ctx.fillRect(
|
|
264
226
|
cdsStartPx + 1,
|
|
265
|
-
cdsTop +
|
|
227
|
+
cdsTop + 1,
|
|
266
228
|
cdsWidthPx - 2,
|
|
267
|
-
|
|
229
|
+
cdsHeight - 2,
|
|
268
230
|
)
|
|
231
|
+
if (forwardFill && backwardFill && strand) {
|
|
232
|
+
const reversal = reversed ? -1 : 1
|
|
233
|
+
const [topFill, bottomFill] =
|
|
234
|
+
strand * reversal === 1
|
|
235
|
+
? [forwardFill, backwardFill]
|
|
236
|
+
: [backwardFill, forwardFill]
|
|
237
|
+
ctx.fillStyle = topFill
|
|
238
|
+
ctx.fillRect(
|
|
239
|
+
cdsStartPx + 1,
|
|
240
|
+
cdsTop + 1,
|
|
241
|
+
cdsWidthPx - 2,
|
|
242
|
+
(cdsHeight - 2) / 2,
|
|
243
|
+
)
|
|
244
|
+
ctx.fillStyle = bottomFill
|
|
245
|
+
ctx.fillRect(
|
|
246
|
+
cdsStartPx + 1,
|
|
247
|
+
cdsTop + (cdsHeight - 2) / 2,
|
|
248
|
+
cdsWidthPx - 2,
|
|
249
|
+
(cdsHeight - 2) / 2,
|
|
250
|
+
)
|
|
251
|
+
}
|
|
269
252
|
}
|
|
270
253
|
}
|
|
254
|
+
currentRow += 1
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const { children: transcriptChildren } = child
|
|
259
|
+
// Draw exons for non-coding genes
|
|
260
|
+
if (cdsCount === 0 && transcriptChildren) {
|
|
261
|
+
for (const [, exon] of transcriptChildren) {
|
|
262
|
+
if (!featureTypeOntology.isTypeOf(exon.type, 'exon')) {
|
|
263
|
+
continue
|
|
264
|
+
}
|
|
265
|
+
drawExon(
|
|
266
|
+
ctx,
|
|
267
|
+
stateModel,
|
|
268
|
+
displayedRegionIndex,
|
|
269
|
+
row,
|
|
270
|
+
exon,
|
|
271
|
+
currentRow,
|
|
272
|
+
strand,
|
|
273
|
+
forwardFill,
|
|
274
|
+
backwardFill,
|
|
275
|
+
)
|
|
271
276
|
}
|
|
272
277
|
currentRow += 1
|
|
273
278
|
}
|
|
274
279
|
}
|
|
275
280
|
}
|
|
276
281
|
|
|
282
|
+
function drawExon(
|
|
283
|
+
ctx: CanvasRenderingContext2D,
|
|
284
|
+
stateModel: LinearApolloDisplayRendering,
|
|
285
|
+
displayedRegionIndex: number,
|
|
286
|
+
row: number,
|
|
287
|
+
exon: AnnotationFeature,
|
|
288
|
+
currentRow: number,
|
|
289
|
+
strand: number | undefined,
|
|
290
|
+
forwardFill: CanvasPattern | null,
|
|
291
|
+
backwardFill: CanvasPattern | null,
|
|
292
|
+
) {
|
|
293
|
+
const { apolloRowHeight, lgv, session, theme } = stateModel
|
|
294
|
+
const { bpPerPx, displayedRegions, offsetPx } = lgv
|
|
295
|
+
const displayedRegion = displayedRegions[displayedRegionIndex]
|
|
296
|
+
const { refName, reversed } = displayedRegion
|
|
297
|
+
const { apolloSelectedFeature } = session
|
|
298
|
+
|
|
299
|
+
const minX =
|
|
300
|
+
(lgv.bpToPx({
|
|
301
|
+
refName,
|
|
302
|
+
coord: exon.min,
|
|
303
|
+
regionNumber: displayedRegionIndex,
|
|
304
|
+
})?.offsetPx ?? 0) - offsetPx
|
|
305
|
+
const widthPx = exon.length / bpPerPx
|
|
306
|
+
const startPx = reversed ? minX - widthPx : minX
|
|
307
|
+
|
|
308
|
+
const top = (row + currentRow) * apolloRowHeight
|
|
309
|
+
const exonHeight = Math.round(0.6 * apolloRowHeight)
|
|
310
|
+
const exonTop = top + (apolloRowHeight - exonHeight) / 2
|
|
311
|
+
ctx.fillStyle = theme?.palette.text.primary ?? 'black'
|
|
312
|
+
ctx.fillRect(startPx, exonTop, widthPx, exonHeight)
|
|
313
|
+
if (widthPx > 2) {
|
|
314
|
+
ctx.clearRect(startPx + 1, exonTop + 1, widthPx - 2, exonHeight - 2)
|
|
315
|
+
ctx.fillStyle =
|
|
316
|
+
apolloSelectedFeature && exon._id === apolloSelectedFeature._id
|
|
317
|
+
? 'rgb(0,0,0)'
|
|
318
|
+
: 'rgb(211,211,211)'
|
|
319
|
+
ctx.fillRect(startPx + 1, exonTop + 1, widthPx - 2, exonHeight - 2)
|
|
320
|
+
if (forwardFill && backwardFill && strand) {
|
|
321
|
+
const reversal = reversed ? -1 : 1
|
|
322
|
+
const [topFill, bottomFill] =
|
|
323
|
+
strand * reversal === 1
|
|
324
|
+
? [forwardFill, backwardFill]
|
|
325
|
+
: [backwardFill, forwardFill]
|
|
326
|
+
ctx.fillStyle = topFill
|
|
327
|
+
ctx.fillRect(startPx + 1, exonTop + 1, widthPx - 2, (exonHeight - 2) / 2)
|
|
328
|
+
ctx.fillStyle = bottomFill
|
|
329
|
+
ctx.fillRect(
|
|
330
|
+
startPx + 1,
|
|
331
|
+
exonTop + 1 + (exonHeight - 2) / 2,
|
|
332
|
+
widthPx - 2,
|
|
333
|
+
(exonHeight - 2) / 2,
|
|
334
|
+
)
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function drawLine(
|
|
340
|
+
ctx: CanvasRenderingContext2D,
|
|
341
|
+
stateModel: LinearApolloDisplayRendering,
|
|
342
|
+
displayedRegionIndex: number,
|
|
343
|
+
row: number,
|
|
344
|
+
transcript: AnnotationFeature,
|
|
345
|
+
currentRow: number,
|
|
346
|
+
) {
|
|
347
|
+
const { apolloRowHeight, lgv, theme } = stateModel
|
|
348
|
+
const { bpPerPx, displayedRegions, offsetPx } = lgv
|
|
349
|
+
const displayedRegion = displayedRegions[displayedRegionIndex]
|
|
350
|
+
const { refName, reversed } = displayedRegion
|
|
351
|
+
const minX =
|
|
352
|
+
(lgv.bpToPx({
|
|
353
|
+
refName,
|
|
354
|
+
coord: transcript.min,
|
|
355
|
+
regionNumber: displayedRegionIndex,
|
|
356
|
+
})?.offsetPx ?? 0) - offsetPx
|
|
357
|
+
const widthPx = transcript.length / bpPerPx
|
|
358
|
+
const startPx = reversed ? minX - widthPx : minX
|
|
359
|
+
const height =
|
|
360
|
+
Math.round((currentRow + 1 / 2) * apolloRowHeight) + row * apolloRowHeight
|
|
361
|
+
ctx.strokeStyle = theme?.palette.text.primary ?? 'black'
|
|
362
|
+
ctx.beginPath()
|
|
363
|
+
ctx.moveTo(startPx, height)
|
|
364
|
+
ctx.lineTo(startPx + widthPx, height)
|
|
365
|
+
ctx.stroke()
|
|
366
|
+
}
|
|
367
|
+
|
|
277
368
|
function drawDragPreview(
|
|
278
369
|
stateModel: LinearApolloDisplay,
|
|
279
370
|
overlayCtx: CanvasRenderingContext2D,
|
|
@@ -384,6 +475,26 @@ function getFeatureFromLayout(
|
|
|
384
475
|
return feature
|
|
385
476
|
}
|
|
386
477
|
|
|
478
|
+
function getCDSCount(
|
|
479
|
+
feature: AnnotationFeature,
|
|
480
|
+
featureTypeOntology: OntologyRecord,
|
|
481
|
+
): number {
|
|
482
|
+
const { children, type } = feature
|
|
483
|
+
if (!children) {
|
|
484
|
+
return 0
|
|
485
|
+
}
|
|
486
|
+
const isMrna = featureTypeOntology.isTypeOf(type, 'mRNA')
|
|
487
|
+
let cdsCount = 0
|
|
488
|
+
if (isMrna) {
|
|
489
|
+
for (const [, child] of children) {
|
|
490
|
+
if (featureTypeOntology.isTypeOf(child.type, 'CDS')) {
|
|
491
|
+
cdsCount += 1
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return cdsCount
|
|
496
|
+
}
|
|
497
|
+
|
|
387
498
|
function getRowCount(
|
|
388
499
|
feature: AnnotationFeature,
|
|
389
500
|
featureTypeOntology: OntologyRecord,
|
|
@@ -397,12 +508,13 @@ function getRowCount(
|
|
|
397
508
|
let rowCount = 0
|
|
398
509
|
if (isTranscript) {
|
|
399
510
|
for (const [, child] of children) {
|
|
400
|
-
|
|
401
|
-
if (isCds) {
|
|
511
|
+
if (featureTypeOntology.isTypeOf(child.type, 'CDS')) {
|
|
402
512
|
rowCount += 1
|
|
403
513
|
}
|
|
404
514
|
}
|
|
405
|
-
|
|
515
|
+
|
|
516
|
+
// return 1 if there are no CDSs for non coding genes
|
|
517
|
+
return rowCount === 0 ? 1 : rowCount
|
|
406
518
|
}
|
|
407
519
|
for (const [, child] of children) {
|
|
408
520
|
rowCount += getRowCount(child, featureTypeOntology)
|
|
@@ -449,6 +561,9 @@ function featuresForRow(
|
|
|
449
561
|
for (const cds of cdss) {
|
|
450
562
|
features.push([cds, ...exons, child, feature])
|
|
451
563
|
}
|
|
564
|
+
if (cdss.length === 0) {
|
|
565
|
+
features.push([...exons, child, feature])
|
|
566
|
+
}
|
|
452
567
|
}
|
|
453
568
|
return features
|
|
454
569
|
}
|
|
@@ -44,6 +44,7 @@ export function baseModelFactory(
|
|
|
44
44
|
),
|
|
45
45
|
),
|
|
46
46
|
filteredFeatureTypes: types.array(types.string),
|
|
47
|
+
loadingState: false,
|
|
47
48
|
})
|
|
48
49
|
.views((self) => {
|
|
49
50
|
const { configuration, renderProps: superRenderProps } = self
|
|
@@ -76,6 +77,9 @@ export function baseModelFactory(
|
|
|
76
77
|
}
|
|
77
78
|
return 300
|
|
78
79
|
},
|
|
80
|
+
get loading() {
|
|
81
|
+
return self.loadingState
|
|
82
|
+
},
|
|
79
83
|
}))
|
|
80
84
|
.views((self) => ({
|
|
81
85
|
get rendererTypeName() {
|
|
@@ -167,6 +171,9 @@ export function baseModelFactory(
|
|
|
167
171
|
updateFilteredFeatureTypes(types: string[]) {
|
|
168
172
|
self.filteredFeatureTypes = cast(types)
|
|
169
173
|
},
|
|
174
|
+
setLoading(loading: boolean) {
|
|
175
|
+
self.loadingState = loading
|
|
176
|
+
},
|
|
170
177
|
}))
|
|
171
178
|
.views((self) => {
|
|
172
179
|
const { filteredFeatureTypes, trackMenuItems: superTrackMenuItems } = self
|
|
@@ -244,9 +251,16 @@ export function baseModelFactory(
|
|
|
244
251
|
if (!self.lgv.initialized || self.regionCannotBeRendered()) {
|
|
245
252
|
return
|
|
246
253
|
}
|
|
254
|
+
self.setLoading(true)
|
|
247
255
|
void (
|
|
248
256
|
self.session as unknown as ApolloSessionModel
|
|
249
|
-
).apolloDataStore
|
|
257
|
+
).apolloDataStore
|
|
258
|
+
.loadFeatures(self.regions)
|
|
259
|
+
.then(() => {
|
|
260
|
+
setTimeout(() => {
|
|
261
|
+
self.setLoading(false)
|
|
262
|
+
}, 1000)
|
|
263
|
+
})
|
|
250
264
|
if (self.lgv.bpPerPx <= 3) {
|
|
251
265
|
void (
|
|
252
266
|
self.session as unknown as ApolloSessionModel
|