react-msaview 5.1.1 → 5.2.1
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/README.md +41 -8
- package/bundle/index.js +17 -17
- package/bundle/index.js.LICENSE.txt +1 -1
- package/bundle/index.js.map +1 -1
- package/dist/calculateBlocks.d.ts +4 -10
- package/dist/calculateBlocks.js +12 -20
- package/dist/calculateBlocks.js.map +1 -1
- package/dist/components/ConservationTrack.js +20 -37
- package/dist/components/ConservationTrack.js.map +1 -1
- package/dist/components/MSAView.js +8 -1
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/ResizeHandles.d.ts +3 -0
- package/dist/components/ResizeHandles.js +60 -105
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/TextTrack.js +25 -34
- package/dist/components/TextTrack.js.map +1 -1
- package/dist/components/Track.js +1 -1
- package/dist/components/Track.js.map +1 -1
- package/dist/components/VerticalScrollbar.js +2 -2
- package/dist/components/VerticalScrollbar.js.map +1 -1
- package/dist/components/dialogs/ExportSVGDialog.js +20 -20
- package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
- package/dist/components/dialogs/InterProScanDialog.js +6 -1
- package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
- package/dist/components/dialogs/UserProvidedDomainsDialog.js +1 -2
- package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +1 -1
- package/dist/components/header/ColorSchemeMenu.js +1 -1
- package/dist/components/header/ColorSchemeMenu.js.map +1 -1
- package/dist/components/header/FileMenu.js +3 -2
- package/dist/components/header/FileMenu.js.map +1 -1
- package/dist/components/header/Header.js +1 -1
- package/dist/components/header/HeaderInfoArea.js +28 -8
- package/dist/components/header/HeaderInfoArea.js.map +1 -1
- package/dist/components/header/MSASettingsMenu.js +1 -1
- package/dist/components/header/MSASettingsMenu.js.map +1 -1
- package/dist/components/header/TreeSettingsMenu.js +1 -1
- package/dist/components/header/TreeSettingsMenu.js.map +1 -1
- package/dist/components/header/ZoomControls.js +7 -2
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/header/ZoomMenu.js +9 -0
- package/dist/components/header/ZoomMenu.js.map +1 -1
- package/dist/components/header/settingsMenuItems.js +24 -8
- package/dist/components/header/settingsMenuItems.js.map +1 -1
- package/dist/components/minimap/Minimap.js +6 -17
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/minimap/MinimapSVG.js +7 -17
- package/dist/components/minimap/MinimapSVG.js.map +1 -1
- package/dist/components/minimap/minimapLayout.d.ts +9 -0
- package/dist/components/minimap/minimapLayout.js +15 -0
- package/dist/components/minimap/minimapLayout.js.map +1 -0
- package/dist/components/msa/MSACanvas.js +6 -1
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +5 -1
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js +2 -2
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/getVisibleLeaves.d.ts +6 -0
- package/dist/components/msa/getVisibleLeaves.js +9 -0
- package/dist/components/msa/getVisibleLeaves.js.map +1 -0
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +2 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +5 -6
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +2 -1
- package/dist/components/msa/renderMSABlock.js +100 -88
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.js +5 -4
- package/dist/components/msa/renderMSAMouseover.js.map +1 -1
- package/dist/components/msa/visibleColRange.d.ts +8 -0
- package/dist/components/msa/visibleColRange.js +10 -0
- package/dist/components/msa/visibleColRange.js.map +1 -0
- package/dist/components/renderCtx.d.ts +7 -0
- package/dist/components/renderCtx.js +2 -0
- package/dist/components/renderCtx.js.map +1 -0
- package/dist/components/tracks/renderTracksSvg.d.ts +6 -5
- package/dist/components/tracks/renderTracksSvg.js +13 -5
- package/dist/components/tracks/renderTracksSvg.js.map +1 -1
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +2 -10
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +5 -4
- package/dist/components/tree/renderTreeCanvas.js +18 -26
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/util.d.ts +0 -14
- package/dist/components/util.js +0 -58
- package/dist/components/util.js.map +1 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +7 -0
- package/dist/constants.js.map +1 -1
- package/dist/flatToTree.js +6 -0
- package/dist/flatToTree.js.map +1 -1
- package/dist/hierarchy.d.ts +3 -1
- package/dist/hierarchy.js +142 -89
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/launchInterProScan.js +22 -9
- package/dist/launchInterProScan.js.map +1 -1
- package/dist/measureTextCanvas.js +2 -1
- package/dist/measureTextCanvas.js.map +1 -1
- package/dist/model.d.ts +234 -176
- package/dist/model.js +285 -259
- package/dist/model.js.map +1 -1
- package/dist/parseAsn1.js +8 -2
- package/dist/parseAsn1.js.map +1 -1
- package/dist/renderToSvg.d.ts +1 -1
- package/dist/renderToSvg.js +43 -46
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +0 -9
- package/dist/rowCoordinateCalculations.js +0 -20
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/setFontSize.d.ts +3 -0
- package/dist/setFontSize.js +14 -0
- package/dist/setFontSize.js.map +1 -0
- package/dist/useDevicePixelRatio.d.ts +1 -0
- package/dist/useDevicePixelRatio.js +27 -0
- package/dist/useDevicePixelRatio.js.map +1 -0
- package/dist/useWheelScroll.d.ts +3 -1
- package/dist/useWheelScroll.js +64 -22
- package/dist/useWheelScroll.js.map +1 -1
- package/dist/util.d.ts +5 -0
- package/dist/util.js +59 -1
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webpack.js +0 -1
- package/dist/webpack.js.map +1 -1
- package/dist/wheelZoom.d.ts +4 -0
- package/dist/wheelZoom.js +43 -0
- package/dist/wheelZoom.js.map +1 -0
- package/package.json +5 -5
- package/src/calculateBlocks.ts +18 -51
- package/src/components/ConservationTrack.tsx +20 -45
- package/src/components/MSAView.tsx +10 -1
- package/src/components/ResizeHandles.tsx +101 -113
- package/src/components/TextTrack.tsx +31 -38
- package/src/components/Track.tsx +1 -1
- package/src/components/VerticalScrollbar.tsx +2 -2
- package/src/components/dialogs/ExportSVGDialog.tsx +27 -17
- package/src/components/dialogs/InterProScanDialog.tsx +6 -1
- package/src/components/dialogs/UserProvidedDomainsDialog.tsx +1 -2
- package/src/components/header/ColorSchemeMenu.tsx +1 -0
- package/src/components/header/FileMenu.tsx +3 -1
- package/src/components/header/Header.tsx +1 -1
- package/src/components/header/HeaderInfoArea.tsx +32 -7
- package/src/components/header/MSASettingsMenu.tsx +1 -0
- package/src/components/header/TreeSettingsMenu.tsx +1 -0
- package/src/components/header/ZoomControls.tsx +14 -1
- package/src/components/header/ZoomMenu.tsx +10 -0
- package/src/components/header/settingsMenuItems.ts +24 -8
- package/src/components/minimap/Minimap.tsx +6 -20
- package/src/components/minimap/MinimapSVG.tsx +10 -27
- package/src/components/minimap/minimapLayout.ts +17 -0
- package/src/components/msa/MSACanvas.tsx +9 -0
- package/src/components/msa/MSACanvasBlock.tsx +7 -1
- package/src/components/msa/MSAMouseoverCanvas.tsx +4 -3
- package/src/components/msa/getVisibleLeaves.ts +21 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +9 -9
- package/src/components/msa/renderMSABlock.ts +123 -125
- package/src/components/msa/renderMSAMouseover.ts +5 -4
- package/src/components/msa/visibleColRange.ts +17 -0
- package/src/components/renderCtx.ts +29 -0
- package/src/components/tracks/renderTracksSvg.ts +20 -10
- package/src/components/tree/TreeCanvas.tsx +3 -1
- package/src/components/tree/TreeCanvasBlock.tsx +2 -12
- package/src/components/tree/renderTreeCanvas.ts +27 -30
- package/src/components/util.ts +0 -81
- package/src/constants.ts +8 -0
- package/src/flatToTree.test.ts +30 -0
- package/src/flatToTree.ts +10 -1
- package/src/hierarchy.test.ts +53 -1
- package/src/hierarchy.ts +153 -100
- package/src/index.ts +8 -0
- package/src/launchInterProScan.ts +33 -11
- package/src/measureTextCanvas.ts +3 -1
- package/src/model.ts +359 -306
- package/src/parseAsn1.test.ts +6 -0
- package/src/parseAsn1.ts +11 -3
- package/src/renderToSvg.tsx +99 -95
- package/src/rowCoordinateCalculations.test.ts +0 -51
- package/src/rowCoordinateCalculations.ts +0 -23
- package/src/setFontSize.test.ts +33 -0
- package/src/setFontSize.ts +20 -0
- package/src/useDevicePixelRatio.ts +29 -0
- package/src/useWheelScroll.ts +79 -21
- package/src/util.ts +60 -1
- package/src/version.ts +1 -1
- package/src/webpack.ts +0 -1
- package/src/wheelZoom.test.ts +46 -0
- package/src/wheelZoom.ts +47 -0
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import { getVisibleLeaves } from './getVisibleLeaves.ts'
|
|
2
|
+
import { visibleColRange } from './visibleColRange.ts'
|
|
3
|
+
import { setFontSize } from '../../setFontSize.ts'
|
|
4
|
+
import { adjustColorForContrast } from '../../util.ts'
|
|
5
|
+
|
|
1
6
|
import type { HierarchyNode } from '../../hierarchy.ts'
|
|
2
7
|
import type { MsaViewModel } from '../../model.ts'
|
|
3
8
|
import type { NodeWithIdsAndLength } from '../../types.ts'
|
|
9
|
+
import type { RenderCtx } from '../renderCtx.ts'
|
|
4
10
|
import type { Theme } from '@mui/material'
|
|
5
11
|
|
|
6
12
|
export function renderMSABlock({
|
|
@@ -19,7 +25,7 @@ export function renderMSABlock({
|
|
|
19
25
|
theme: Theme
|
|
20
26
|
model: MsaViewModel
|
|
21
27
|
contrastScheme: Record<string, string>
|
|
22
|
-
ctx:
|
|
28
|
+
ctx: RenderCtx
|
|
23
29
|
highResScaleFactorOverride?: number
|
|
24
30
|
blockSizeXOverride?: number
|
|
25
31
|
blockSizeYOverride?: number
|
|
@@ -31,50 +37,51 @@ export function renderMSABlock({
|
|
|
31
37
|
fontSize,
|
|
32
38
|
highResScaleFactor,
|
|
33
39
|
actuallyShowDomains,
|
|
34
|
-
leaves,
|
|
35
40
|
bgColor,
|
|
36
41
|
} = model
|
|
37
|
-
const k = highResScaleFactorOverride
|
|
38
|
-
const bx = blockSizeXOverride
|
|
39
|
-
const by = blockSizeYOverride
|
|
42
|
+
const k = highResScaleFactorOverride ?? highResScaleFactor
|
|
43
|
+
const bx = blockSizeXOverride ?? blockSize
|
|
44
|
+
const by = blockSizeYOverride ?? blockSize
|
|
40
45
|
ctx.resetTransform()
|
|
41
46
|
ctx.scale(k, k)
|
|
42
47
|
ctx.translate(-offsetX, rowHeight / 2 - offsetY)
|
|
43
48
|
ctx.textAlign = 'center'
|
|
44
|
-
|
|
45
|
-
// (an invalid "bold bold 16px" string would be silently ignored by canvas,
|
|
46
|
-
// freezing the font size against zoom changes)
|
|
47
|
-
ctx.font = ctx.font.replace(
|
|
48
|
-
/(?:bold )?\d+px/,
|
|
49
|
-
`${bgColor ? '' : 'bold '}${fontSize}px`,
|
|
50
|
-
)
|
|
49
|
+
setFontSize(ctx, fontSize, !bgColor)
|
|
51
50
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
const { xStart, xEnd } = visibleColRange({
|
|
52
|
+
offsetX,
|
|
53
|
+
blockWidth: bx,
|
|
54
|
+
colWidth,
|
|
55
|
+
})
|
|
56
|
+
const visibleLeaves = getVisibleLeaves({ model, offsetY, blockSizeY: by })
|
|
57
|
+
const { relativeTo, columns } = model
|
|
58
|
+
const referenceSeq = relativeTo
|
|
59
|
+
? columns.get(relativeTo)?.slice(xStart, xEnd)
|
|
60
|
+
: null
|
|
57
61
|
|
|
58
62
|
if (!actuallyShowDomains) {
|
|
59
|
-
|
|
63
|
+
drawTilesAndText({
|
|
60
64
|
model,
|
|
61
65
|
ctx,
|
|
62
66
|
theme,
|
|
67
|
+
contrastScheme,
|
|
63
68
|
offsetX,
|
|
64
69
|
xStart,
|
|
65
70
|
xEnd,
|
|
66
71
|
visibleLeaves,
|
|
72
|
+
referenceSeq,
|
|
73
|
+
})
|
|
74
|
+
} else {
|
|
75
|
+
drawText({
|
|
76
|
+
model,
|
|
77
|
+
ctx,
|
|
78
|
+
offsetX,
|
|
79
|
+
xStart,
|
|
80
|
+
xEnd,
|
|
81
|
+
visibleLeaves,
|
|
82
|
+
referenceSeq,
|
|
67
83
|
})
|
|
68
84
|
}
|
|
69
|
-
drawText({
|
|
70
|
-
model,
|
|
71
|
-
ctx,
|
|
72
|
-
offsetX,
|
|
73
|
-
contrastScheme,
|
|
74
|
-
xStart,
|
|
75
|
-
xEnd,
|
|
76
|
-
visibleLeaves,
|
|
77
|
-
})
|
|
78
85
|
drawInsertionIndicators({
|
|
79
86
|
model,
|
|
80
87
|
ctx,
|
|
@@ -85,22 +92,26 @@ export function renderMSABlock({
|
|
|
85
92
|
ctx.resetTransform()
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
function
|
|
95
|
+
function drawTilesAndText({
|
|
89
96
|
model,
|
|
90
97
|
offsetX,
|
|
91
98
|
ctx,
|
|
92
|
-
visibleLeaves,
|
|
93
99
|
theme,
|
|
100
|
+
contrastScheme,
|
|
101
|
+
visibleLeaves,
|
|
94
102
|
xStart,
|
|
95
103
|
xEnd,
|
|
104
|
+
referenceSeq,
|
|
96
105
|
}: {
|
|
97
106
|
model: MsaViewModel
|
|
98
107
|
offsetX: number
|
|
99
108
|
theme: Theme
|
|
100
|
-
ctx:
|
|
109
|
+
ctx: RenderCtx
|
|
110
|
+
contrastScheme: Record<string, string>
|
|
101
111
|
visibleLeaves: HierarchyNode<NodeWithIdsAndLength>[]
|
|
102
112
|
xStart: number
|
|
103
113
|
xEnd: number
|
|
114
|
+
referenceSeq: string | null | undefined
|
|
104
115
|
}) {
|
|
105
116
|
const {
|
|
106
117
|
bgColor,
|
|
@@ -110,131 +121,118 @@ function drawTiles({
|
|
|
110
121
|
colWidth,
|
|
111
122
|
rowHeight,
|
|
112
123
|
relativeTo,
|
|
124
|
+
showMsaLetters,
|
|
125
|
+
colClustalX,
|
|
126
|
+
colConsensus,
|
|
113
127
|
} = model
|
|
114
128
|
|
|
115
|
-
// Get reference sequence if relativeTo is set
|
|
116
|
-
const referenceSeq = relativeTo
|
|
117
|
-
? columns[relativeTo]?.slice(xStart, xEnd)
|
|
118
|
-
: null
|
|
119
|
-
|
|
120
129
|
const isClustalX = colorSchemeName === 'clustalx_protein_dynamic'
|
|
121
130
|
const isPercentIdentity = colorSchemeName === 'percent_identity_dynamic'
|
|
131
|
+
const drawBgTiles = bgColor || isClustalX || isPercentIdentity
|
|
132
|
+
if (!drawBgTiles && !showMsaLetters) {
|
|
133
|
+
return
|
|
134
|
+
}
|
|
122
135
|
const offsetXAligned = offsetX - (offsetX % colWidth)
|
|
136
|
+
const halfColWidth = colWidth / 2
|
|
137
|
+
const quarterRowHeight = rowHeight / 4
|
|
123
138
|
|
|
124
139
|
for (let i = 0, l1 = visibleLeaves.length; i < l1; i++) {
|
|
125
140
|
const node = visibleLeaves[i]!
|
|
126
|
-
const {
|
|
127
|
-
data: { name },
|
|
128
|
-
} = node
|
|
141
|
+
const { name } = node.data
|
|
129
142
|
const y = node.x!
|
|
130
|
-
const str = columns
|
|
131
|
-
if (str) {
|
|
132
|
-
|
|
133
|
-
|
|
143
|
+
const str = columns.get(name)?.slice(xStart, xEnd)
|
|
144
|
+
if (!str) {
|
|
145
|
+
continue
|
|
146
|
+
}
|
|
147
|
+
const tileY = y - rowHeight
|
|
148
|
+
const textY = y - quarterRowHeight
|
|
134
149
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
150
|
+
for (let j = 0, l2 = str.length; j < l2; j++) {
|
|
151
|
+
const letter = str[j]!
|
|
152
|
+
const x = j * colWidth + offsetXAligned
|
|
153
|
+
const isMatchingReference =
|
|
154
|
+
referenceSeq && name !== relativeTo && letter === referenceSeq[j]
|
|
138
155
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
let color: string | undefined
|
|
157
|
+
if (isClustalX) {
|
|
158
|
+
color = colClustalX[xStart + j]![letter]
|
|
159
|
+
} else if (isPercentIdentity) {
|
|
160
|
+
const consensus = colConsensus[xStart + j]!
|
|
161
|
+
color = letter === consensus.letter ? consensus.color : undefined
|
|
162
|
+
} else {
|
|
163
|
+
color = colorScheme[letter]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (drawBgTiles) {
|
|
167
|
+
ctx.fillStyle = isMatchingReference
|
|
168
|
+
? theme.palette.action.hover
|
|
169
|
+
: color || theme.palette.background.default
|
|
170
|
+
ctx.fillRect(x, tileY, colWidth, rowHeight)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (showMsaLetters) {
|
|
174
|
+
ctx.fillStyle = bgColor
|
|
175
|
+
? (contrastScheme[letter] ?? 'black')
|
|
176
|
+
: color
|
|
177
|
+
? adjustColorForContrast(color, theme.palette.background.default)
|
|
178
|
+
: theme.palette.text.primary
|
|
179
|
+
ctx.fillText(
|
|
180
|
+
isMatchingReference ? '.' : letter,
|
|
181
|
+
x + halfColWidth,
|
|
182
|
+
textY,
|
|
183
|
+
)
|
|
161
184
|
}
|
|
162
185
|
}
|
|
163
186
|
}
|
|
164
187
|
}
|
|
165
188
|
|
|
189
|
+
// When domains are shown the background tiles come from renderBoxFeatureCanvasBlock,
|
|
190
|
+
// so we only need to draw text here.
|
|
166
191
|
function drawText({
|
|
167
192
|
model,
|
|
168
193
|
offsetX,
|
|
169
|
-
contrastScheme,
|
|
170
194
|
ctx,
|
|
171
195
|
visibleLeaves,
|
|
172
196
|
xStart,
|
|
173
197
|
xEnd,
|
|
198
|
+
referenceSeq,
|
|
174
199
|
}: {
|
|
175
200
|
offsetX: number
|
|
176
201
|
model: MsaViewModel
|
|
177
|
-
|
|
178
|
-
ctx: CanvasRenderingContext2D
|
|
202
|
+
ctx: RenderCtx
|
|
179
203
|
visibleLeaves: HierarchyNode<NodeWithIdsAndLength>[]
|
|
180
204
|
xStart: number
|
|
181
205
|
xEnd: number
|
|
206
|
+
referenceSeq: string | null | undefined
|
|
182
207
|
}) {
|
|
183
|
-
const {
|
|
184
|
-
bgColor,
|
|
185
|
-
actuallyShowDomains,
|
|
186
|
-
showMsaLetters,
|
|
187
|
-
colorScheme,
|
|
188
|
-
columns,
|
|
189
|
-
colWidth,
|
|
190
|
-
rowHeight,
|
|
191
|
-
relativeTo,
|
|
192
|
-
} = model
|
|
208
|
+
const { showMsaLetters, columns, colWidth, rowHeight, relativeTo } = model
|
|
193
209
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const quarterRowHeight = rowHeight / 4
|
|
203
|
-
|
|
204
|
-
for (let i = 0, l1 = visibleLeaves.length; i < l1; i++) {
|
|
205
|
-
const node = visibleLeaves[i]!
|
|
206
|
-
const {
|
|
207
|
-
data: { name },
|
|
208
|
-
} = node
|
|
209
|
-
const y = node.x! - quarterRowHeight
|
|
210
|
-
const str = columns[name]?.slice(xStart, xEnd)
|
|
211
|
-
if (str) {
|
|
212
|
-
for (let j = 0, l2 = str.length; j < l2; j++) {
|
|
213
|
-
const letter = str[j]!
|
|
214
|
-
|
|
215
|
-
// Check if this position matches the reference
|
|
216
|
-
const isMatchingReference =
|
|
217
|
-
referenceSeq && name !== relativeTo && letter === referenceSeq[j]
|
|
218
|
-
|
|
219
|
-
// Show dot for matching positions, original letter for differences
|
|
220
|
-
const displayLetter = isMatchingReference ? '.' : letter
|
|
221
|
-
|
|
222
|
-
const color = colorScheme[letter.toUpperCase()]
|
|
223
|
-
const contrast = contrastScheme[letter.toUpperCase()] || 'black'
|
|
210
|
+
if (!showMsaLetters) {
|
|
211
|
+
return
|
|
212
|
+
}
|
|
213
|
+
const offsetXAligned = offsetX - (offsetX % colWidth)
|
|
214
|
+
const halfColWidth = colWidth / 2
|
|
215
|
+
const quarterRowHeight = rowHeight / 4
|
|
216
|
+
// note: -rowHeight/4 matches +rowHeight/4 in tree
|
|
217
|
+
ctx.fillStyle = 'black'
|
|
224
218
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
219
|
+
for (let i = 0, l1 = visibleLeaves.length; i < l1; i++) {
|
|
220
|
+
const node = visibleLeaves[i]!
|
|
221
|
+
const { name } = node.data
|
|
222
|
+
const y = node.x! - quarterRowHeight
|
|
223
|
+
const str = columns.get(name)?.slice(xStart, xEnd)
|
|
224
|
+
if (!str) {
|
|
225
|
+
continue
|
|
226
|
+
}
|
|
227
|
+
for (let j = 0, l2 = str.length; j < l2; j++) {
|
|
228
|
+
const letter = str[j]!
|
|
229
|
+
const isMatchingReference =
|
|
230
|
+
referenceSeq && name !== relativeTo && letter === referenceSeq[j]
|
|
231
|
+
ctx.fillText(
|
|
232
|
+
isMatchingReference ? '.' : letter,
|
|
233
|
+
j * colWidth + offsetXAligned + halfColWidth,
|
|
234
|
+
y,
|
|
235
|
+
)
|
|
238
236
|
}
|
|
239
237
|
}
|
|
240
238
|
}
|
|
@@ -247,7 +245,7 @@ function drawInsertionIndicators({
|
|
|
247
245
|
xEnd,
|
|
248
246
|
}: {
|
|
249
247
|
model: MsaViewModel
|
|
250
|
-
ctx:
|
|
248
|
+
ctx: RenderCtx
|
|
251
249
|
visibleLeaves: HierarchyNode<NodeWithIdsAndLength>[]
|
|
252
250
|
xStart: number
|
|
253
251
|
xEnd: number
|
|
@@ -273,7 +271,7 @@ function drawZigZag({
|
|
|
273
271
|
offset,
|
|
274
272
|
}: {
|
|
275
273
|
model: MsaViewModel
|
|
276
|
-
ctx:
|
|
274
|
+
ctx: RenderCtx
|
|
277
275
|
visibleLeaves: HierarchyNode<NodeWithIdsAndLength>[]
|
|
278
276
|
xStart: number
|
|
279
277
|
xEnd: number
|
|
@@ -25,17 +25,18 @@ export function renderMouseover({
|
|
|
25
25
|
mouseClickRow,
|
|
26
26
|
mouseClickCol,
|
|
27
27
|
relativeTo,
|
|
28
|
-
rowNamesSet,
|
|
29
28
|
hoveredTreeNode,
|
|
30
29
|
highlightedColumns,
|
|
30
|
+
highResScaleFactor,
|
|
31
31
|
} = model
|
|
32
32
|
const width = msaAreaWidth - verticalScrollbarWidth
|
|
33
33
|
ctx.resetTransform()
|
|
34
|
-
ctx.clearRect(0, 0, width, height)
|
|
34
|
+
ctx.clearRect(0, 0, width * highResScaleFactor, height * highResScaleFactor)
|
|
35
|
+
ctx.scale(highResScaleFactor, highResScaleFactor)
|
|
35
36
|
|
|
36
37
|
// Highlight reference row (relativeTo) persistently
|
|
37
38
|
if (relativeTo) {
|
|
38
|
-
const referenceRowIndex = rowNamesSet.get(relativeTo)
|
|
39
|
+
const referenceRowIndex = model.rowNamesSet.get(relativeTo)
|
|
39
40
|
if (referenceRowIndex !== undefined) {
|
|
40
41
|
ctx.fillStyle = referenceColor
|
|
41
42
|
ctx.fillRect(0, referenceRowIndex * rowHeight + scrollY, width, rowHeight)
|
|
@@ -46,7 +47,7 @@ export function renderMouseover({
|
|
|
46
47
|
if (hoveredTreeNode) {
|
|
47
48
|
ctx.fillStyle = multiRowHoverColor
|
|
48
49
|
for (const descendantName of hoveredTreeNode.descendantNames) {
|
|
49
|
-
const rowIndex = rowNamesSet.get(descendantName)
|
|
50
|
+
const rowIndex = model.rowNamesSet.get(descendantName)
|
|
50
51
|
if (rowIndex !== undefined) {
|
|
51
52
|
ctx.fillRect(0, rowIndex * rowHeight + scrollY, width, rowHeight)
|
|
52
53
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// The half-open range of alignment columns [xStart, xEnd) intersecting a block
|
|
2
|
+
// of width blockWidth at horizontal offset offsetX. X-axis counterpart to
|
|
3
|
+
// getVisibleLeaves.
|
|
4
|
+
export function visibleColRange({
|
|
5
|
+
offsetX,
|
|
6
|
+
blockWidth,
|
|
7
|
+
colWidth,
|
|
8
|
+
}: {
|
|
9
|
+
offsetX: number
|
|
10
|
+
blockWidth: number
|
|
11
|
+
colWidth: number
|
|
12
|
+
}) {
|
|
13
|
+
return {
|
|
14
|
+
xStart: Math.max(0, Math.floor(offsetX / colWidth)),
|
|
15
|
+
xEnd: Math.max(0, Math.ceil((offsetX + blockWidth) / colWidth)),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The subset of the canvas 2D API that the block renderers use. Both a real
|
|
3
|
+
* `CanvasRenderingContext2D` and the `@jbrowse/svgcanvas` `Context` (used for
|
|
4
|
+
* SVG export) satisfy this, so renderers can be typed against it without an
|
|
5
|
+
* `as any` cast at the SVG-export boundary.
|
|
6
|
+
*/
|
|
7
|
+
export type RenderCtx = Pick<
|
|
8
|
+
CanvasRenderingContext2D,
|
|
9
|
+
| 'arc'
|
|
10
|
+
| 'beginPath'
|
|
11
|
+
| 'clearRect'
|
|
12
|
+
| 'fill'
|
|
13
|
+
| 'fillRect'
|
|
14
|
+
| 'fillStyle'
|
|
15
|
+
| 'fillText'
|
|
16
|
+
| 'font'
|
|
17
|
+
| 'lineTo'
|
|
18
|
+
| 'lineWidth'
|
|
19
|
+
| 'measureText'
|
|
20
|
+
| 'moveTo'
|
|
21
|
+
| 'resetTransform'
|
|
22
|
+
| 'scale'
|
|
23
|
+
| 'setLineDash'
|
|
24
|
+
| 'stroke'
|
|
25
|
+
| 'strokeRect'
|
|
26
|
+
| 'strokeStyle'
|
|
27
|
+
| 'textAlign'
|
|
28
|
+
| 'translate'
|
|
29
|
+
>
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { setFontSize } from '../../setFontSize.ts'
|
|
2
|
+
import { visibleColRange } from '../msa/visibleColRange.ts'
|
|
3
|
+
|
|
1
4
|
import type { MsaViewModel } from '../../model.ts'
|
|
2
5
|
import type { BasicTrack } from '../../types.ts'
|
|
6
|
+
import type { RenderCtx } from '../renderCtx.ts'
|
|
3
7
|
|
|
4
8
|
export function drawConservationBars({
|
|
5
9
|
ctx,
|
|
@@ -9,15 +13,18 @@ export function drawConservationBars({
|
|
|
9
13
|
offsetX,
|
|
10
14
|
blockSize,
|
|
11
15
|
}: {
|
|
12
|
-
ctx:
|
|
16
|
+
ctx: RenderCtx
|
|
13
17
|
conservation: number[]
|
|
14
18
|
colWidth: number
|
|
15
19
|
trackHeight: number
|
|
16
20
|
offsetX: number
|
|
17
21
|
blockSize: number
|
|
18
22
|
}) {
|
|
19
|
-
const xStart =
|
|
20
|
-
|
|
23
|
+
const { xStart, xEnd } = visibleColRange({
|
|
24
|
+
offsetX,
|
|
25
|
+
blockWidth: blockSize,
|
|
26
|
+
colWidth,
|
|
27
|
+
})
|
|
21
28
|
|
|
22
29
|
ctx.fillStyle = 'gray'
|
|
23
30
|
for (let i = xStart; i < xEnd && i < conservation.length; i++) {
|
|
@@ -39,7 +46,7 @@ export function drawTextTrackContent({
|
|
|
39
46
|
offsetX,
|
|
40
47
|
blockSize,
|
|
41
48
|
}: {
|
|
42
|
-
ctx:
|
|
49
|
+
ctx: RenderCtx
|
|
43
50
|
data: string | undefined
|
|
44
51
|
colorScheme: Record<string, string>
|
|
45
52
|
contrastScheme: Record<string, string>
|
|
@@ -49,8 +56,11 @@ export function drawTextTrackContent({
|
|
|
49
56
|
offsetX: number
|
|
50
57
|
blockSize: number
|
|
51
58
|
}) {
|
|
52
|
-
const xStart =
|
|
53
|
-
|
|
59
|
+
const { xStart, xEnd } = visibleColRange({
|
|
60
|
+
offsetX,
|
|
61
|
+
blockWidth: blockSize,
|
|
62
|
+
colWidth,
|
|
63
|
+
})
|
|
54
64
|
const str = data?.slice(xStart, xEnd)
|
|
55
65
|
|
|
56
66
|
for (let i = 0; str && i < str.length; i++) {
|
|
@@ -78,7 +88,7 @@ export function renderConservationTrack({
|
|
|
78
88
|
highResScaleFactorOverride,
|
|
79
89
|
}: {
|
|
80
90
|
model: MsaViewModel
|
|
81
|
-
ctx:
|
|
91
|
+
ctx: RenderCtx
|
|
82
92
|
offsetX: number
|
|
83
93
|
offsetY: number
|
|
84
94
|
trackHeight: number
|
|
@@ -116,7 +126,7 @@ export function renderTextTrack({
|
|
|
116
126
|
highResScaleFactorOverride,
|
|
117
127
|
}: {
|
|
118
128
|
model: MsaViewModel
|
|
119
|
-
ctx:
|
|
129
|
+
ctx: RenderCtx
|
|
120
130
|
track: BasicTrack
|
|
121
131
|
offsetX: number
|
|
122
132
|
offsetY: number
|
|
@@ -143,7 +153,7 @@ export function renderTextTrack({
|
|
|
143
153
|
ctx.scale(k, k)
|
|
144
154
|
ctx.translate(-offsetX, offsetY)
|
|
145
155
|
ctx.textAlign = 'center'
|
|
146
|
-
ctx
|
|
156
|
+
setFontSize(ctx, fontSize)
|
|
147
157
|
|
|
148
158
|
drawTextTrackContent({
|
|
149
159
|
ctx,
|
|
@@ -169,7 +179,7 @@ export function renderAllTracks({
|
|
|
169
179
|
highResScaleFactorOverride,
|
|
170
180
|
}: {
|
|
171
181
|
model: MsaViewModel
|
|
172
|
-
ctx:
|
|
182
|
+
ctx: RenderCtx
|
|
173
183
|
offsetX: number
|
|
174
184
|
contrastScheme: Record<string, string>
|
|
175
185
|
blockSizeXOverride?: number
|
|
@@ -43,7 +43,9 @@ const TreeCanvas = observer(function ({ model }: { model: MsaViewModel }) {
|
|
|
43
43
|
ctx.resetTransform()
|
|
44
44
|
ctx.clearRect(0, 0, w, h)
|
|
45
45
|
|
|
46
|
-
const leafByName = new Map(
|
|
46
|
+
const leafByName = new Map(
|
|
47
|
+
leaves.map(leaf => [leaf.data.name, leaf]),
|
|
48
|
+
)
|
|
47
49
|
const fillRow = (name: string) => {
|
|
48
50
|
const leaf = leafByName.get(name)
|
|
49
51
|
if (leaf) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import { useTheme } from '@mui/material'
|
|
4
4
|
import Flatbush from 'flatbush'
|
|
@@ -62,7 +62,6 @@ class ClickMapIndex {
|
|
|
62
62
|
finish() {
|
|
63
63
|
if (this.entries.length === 0) {
|
|
64
64
|
this.flatbush = null
|
|
65
|
-
return
|
|
66
65
|
} else {
|
|
67
66
|
this.flatbush = new Flatbush(this.entries.length)
|
|
68
67
|
for (const entry of this.entries) {
|
|
@@ -114,15 +113,6 @@ const TreeCanvasBlock = observer(function ({
|
|
|
114
113
|
const w2 = width * highResScaleFactor
|
|
115
114
|
const h2 = height * highResScaleFactor
|
|
116
115
|
|
|
117
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
118
|
-
const vref = useCallback(
|
|
119
|
-
(arg: HTMLCanvasElement) => {
|
|
120
|
-
model.incrementRef()
|
|
121
|
-
ref.current = arg
|
|
122
|
-
},
|
|
123
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
124
|
-
[model, height, width],
|
|
125
|
-
)
|
|
126
116
|
useEffect(() => {
|
|
127
117
|
const ctx = ref.current?.getContext('2d')
|
|
128
118
|
if (!ctx) {
|
|
@@ -289,7 +279,7 @@ const TreeCanvasBlock = observer(function ({
|
|
|
289
279
|
model.setHoveredTreeNode(undefined)
|
|
290
280
|
model.setMousePos(undefined, undefined)
|
|
291
281
|
}}
|
|
292
|
-
ref={
|
|
282
|
+
ref={ref}
|
|
293
283
|
/>
|
|
294
284
|
<canvas
|
|
295
285
|
style={{
|