@apollo-annotation/jbrowse-plugin-apollo 0.3.8 → 0.3.9

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 (48) hide show
  1. package/dist/index.esm.js +10932 -10932
  2. package/dist/index.esm.js.map +1 -1
  3. package/dist/jbrowse-plugin-apollo.cjs.development.js +10845 -10846
  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 +18619 -21342
  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 +7 -7
  12. package/src/ApolloInternetAccount/model.ts +81 -63
  13. package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +4 -4
  14. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +9 -7
  15. package/src/BackendDrivers/CollaborationServerDriver.ts +49 -18
  16. package/src/BackendDrivers/DesktopFileDriver.ts +2 -2
  17. package/src/ChangeManager.ts +3 -1
  18. package/src/FeatureDetailsWidget/BasicInformation.tsx +6 -4
  19. package/src/FeatureDetailsWidget/NumberTextField.tsx +5 -2
  20. package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +39 -203
  21. package/src/LinearApolloDisplay/components/CheckResultWarnings.tsx +92 -0
  22. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +6 -102
  23. package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +31 -230
  24. package/src/LinearApolloDisplay/glyphs/util.ts +19 -0
  25. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceOverlay.ts +181 -0
  26. package/src/LinearApolloReferenceSequenceDisplay/drawSequenceTrack.ts +218 -0
  27. package/src/LinearApolloReferenceSequenceDisplay/stateModel/rendering.ts +62 -386
  28. package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +6 -0
  29. package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +122 -70
  30. package/src/components/AddAssembly.tsx +33 -37
  31. package/src/components/AddFeature.tsx +21 -18
  32. package/src/components/AddRefSeqAliases.tsx +56 -42
  33. package/src/components/CopyFeature.tsx +1 -1
  34. package/src/components/CreateApolloAnnotation.tsx +22 -10
  35. package/src/components/DeleteAssembly.tsx +2 -9
  36. package/src/components/DownloadGFF3.tsx +2 -2
  37. package/src/components/ManageChecks.tsx +2 -9
  38. package/src/components/ManageUsers.tsx +23 -22
  39. package/src/components/OntologyTermAutocomplete.tsx +1 -8
  40. package/src/components/ViewChangeLog.tsx +25 -50
  41. package/src/components/ViewCheckResults.tsx +1 -7
  42. package/src/config.ts +3 -3
  43. package/src/index.ts +17 -16
  44. package/src/makeDisplayComponent.tsx +9 -13
  45. package/src/session/ClientDataStore.ts +32 -14
  46. package/src/session/session.ts +19 -27
  47. package/src/util/glyphUtils.ts +178 -1
  48. package/src/util/loadAssemblyIntoClient.ts +3 -2
