react-msaview 3.1.5 → 3.1.7
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/bundle/index.js +30 -39
- package/dist/DataModel.d.ts +34 -0
- package/dist/DataModel.js +46 -0
- package/dist/DataModel.js.map +1 -0
- package/dist/SelectedStructuresMixin.d.ts +46 -0
- package/dist/SelectedStructuresMixin.js +52 -0
- package/dist/SelectedStructuresMixin.js.map +1 -0
- package/dist/components/MSAPanel/MSABlock.js +32 -16
- package/dist/components/MSAPanel/MSABlock.js.map +1 -1
- package/dist/components/MSAPanel/renderMSAMouseover.js +14 -4
- package/dist/components/MSAPanel/renderMSAMouseover.js.map +1 -1
- package/dist/components/TreePanel/TreeNodeMenu.js +65 -55
- package/dist/components/TreePanel/TreeNodeMenu.js.map +1 -1
- package/dist/components/TreePanel/renderTreeCanvas.js +4 -3
- package/dist/components/TreePanel/renderTreeCanvas.js.map +1 -1
- package/dist/components/dialogs/SettingsDialog.js +41 -31
- package/dist/components/dialogs/SettingsDialog.js.map +1 -1
- package/dist/measureTextCanvas.d.ts +1 -1
- package/dist/measureTextCanvas.js +1 -1
- package/dist/measureTextCanvas.js.map +1 -1
- package/dist/model.d.ts +113 -108
- package/dist/model.js +61 -93
- package/dist/model.js.map +1 -1
- package/dist/util.d.ts +0 -1
- package/dist/util.js +0 -7
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -2
- package/src/DataModel.ts +46 -0
- package/src/SelectedStructuresMixin.ts +59 -0
- package/src/components/MSAPanel/MSABlock.tsx +33 -18
- package/src/components/MSAPanel/renderMSAMouseover.ts +16 -3
- package/src/components/TreePanel/TreeNodeMenu.tsx +93 -84
- package/src/components/TreePanel/renderTreeCanvas.ts +3 -2
- package/src/components/dialogs/SettingsDialog.tsx +128 -116
- package/src/measureTextCanvas.ts +1 -1
- package/src/model.ts +72 -109
- package/src/util.ts +0 -11
- package/src/version.ts +1 -1
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { MsaViewModel } from '../../model'
|
|
2
2
|
|
|
3
|
+
const hoverColor = 'rgba(0,0,0,0.15)'
|
|
4
|
+
const highlightColor = 'rgba(128,128,0,0.2)'
|
|
5
|
+
|
|
3
6
|
export function renderMouseover({
|
|
4
7
|
ctx,
|
|
5
8
|
model,
|
|
@@ -18,19 +21,29 @@ export function renderMouseover({
|
|
|
18
21
|
mouseRow,
|
|
19
22
|
// @ts-expect-error
|
|
20
23
|
mouseCol2,
|
|
24
|
+
mouseClickRow,
|
|
25
|
+
mouseClickCol,
|
|
21
26
|
} = model
|
|
22
27
|
ctx.resetTransform()
|
|
23
28
|
ctx.clearRect(0, 0, width, height)
|
|
24
29
|
if (mouseCol !== undefined) {
|
|
25
|
-
ctx.fillStyle =
|
|
30
|
+
ctx.fillStyle = hoverColor
|
|
26
31
|
ctx.fillRect((mouseCol - 1) * colWidth + scrollX, 0, colWidth, height)
|
|
27
32
|
}
|
|
28
33
|
if (mouseRow !== undefined) {
|
|
29
|
-
ctx.fillStyle =
|
|
34
|
+
ctx.fillStyle = hoverColor
|
|
30
35
|
ctx.fillRect(0, mouseRow * rowHeight + scrollY, width, rowHeight)
|
|
31
36
|
}
|
|
37
|
+
if (mouseClickCol !== undefined) {
|
|
38
|
+
ctx.fillStyle = highlightColor
|
|
39
|
+
ctx.fillRect((mouseClickCol - 1) * colWidth + scrollX, 0, colWidth, height)
|
|
40
|
+
}
|
|
41
|
+
if (mouseClickRow !== undefined) {
|
|
42
|
+
ctx.fillStyle = highlightColor
|
|
43
|
+
ctx.fillRect(0, mouseClickRow * rowHeight + scrollY, width, rowHeight)
|
|
44
|
+
}
|
|
32
45
|
if (mouseCol2 !== undefined) {
|
|
33
|
-
ctx.fillStyle =
|
|
46
|
+
ctx.fillStyle = highlightColor
|
|
34
47
|
ctx.fillRect((mouseCol2 - 1) * colWidth + scrollX, 0, colWidth, height)
|
|
35
48
|
}
|
|
36
49
|
}
|
|
@@ -5,6 +5,7 @@ import { observer } from 'mobx-react'
|
|
|
5
5
|
// locals
|
|
6
6
|
import { MsaViewModel } from '../../model'
|
|
7
7
|
|
|
8
|
+
// lazies
|
|
8
9
|
const TreeNodeInfoDialog = lazy(() => import('./dialogs/TreeNodeInfoDialog'))
|
|
9
10
|
|
|
10
11
|
const TreeMenu = observer(function ({
|
|
@@ -16,104 +17,112 @@ const TreeMenu = observer(function ({
|
|
|
16
17
|
model: MsaViewModel
|
|
17
18
|
onClose: () => void
|
|
18
19
|
}) {
|
|
19
|
-
const { structures } = model
|
|
20
|
+
const { selectedStructures, collapsed, collapsed2, structures } = model
|
|
20
21
|
const nodeDetails = node ? model.getRowData(node.name) : undefined
|
|
21
22
|
|
|
22
23
|
return (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
<Menu
|
|
25
|
+
anchorReference="anchorPosition"
|
|
26
|
+
anchorPosition={{
|
|
27
|
+
top: node.y,
|
|
28
|
+
left: node.x,
|
|
29
|
+
}}
|
|
30
|
+
transitionDuration={0}
|
|
31
|
+
keepMounted
|
|
32
|
+
open={Boolean(node)}
|
|
33
|
+
onClose={onClose}
|
|
34
|
+
>
|
|
35
|
+
<MenuItem dense disabled>
|
|
36
|
+
{node.name}
|
|
37
|
+
</MenuItem>
|
|
38
|
+
|
|
39
|
+
<MenuItem
|
|
40
|
+
dense
|
|
41
|
+
onClick={() => {
|
|
42
|
+
model.queueDialog(onClose => [
|
|
43
|
+
TreeNodeInfoDialog,
|
|
44
|
+
{
|
|
45
|
+
info: model.getRowData(node.name),
|
|
46
|
+
model,
|
|
47
|
+
nodeName: node.name,
|
|
48
|
+
onClose,
|
|
49
|
+
},
|
|
50
|
+
])
|
|
51
|
+
onClose()
|
|
29
52
|
}}
|
|
30
|
-
transitionDuration={0}
|
|
31
|
-
keepMounted
|
|
32
|
-
open={Boolean(node)}
|
|
33
|
-
onClose={onClose}
|
|
34
53
|
>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<MenuItem
|
|
57
|
-
dense
|
|
58
|
-
onClick={() => {
|
|
59
|
-
model.hideNode(node.id)
|
|
60
|
-
onClose()
|
|
61
|
-
}}
|
|
62
|
-
>
|
|
63
|
-
Hide node
|
|
64
|
-
</MenuItem>
|
|
65
|
-
|
|
66
|
-
{structures[node.name]?.map(entry => {
|
|
67
|
-
return !model.selectedStructures.some(n => n.id === node.name) ? (
|
|
68
|
-
<MenuItem
|
|
69
|
-
key={JSON.stringify(entry)}
|
|
70
|
-
dense
|
|
71
|
-
onClick={() => {
|
|
72
|
-
model.addStructureToSelection({
|
|
73
|
-
structure: entry,
|
|
74
|
-
id: node.name,
|
|
75
|
-
})
|
|
76
|
-
onClose()
|
|
77
|
-
}}
|
|
78
|
-
>
|
|
79
|
-
Add PDB to selection ({entry.pdb})
|
|
80
|
-
</MenuItem>
|
|
81
|
-
) : (
|
|
82
|
-
<MenuItem
|
|
83
|
-
key={JSON.stringify(entry)}
|
|
84
|
-
dense
|
|
85
|
-
onClick={() => {
|
|
86
|
-
model.removeStructureFromSelection({
|
|
87
|
-
structure: entry,
|
|
88
|
-
id: node.name,
|
|
89
|
-
})
|
|
90
|
-
onClose()
|
|
91
|
-
}}
|
|
92
|
-
>
|
|
93
|
-
Remove PDB from selection ({entry.pdb})
|
|
94
|
-
</MenuItem>
|
|
95
|
-
)
|
|
96
|
-
})}
|
|
54
|
+
More info...
|
|
55
|
+
</MenuItem>
|
|
56
|
+
<MenuItem
|
|
57
|
+
dense
|
|
58
|
+
onClick={() => {
|
|
59
|
+
if (collapsed.includes(node.id)) {
|
|
60
|
+
model.toggleCollapsed(node.id)
|
|
61
|
+
} else {
|
|
62
|
+
if (node.id.endsWith('-leafnode')) {
|
|
63
|
+
model.toggleCollapsed2(`${node.id}`)
|
|
64
|
+
} else {
|
|
65
|
+
model.toggleCollapsed2(`${node.id}-leafnode`)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
onClose()
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{collapsed.includes(node.id) || collapsed2.includes(node.id)
|
|
72
|
+
? 'Show node'
|
|
73
|
+
: 'Hide node'}
|
|
74
|
+
</MenuItem>
|
|
97
75
|
|
|
98
|
-
|
|
99
|
-
|
|
76
|
+
{structures[node.name]?.map(entry =>
|
|
77
|
+
!selectedStructures.some(n => n.id === node.name) ? (
|
|
78
|
+
<MenuItem
|
|
79
|
+
key={JSON.stringify(entry)}
|
|
80
|
+
dense
|
|
81
|
+
onClick={() => {
|
|
82
|
+
model.addStructureToSelection({
|
|
83
|
+
structure: entry,
|
|
84
|
+
id: node.name,
|
|
85
|
+
})
|
|
86
|
+
onClose()
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
Add PDB to selection ({entry.pdb})
|
|
90
|
+
</MenuItem>
|
|
91
|
+
) : (
|
|
100
92
|
<MenuItem
|
|
93
|
+
key={JSON.stringify(entry)}
|
|
101
94
|
dense
|
|
102
|
-
key={accession}
|
|
103
95
|
onClick={() => {
|
|
104
|
-
model.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
accession,
|
|
96
|
+
model.removeStructureFromSelection({
|
|
97
|
+
structure: entry,
|
|
98
|
+
id: node.name,
|
|
108
99
|
})
|
|
109
100
|
onClose()
|
|
110
101
|
}}
|
|
111
102
|
>
|
|
112
|
-
|
|
103
|
+
Remove PDB from selection ({entry.pdb})
|
|
113
104
|
</MenuItem>
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
|
|
105
|
+
),
|
|
106
|
+
)}
|
|
107
|
+
|
|
108
|
+
{// @ts-expect-error
|
|
109
|
+
nodeDetails?.data.accession?.map(accession => (
|
|
110
|
+
<MenuItem
|
|
111
|
+
dense
|
|
112
|
+
key={accession}
|
|
113
|
+
onClick={() => {
|
|
114
|
+
model.addUniprotTrack({
|
|
115
|
+
// @ts-expect-error
|
|
116
|
+
name: nodeDetails?.data.name,
|
|
117
|
+
accession,
|
|
118
|
+
})
|
|
119
|
+
onClose()
|
|
120
|
+
}}
|
|
121
|
+
>
|
|
122
|
+
Open UniProt track ({accession})
|
|
123
|
+
</MenuItem>
|
|
124
|
+
))}
|
|
125
|
+
</Menu>
|
|
117
126
|
)
|
|
118
127
|
})
|
|
119
128
|
|
|
@@ -90,6 +90,7 @@ export function renderNodeBubbles({
|
|
|
90
90
|
} = node
|
|
91
91
|
const { branchset, id = '', name = '' } = data
|
|
92
92
|
if (
|
|
93
|
+
!id.endsWith('-leafnode') &&
|
|
93
94
|
branchset.length &&
|
|
94
95
|
y > offsetY - extendBounds &&
|
|
95
96
|
y < offsetY + by + extendBounds
|
|
@@ -195,8 +196,8 @@ export function renderTreeLabels({
|
|
|
195
196
|
}
|
|
196
197
|
ctx.fillText(displayName, offset, yp)
|
|
197
198
|
clickMap?.insert({
|
|
198
|
-
minX: treeAreaWidth - width
|
|
199
|
-
maxX: treeAreaWidth
|
|
199
|
+
minX: treeAreaWidth - width,
|
|
200
|
+
maxX: treeAreaWidth,
|
|
200
201
|
minY: yp - height,
|
|
201
202
|
maxY: yp,
|
|
202
203
|
name,
|
|
@@ -35,140 +35,152 @@ function FormControlLabel2(rest: FormControlLabelProps) {
|
|
|
35
35
|
)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function Checkbox2({
|
|
39
|
+
checked,
|
|
40
|
+
label,
|
|
41
|
+
onChange,
|
|
42
|
+
}: {
|
|
43
|
+
checked: boolean
|
|
44
|
+
label: string
|
|
45
|
+
onChange: () => void
|
|
46
|
+
}) {
|
|
47
|
+
return (
|
|
48
|
+
<FormControlLabel2
|
|
49
|
+
control={<Checkbox checked={checked} onChange={onChange} />}
|
|
50
|
+
label={label}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
38
55
|
const SettingsContent = observer(function ({ model }: { model: MsaViewModel }) {
|
|
56
|
+
return (
|
|
57
|
+
<>
|
|
58
|
+
<TreeSettings model={model} />
|
|
59
|
+
<MSASettings model={model} />
|
|
60
|
+
</>
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const TreeSettings = observer(function TreeSettings({
|
|
65
|
+
model,
|
|
66
|
+
}: {
|
|
67
|
+
model: MsaViewModel
|
|
68
|
+
}) {
|
|
39
69
|
const { classes } = useStyles()
|
|
40
70
|
const {
|
|
41
|
-
bgColor,
|
|
42
|
-
colWidth,
|
|
43
|
-
colorSchemeName,
|
|
44
71
|
drawTree,
|
|
45
72
|
drawNodeBubbles,
|
|
46
73
|
labelsAlignRight,
|
|
47
74
|
noTree,
|
|
48
|
-
rowHeight,
|
|
49
75
|
showBranchLen,
|
|
50
76
|
treeWidthMatchesArea,
|
|
51
77
|
treeWidth,
|
|
52
78
|
} = model
|
|
79
|
+
|
|
53
80
|
return (
|
|
54
|
-
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
checked={showBranchLen}
|
|
62
|
-
onChange={() => model.setShowBranchLen(!showBranchLen)}
|
|
63
|
-
/>
|
|
64
|
-
}
|
|
65
|
-
label="Show branch length?"
|
|
66
|
-
/>
|
|
81
|
+
<div>
|
|
82
|
+
<h1>Tree options</h1>
|
|
83
|
+
<Checkbox2
|
|
84
|
+
checked={showBranchLen}
|
|
85
|
+
onChange={() => model.setShowBranchLen(!showBranchLen)}
|
|
86
|
+
label="Show branch length?"
|
|
87
|
+
/>
|
|
67
88
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
control={
|
|
79
|
-
<Checkbox
|
|
80
|
-
checked={drawTree}
|
|
81
|
-
onChange={() => model.setDrawTree(!drawTree)}
|
|
82
|
-
/>
|
|
83
|
-
}
|
|
84
|
-
label="Show tree?"
|
|
85
|
-
/>
|
|
89
|
+
<Checkbox2
|
|
90
|
+
checked={drawNodeBubbles}
|
|
91
|
+
onChange={() => model.setDrawNodeBubbles(!drawNodeBubbles)}
|
|
92
|
+
label="Draw clickable bubbles on tree branches?"
|
|
93
|
+
/>
|
|
94
|
+
<Checkbox2
|
|
95
|
+
checked={drawTree}
|
|
96
|
+
onChange={() => model.setDrawTree(!drawTree)}
|
|
97
|
+
label="Show tree?"
|
|
98
|
+
/>
|
|
86
99
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<Checkbox
|
|
101
|
-
checked={treeWidthMatchesArea}
|
|
102
|
-
onChange={() =>
|
|
103
|
-
model.setTreeWidthMatchesArea(!treeWidthMatchesArea)
|
|
104
|
-
}
|
|
105
|
-
/>
|
|
106
|
-
}
|
|
107
|
-
label="Make tree width fit to tree area?"
|
|
108
|
-
/>
|
|
109
|
-
{!treeWidthMatchesArea ? (
|
|
110
|
-
<div className={classes.flex}>
|
|
111
|
-
<Typography>Tree width ({treeWidth}px)</Typography>
|
|
112
|
-
<Slider
|
|
113
|
-
className={classes.field}
|
|
114
|
-
min={50}
|
|
115
|
-
max={600}
|
|
116
|
-
value={treeWidth}
|
|
117
|
-
onChange={(_, val) => model.setTreeWidth(val as number)}
|
|
118
|
-
/>
|
|
119
|
-
</div>
|
|
120
|
-
) : null}
|
|
121
|
-
</div>
|
|
122
|
-
) : null}
|
|
123
|
-
</div>
|
|
124
|
-
<div>
|
|
125
|
-
<h1>MSA options</h1>
|
|
126
|
-
|
|
127
|
-
<FormControlLabel2
|
|
128
|
-
control={
|
|
129
|
-
<Checkbox
|
|
130
|
-
checked={bgColor}
|
|
131
|
-
onChange={() => model.setBgColor(!bgColor)}
|
|
132
|
-
/>
|
|
133
|
-
}
|
|
134
|
-
label="Color background tiles of MSA?"
|
|
135
|
-
/>
|
|
136
|
-
|
|
137
|
-
<div className={classes.flex}>
|
|
138
|
-
<Typography>Column width ({colWidth}px)</Typography>
|
|
139
|
-
<Slider
|
|
140
|
-
className={classes.field}
|
|
141
|
-
min={1}
|
|
142
|
-
max={50}
|
|
143
|
-
value={colWidth}
|
|
144
|
-
onChange={(_, val) => model.setColWidth(val as number)}
|
|
145
|
-
/>
|
|
146
|
-
</div>
|
|
147
|
-
<div className={classes.flex}>
|
|
148
|
-
<Typography>Row height ({rowHeight}px)</Typography>
|
|
149
|
-
<Slider
|
|
150
|
-
className={classes.field}
|
|
151
|
-
min={1}
|
|
152
|
-
max={50}
|
|
153
|
-
value={rowHeight}
|
|
154
|
-
onChange={(_, val) => model.setRowHeight(val as number)}
|
|
100
|
+
<Checkbox2
|
|
101
|
+
checked={labelsAlignRight}
|
|
102
|
+
onChange={() => model.setLabelsAlignRight(!labelsAlignRight)}
|
|
103
|
+
label="Tree labels align right?"
|
|
104
|
+
/>
|
|
105
|
+
{!noTree ? (
|
|
106
|
+
<div>
|
|
107
|
+
<Checkbox2
|
|
108
|
+
checked={treeWidthMatchesArea}
|
|
109
|
+
onChange={() =>
|
|
110
|
+
model.setTreeWidthMatchesArea(!treeWidthMatchesArea)
|
|
111
|
+
}
|
|
112
|
+
label="Make tree width fit to tree area?"
|
|
155
113
|
/>
|
|
114
|
+
{!treeWidthMatchesArea ? (
|
|
115
|
+
<div className={classes.flex}>
|
|
116
|
+
<Typography>Tree width ({treeWidth}px)</Typography>
|
|
117
|
+
<Slider
|
|
118
|
+
className={classes.field}
|
|
119
|
+
min={50}
|
|
120
|
+
max={600}
|
|
121
|
+
value={treeWidth}
|
|
122
|
+
onChange={(_, val) => model.setTreeWidth(val as number)}
|
|
123
|
+
/>
|
|
124
|
+
</div>
|
|
125
|
+
) : null}
|
|
156
126
|
</div>
|
|
127
|
+
) : null}
|
|
128
|
+
</div>
|
|
129
|
+
)
|
|
130
|
+
})
|
|
157
131
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
132
|
+
const MSASettings = observer(function MSASettings({
|
|
133
|
+
model,
|
|
134
|
+
}: {
|
|
135
|
+
model: MsaViewModel
|
|
136
|
+
}) {
|
|
137
|
+
const { classes } = useStyles()
|
|
138
|
+
const { bgColor, colWidth, colorSchemeName, rowHeight } = model
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div>
|
|
142
|
+
<h1>MSA options</h1>
|
|
143
|
+
|
|
144
|
+
<Checkbox2
|
|
145
|
+
checked={bgColor}
|
|
146
|
+
onChange={() => model.setBgColor(!bgColor)}
|
|
147
|
+
label="Color background tiles of MSA?"
|
|
148
|
+
/>
|
|
149
|
+
|
|
150
|
+
<div className={classes.flex}>
|
|
151
|
+
<Typography>Column width ({colWidth}px)</Typography>
|
|
152
|
+
<Slider
|
|
153
|
+
className={classes.field}
|
|
154
|
+
min={1}
|
|
155
|
+
max={50}
|
|
156
|
+
value={colWidth}
|
|
157
|
+
onChange={(_, val) => model.setColWidth(val as number)}
|
|
158
|
+
/>
|
|
170
159
|
</div>
|
|
171
|
-
|
|
160
|
+
<div className={classes.flex}>
|
|
161
|
+
<Typography>Row height ({rowHeight}px)</Typography>
|
|
162
|
+
<Slider
|
|
163
|
+
className={classes.field}
|
|
164
|
+
min={1}
|
|
165
|
+
max={50}
|
|
166
|
+
value={rowHeight}
|
|
167
|
+
onChange={(_, val) => model.setRowHeight(val as number)}
|
|
168
|
+
/>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
<TextField
|
|
172
|
+
select
|
|
173
|
+
label="Color scheme"
|
|
174
|
+
value={colorSchemeName}
|
|
175
|
+
onChange={event => model.setColorSchemeName(event.target.value)}
|
|
176
|
+
>
|
|
177
|
+
{Object.keys(colorSchemes).map(option => (
|
|
178
|
+
<MenuItem key={option} value={option}>
|
|
179
|
+
{option}
|
|
180
|
+
</MenuItem>
|
|
181
|
+
))}
|
|
182
|
+
</TextField>
|
|
183
|
+
</div>
|
|
172
184
|
)
|
|
173
185
|
})
|
|
174
186
|
|
package/src/measureTextCanvas.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
let canvasHandle: HTMLCanvasElement | undefined
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export function measureTextCanvas(text: string, fontSize: number) {
|
|
4
4
|
if (!canvasHandle) {
|
|
5
5
|
canvasHandle = document.createElement('canvas')
|
|
6
6
|
}
|