@apollo-annotation/jbrowse-plugin-apollo 0.3.9 → 0.3.11
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 +235 -120
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +233 -118
- 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 +562 -298
- 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/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -1
- package/src/ApolloInternetAccount/model.ts +6 -2
- package/src/BackendDrivers/CollaborationServerDriver.ts +11 -5
- package/src/ChangeManager.ts +19 -4
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +29 -9
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +2 -2
- package/src/LinearApolloDisplay/glyphs/util.ts +17 -0
- package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +18 -25
- package/src/LinearApolloReferenceSequenceDisplay/drawSequenceTrack.ts +41 -59
- package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +33 -2
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +101 -3
- package/src/components/AddAssembly.tsx +1 -1
- package/src/components/ImportFeatures.tsx +1 -1
- package/src/components/OntologyTermAutocomplete.tsx +2 -2
- package/src/components/OntologyTermMultiSelect.tsx +2 -2
- package/src/makeDisplayComponent.tsx +1 -1
- package/src/session/ClientDataStore.ts +1 -1
- package/src/session/session.ts +4 -0
- package/src/util/displayUtils.ts +28 -0
- package/src/util/glyphUtils.ts +18 -0
|
@@ -1,15 +1,62 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
2
2
|
import type PluginManager from '@jbrowse/core/PluginManager'
|
|
3
3
|
import { type AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
defaultCodonTable,
|
|
6
|
+
doesIntersect2,
|
|
7
|
+
getFrame,
|
|
8
|
+
revcom,
|
|
9
|
+
} from '@jbrowse/core/util'
|
|
5
10
|
import { type Theme, createTheme } from '@mui/material'
|
|
6
11
|
import { autorun } from 'mobx'
|
|
7
12
|
import { type Instance, addDisposer, types } from 'mobx-state-tree'
|
|
8
13
|
|
|
9
14
|
import { type ApolloSessionModel } from '../../session'
|
|
15
|
+
import { codonColorCode } from '../../util/displayUtils'
|
|
10
16
|
|
|
11
17
|
import { layoutsModelFactory } from './layouts'
|
|
12
18
|
|
|
19
|
+
function drawCodon(
|
|
20
|
+
ctx: CanvasRenderingContext2D,
|
|
21
|
+
codon: string,
|
|
22
|
+
leftPx: number,
|
|
23
|
+
index: number,
|
|
24
|
+
theme: Theme,
|
|
25
|
+
highContrast: boolean,
|
|
26
|
+
bpPerPx: number,
|
|
27
|
+
bp: number,
|
|
28
|
+
rowHeight: number,
|
|
29
|
+
showFeatureLabels: boolean,
|
|
30
|
+
showStartCodons: boolean,
|
|
31
|
+
showStopCodons: boolean,
|
|
32
|
+
) {
|
|
33
|
+
const frameOffsets = (
|
|
34
|
+
showFeatureLabels ? [0, 4, 2, 0, 14, 12, 10] : [0, 2, 1, 0, 7, 6, 5]
|
|
35
|
+
).map((b) => b * rowHeight)
|
|
36
|
+
const strands = [-1, 1] as const
|
|
37
|
+
for (const strand of strands) {
|
|
38
|
+
const frame = getFrame(bp, bp + 3, strand, 0)
|
|
39
|
+
const top = frameOffsets.at(frame)
|
|
40
|
+
if (top === undefined) {
|
|
41
|
+
continue
|
|
42
|
+
}
|
|
43
|
+
const left = Math.round(leftPx + index / bpPerPx)
|
|
44
|
+
const width = Math.round(3 / bpPerPx) === 0 ? 1 : Math.round(3 / bpPerPx)
|
|
45
|
+
const codonCode = strand === 1 ? codon : revcom(codon)
|
|
46
|
+
const aminoAcidCode =
|
|
47
|
+
defaultCodonTable[codonCode as keyof typeof defaultCodonTable]
|
|
48
|
+
const fillColor = codonColorCode(aminoAcidCode, theme, highContrast)
|
|
49
|
+
if (
|
|
50
|
+
fillColor &&
|
|
51
|
+
((showStopCodons && aminoAcidCode == '*') ||
|
|
52
|
+
(showStartCodons && aminoAcidCode != '*'))
|
|
53
|
+
) {
|
|
54
|
+
ctx.fillStyle = fillColor
|
|
55
|
+
ctx.fillRect(left, top, width, rowHeight)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
13
60
|
export function renderingModelFactory(
|
|
14
61
|
pluginManager: PluginManager,
|
|
15
62
|
configSchema: AnyConfigurationSchemaType,
|
|
@@ -135,17 +182,29 @@ export function renderingModelFactory(
|
|
|
135
182
|
self,
|
|
136
183
|
autorun(
|
|
137
184
|
() => {
|
|
138
|
-
const {
|
|
185
|
+
const {
|
|
186
|
+
apolloRowHeight,
|
|
187
|
+
canvas,
|
|
188
|
+
featureLayouts,
|
|
189
|
+
featuresHeight,
|
|
190
|
+
lgv,
|
|
191
|
+
session,
|
|
192
|
+
theme,
|
|
193
|
+
showFeatureLabels,
|
|
194
|
+
showStartCodons,
|
|
195
|
+
showStopCodons,
|
|
196
|
+
} = self
|
|
139
197
|
if (!lgv.initialized || self.regionCannotBeRendered()) {
|
|
140
198
|
return
|
|
141
199
|
}
|
|
142
|
-
const { displayedRegions, dynamicBlocks } = lgv
|
|
200
|
+
const { bpPerPx, offsetPx, displayedRegions, dynamicBlocks } = lgv
|
|
143
201
|
|
|
144
202
|
const ctx = canvas?.getContext('2d')
|
|
145
203
|
if (!ctx) {
|
|
146
204
|
return
|
|
147
205
|
}
|
|
148
206
|
ctx.clearRect(0, 0, dynamicBlocks.totalWidthPx, featuresHeight)
|
|
207
|
+
|
|
149
208
|
for (const [idx, featureLayout] of featureLayouts.entries()) {
|
|
150
209
|
const displayedRegion = displayedRegions[idx]
|
|
151
210
|
for (const [row, featureLayoutRow] of featureLayout.entries()) {
|
|
@@ -171,6 +230,45 @@ export function renderingModelFactory(
|
|
|
171
230
|
}
|
|
172
231
|
}
|
|
173
232
|
}
|
|
233
|
+
|
|
234
|
+
if (showStartCodons || showStopCodons) {
|
|
235
|
+
const { apolloDataStore } = session
|
|
236
|
+
for (const block of dynamicBlocks.contentBlocks) {
|
|
237
|
+
const assembly = apolloDataStore.assemblies.get(
|
|
238
|
+
block.assemblyName,
|
|
239
|
+
)
|
|
240
|
+
const ref = assembly?.getByRefName(block.refName)
|
|
241
|
+
const roundedStart = Math.floor(block.start)
|
|
242
|
+
const roundedEnd = Math.ceil(block.end)
|
|
243
|
+
let seq = ref?.getSequence(roundedStart, roundedEnd)
|
|
244
|
+
if (!seq) {
|
|
245
|
+
break
|
|
246
|
+
}
|
|
247
|
+
seq = seq.toUpperCase()
|
|
248
|
+
const baseOffsetPx = (block.start - roundedStart) / bpPerPx
|
|
249
|
+
const seqLeftPx = Math.round(
|
|
250
|
+
block.offsetPx - offsetPx - baseOffsetPx,
|
|
251
|
+
)
|
|
252
|
+
for (let i = 0; i < seq.length; i++) {
|
|
253
|
+
const bp = roundedStart + i
|
|
254
|
+
const codon = seq.slice(i, i + 3)
|
|
255
|
+
drawCodon(
|
|
256
|
+
ctx,
|
|
257
|
+
codon,
|
|
258
|
+
seqLeftPx,
|
|
259
|
+
i,
|
|
260
|
+
theme,
|
|
261
|
+
true,
|
|
262
|
+
bpPerPx,
|
|
263
|
+
bp,
|
|
264
|
+
apolloRowHeight,
|
|
265
|
+
showFeatureLabels,
|
|
266
|
+
showStartCodons,
|
|
267
|
+
showStopCodons,
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
174
272
|
},
|
|
175
273
|
{ name: 'LinearApolloSixFrameDisplayRenderFeatures' },
|
|
176
274
|
),
|
|
@@ -93,7 +93,7 @@ export function OntologyTermAutocomplete({
|
|
|
93
93
|
)
|
|
94
94
|
}
|
|
95
95
|
return () => {
|
|
96
|
-
controller.abort()
|
|
96
|
+
controller.abort('OntologyTermAutocomplete matcher')
|
|
97
97
|
}
|
|
98
98
|
}, [session, valueString, filterTerms, ontologyStore, needToLoadCurrentTerm])
|
|
99
99
|
|
|
@@ -119,7 +119,7 @@ export function OntologyTermAutocomplete({
|
|
|
119
119
|
)
|
|
120
120
|
}
|
|
121
121
|
return () => {
|
|
122
|
-
controller.abort()
|
|
122
|
+
controller.abort('OntologyTermAutocomplete loader')
|
|
123
123
|
}
|
|
124
124
|
}, [
|
|
125
125
|
needToLoadTermChoices,
|
|
@@ -89,7 +89,7 @@ function TermTagWithTooltip({
|
|
|
89
89
|
})
|
|
90
90
|
|
|
91
91
|
return () => {
|
|
92
|
-
controller.abort()
|
|
92
|
+
controller.abort('TermTagWithTooltip ')
|
|
93
93
|
}
|
|
94
94
|
}, [termId, ontology, manager])
|
|
95
95
|
|
|
@@ -211,7 +211,7 @@ export function OntologyTermMultiSelect({
|
|
|
211
211
|
})
|
|
212
212
|
|
|
213
213
|
return () => {
|
|
214
|
-
aborter.abort()
|
|
214
|
+
aborter.abort('OntologyTermMultiSelect')
|
|
215
215
|
}
|
|
216
216
|
}, [getOntologyTerms, ontology, includeDeprecated, inputValue, value])
|
|
217
217
|
|
|
@@ -97,7 +97,7 @@ const ResizeHandle = ({
|
|
|
97
97
|
const controller = new AbortController()
|
|
98
98
|
const { signal } = controller
|
|
99
99
|
function abortDrag() {
|
|
100
|
-
controller.abort()
|
|
100
|
+
controller.abort('makeDisplayComponent')
|
|
101
101
|
}
|
|
102
102
|
globalThis.addEventListener('mousemove', mouseMove, { signal })
|
|
103
103
|
globalThis.addEventListener('mouseup', abortDrag, { signal })
|
|
@@ -204,7 +204,7 @@ export function clientDataStoreFactory(
|
|
|
204
204
|
statusMessage: `Loading ontology "${name}", version "${version}", this may take a while`,
|
|
205
205
|
progressPct: 0,
|
|
206
206
|
cancelCallback: () => {
|
|
207
|
-
controller.abort()
|
|
207
|
+
controller.abort('ClientDataStore')
|
|
208
208
|
jobsManager.abortJob(job.name)
|
|
209
209
|
},
|
|
210
210
|
}
|
package/src/session/session.ts
CHANGED
|
@@ -74,6 +74,7 @@ export function extendSession(
|
|
|
74
74
|
apolloSelectedFeature: types.safeReference(AnnotationFeatureExtended),
|
|
75
75
|
jobsManager: types.optional(ApolloJobModel, {}),
|
|
76
76
|
isLocked: types.optional(types.boolean, false),
|
|
77
|
+
changeInProgress: types.optional(types.boolean, false),
|
|
77
78
|
})
|
|
78
79
|
.volatile(() => ({
|
|
79
80
|
apolloHoveredFeature: undefined as HoveredFeature | undefined,
|
|
@@ -141,6 +142,9 @@ export function extendSession(
|
|
|
141
142
|
toggleLocked() {
|
|
142
143
|
self.isLocked = !self.isLocked
|
|
143
144
|
},
|
|
145
|
+
setChangeInProgress(changeInProgress: boolean) {
|
|
146
|
+
self.changeInProgress = changeInProgress
|
|
147
|
+
},
|
|
144
148
|
getPluginConfiguration() {
|
|
145
149
|
const { jbrowse } = getRoot<ApolloRootModel>(self)
|
|
146
150
|
const pluginConfiguration =
|
package/src/util/displayUtils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type CheckResultIdsType } from '@apollo-annotation/mst'
|
|
2
|
+
import { type Theme } from '@mui/material'
|
|
2
3
|
import { makeStyles } from 'tss-react/mui'
|
|
3
4
|
|
|
4
5
|
export { default as EditZoomThresholdDialog } from '../components/EditZoomThresholdDialog'
|
|
@@ -147,3 +148,30 @@ export function clusterResultByMessage<
|
|
|
147
148
|
)
|
|
148
149
|
return clusters
|
|
149
150
|
}
|
|
151
|
+
|
|
152
|
+
export function codonColorCode(
|
|
153
|
+
letter: string,
|
|
154
|
+
theme: Theme,
|
|
155
|
+
highContrast?: boolean,
|
|
156
|
+
) {
|
|
157
|
+
if (letter === 'M') {
|
|
158
|
+
return theme.palette.startCodon
|
|
159
|
+
}
|
|
160
|
+
if (letter === '*') {
|
|
161
|
+
return highContrast ? theme.palette.text.primary : theme.palette.stopCodon
|
|
162
|
+
}
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function colorCode(letter: string, theme: Theme) {
|
|
167
|
+
const letterUpper = letter.toUpperCase()
|
|
168
|
+
if (
|
|
169
|
+
letterUpper === 'A' ||
|
|
170
|
+
letterUpper === 'C' ||
|
|
171
|
+
letterUpper === 'G' ||
|
|
172
|
+
letterUpper === 'T'
|
|
173
|
+
) {
|
|
174
|
+
return theme.palette.bases[letterUpper].main.toString()
|
|
175
|
+
}
|
|
176
|
+
return 'lightgray'
|
|
177
|
+
}
|
package/src/util/glyphUtils.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { type MenuItem } from '@jbrowse/core/ui'
|
|
|
7
7
|
import {
|
|
8
8
|
type AbstractSessionModel,
|
|
9
9
|
getContainingView,
|
|
10
|
+
isSessionModelWithWidgets,
|
|
10
11
|
} from '@jbrowse/core/util'
|
|
11
12
|
import { type LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
12
13
|
import SkipNextRoundedIcon from '@mui/icons-material/SkipNextRounded'
|
|
@@ -363,6 +364,23 @@ export function getContextMenuItemsForFeature(
|
|
|
363
364
|
},
|
|
364
365
|
},
|
|
365
366
|
)
|
|
367
|
+
if (isSessionModelWithWidgets(session)) {
|
|
368
|
+
menuItems.push({
|
|
369
|
+
label: 'Open feature details',
|
|
370
|
+
onClick: () => {
|
|
371
|
+
const apolloGeneWidget = session.addWidget(
|
|
372
|
+
'ApolloFeatureDetailsWidget',
|
|
373
|
+
'apolloFeatureDetailsWidget',
|
|
374
|
+
{
|
|
375
|
+
feature: sourceFeature,
|
|
376
|
+
assembly: currentAssemblyId,
|
|
377
|
+
refName: region.refName,
|
|
378
|
+
},
|
|
379
|
+
)
|
|
380
|
+
session.showWidget(apolloGeneWidget)
|
|
381
|
+
},
|
|
382
|
+
})
|
|
383
|
+
}
|
|
366
384
|
return menuItems
|
|
367
385
|
}
|
|
368
386
|
|