@@ -0,0 +1,218 @@
1
+ import { defaultCodonTable, getFrame, revcom } from '@jbrowse/core/util'
2
+ import { type BlockSet } from '@jbrowse/core/util/blockTypes'
3
+ import { type Theme } from '@mui/material'
4
+
5
+ import { type ApolloSessionModel } from '../session'
6
+
7
+ function colorCode(letter: string, theme: Theme) {
8
+ const letterUpper = letter.toUpperCase()
9
+ if (
10
+ letterUpper === 'A' ||
11
+ letterUpper === 'C' ||
12
+ letterUpper === 'G' ||
13
+ letterUpper === 'T'
14
+ ) {
15
+ return theme.palette.bases[letterUpper].main.toString()
16
+ }
17
+ return 'lightgray'
18
+ }
19
+
20
+ function codonColorCode(letter: string, theme: Theme, highContrast?: boolean) {
21
+ if (letter === 'M') {
22
+ return theme.palette.startCodon
23
+ }
24
+ if (letter === '*') {
25
+ return highContrast ? theme.palette.text.primary : theme.palette.stopCodon
26
+ }
27
+ return
28
+ }
29
+
30
+ function drawLetter(
31
+ seqTrackctx: CanvasRenderingContext2D,
32
+ left: number,
33
+ top: number,
34
+ width: number,
35
+ letter: string,
36
+ ) {
37
+ const fontSize = Math.min(width, 10)
38
+ seqTrackctx.fillStyle = '#000'
39
+ seqTrackctx.font = `${fontSize}px`
40
+ const textWidth = seqTrackctx.measureText(letter).width
41
+ const textX = left + (width - textWidth) / 2
42
+ seqTrackctx.fillText(letter, textX, top + 10)
43
+ }
44
+
45
+ function drawTranslationFrameBackgrounds(
46
+ canvas: HTMLCanvasElement,
47
+ ctx: CanvasRenderingContext2D,
48
+ bpPerPx: number,
49
+ theme: Theme,
50
+ dynamicBlocks: BlockSet,
51
+ highContrast: boolean,
52
+ sequenceRowHeight: number,
53
+ ) {
54
+ const frames =
55
+ bpPerPx <= 1 ? [3, 2, 1, 0, 0, -1, -2, -3] : [3, 2, 1, -1, -2, -3]
56
+ for (const [idx, frame] of frames.entries()) {
57
+ const frameColor = theme.palette.framesCDS.at(frame)?.main
58
+ if (!frameColor) {
59
+ continue
60
+ }
61
+ const top = idx * sequenceRowHeight
62
+ const { offsetPx } = dynamicBlocks
63
+ const left = Math.max(0, -offsetPx)
64
+ const width = dynamicBlocks.totalWidthPx
65
+ ctx.fillStyle = highContrast ? theme.palette.background.default : frameColor
66
+ ctx.fillRect(left, top, width, sequenceRowHeight)
67
+ if (highContrast) {
68
+ // eslint-disable-next-line prefer-destructuring
69
+ ctx.strokeStyle = theme.palette.grey[200]
70
+ ctx.strokeRect(left, top, width, sequenceRowHeight)
71
+ }
72
+ }
73
+ // allows inter-region padding lines to show through
74
+ for (const block of dynamicBlocks.getBlocks()) {
75
+ if (block.type === 'InterRegionPaddingBlock') {
76
+ const left = block.offsetPx - dynamicBlocks.offsetPx
77
+ ctx.clearRect(left, 0, block.widthPx, canvas.height)
78
+ }
79
+ }
80
+ }
81
+
82
+ function drawBase(
83
+ ctx: CanvasRenderingContext2D,
84
+ base: string,
85
+ index: number,
86
+ leftPx: number,
87
+ bpPerPx: number,
88
+ rowHeight: number,
89
+ theme: Theme,
90
+ ) {
91
+ const width = 1 / bpPerPx
92
+ if (width < 1) {
93
+ return
94
+ }
95
+ const left = leftPx + index / bpPerPx
96
+ const strands = [-1, 1] as const
97
+ for (const strand of strands) {
98
+ const top = (strand === 1 ? 3 : 4) * rowHeight
99
+ const baseCode = strand === 1 ? base : revcom(base)
100
+ ctx.fillStyle = colorCode(baseCode, theme)
101
+ ctx.fillRect(left, top, width, rowHeight)
102
+ if (1 / bpPerPx >= 12) {
103
+ ctx.strokeStyle = theme.palette.text.disabled
104
+ ctx.strokeRect(left, top, width, rowHeight)
105
+ drawLetter(ctx, left, top, width, baseCode)
106
+ }
107
+ }
108
+ }
109
+
110
+ function drawCodon(
111
+ ctx: CanvasRenderingContext2D,
112
+ codon: string,
113
+ leftPx: number,
114
+ index: number,
115
+ theme: Theme,
116
+ highContrast: boolean,
117
+ bpPerPx: number,
118
+ bp: number,
119
+ rowHeight: number,
120
+ showStartCodons: boolean,
121
+ showStopCodons: boolean,
122
+ ) {
123
+ const frameOffsets = (
124
+ bpPerPx <= 1 ? [0, 2, 1, 0, 7, 6, 5] : [0, 2, 1, 0, 5, 4, 3]
125
+ ).map((b) => b * rowHeight)
126
+ const strands = [-1, 1] as const
127
+ for (const strand of strands) {
128
+ const frame = getFrame(bp, bp + 3, strand, 0)
129
+ const top = frameOffsets.at(frame)
130
+ if (top === undefined) {
131
+ continue
132
+ }
133
+ const left = Math.round(leftPx + index / bpPerPx)
134
+ const width = Math.round(3 / bpPerPx)
135
+ const codonCode = strand === 1 ? codon : revcom(codon)
136
+ const aminoAcidCode =
137
+ defaultCodonTable[codonCode as keyof typeof defaultCodonTable]
138
+ const fillColor = codonColorCode(aminoAcidCode, theme, highContrast)
139
+ if (
140
+ fillColor &&
141
+ ((showStopCodons && aminoAcidCode == '*') ||
142
+ (showStartCodons && aminoAcidCode != '*'))
143
+ ) {
144
+ ctx.fillStyle = fillColor
145
+ ctx.fillRect(left, top, width, rowHeight)
146
+ }
147
+ if (1 / bpPerPx >= 4) {
148
+ ctx.strokeStyle = theme.palette.text.disabled
149
+ ctx.strokeRect(left, top, width, rowHeight)
150
+ drawLetter(ctx, left, top, width, aminoAcidCode)
151
+ }
152
+ }
153
+ }
154
+
155
+ export function drawSequenceTrack(
156
+ canvas: HTMLCanvasElement,
157
+ theme: Theme,
158
+ bpPerPx: number,
159
+ offsetPx: number,
160
+ dynamicBlocks: BlockSet,
161
+ highContrast: boolean,
162
+ showStartCodons: boolean,
163
+ showStopCodons: boolean,
164
+ sequenceRowHeight: number,
165
+ session: ApolloSessionModel,
166
+ ) {
167
+ const ctx = canvas.getContext('2d')
168
+ if (!ctx) {
169
+ return
170
+ }
171
+ ctx.clearRect(0, 0, canvas.width, canvas.height)
172
+
173
+ drawTranslationFrameBackgrounds(
174
+ canvas,
175
+ ctx,
176
+ bpPerPx,
177
+ theme,
178
+ dynamicBlocks,
179
+ highContrast,
180
+ sequenceRowHeight,
181
+ )
182
+
183
+ const { apolloDataStore } = session
184
+ for (const block of dynamicBlocks.contentBlocks) {
185
+ const assembly = apolloDataStore.assemblies.get(block.assemblyName)
186
+ const ref = assembly?.getByRefName(block.refName)
187
+ const roundedStart = Math.floor(block.start)
188
+ const roundedEnd = Math.ceil(block.end)
189
+ let seq = ref?.getSequence(roundedStart, roundedEnd)
190
+ if (!seq) {
191
+ return
192
+ }
193
+ seq = seq.toUpperCase()
194
+ const baseOffsetPx = (block.start - roundedStart) / bpPerPx
195
+ const seqLeftPx = Math.round(block.offsetPx - offsetPx - baseOffsetPx)
196
+ for (let i = 0; i < seq.length; i++) {
197
+ const bp = roundedStart + i
198
+ const codon = seq.slice(i, i + 3)
199
+ drawBase(ctx, seq[i], i, seqLeftPx, bpPerPx, sequenceRowHeight, theme)
200
+ if (codon.length !== 3) {
201
+ continue
202
+ }
203
+ drawCodon(
204
+ ctx,
205
+ codon,
206
+ seqLeftPx,
207
+ i,
208
+ theme,
209
+ highContrast,
210
+ bpPerPx,
211
+ bp,
212
+ sequenceRowHeight,
213
+ showStartCodons,
214
+ showStopCodons,
215
+ )
216
+ }
217
+ }
218
+ }