@jbrowse/plugin-linear-genome-view 1.7.8 → 1.7.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/BaseLinearDisplay/components/BaseLinearDisplay.d.ts +1 -5
- package/dist/BaseLinearDisplay/components/BaseLinearDisplay.js +32 -120
- package/dist/BaseLinearDisplay/components/Tooltip.d.ts +8 -0
- package/dist/BaseLinearDisplay/components/Tooltip.js +125 -0
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +4 -4
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +3 -2
- package/dist/LinearBareDisplay/model.d.ts +1 -1
- package/dist/LinearBasicDisplay/model.d.ts +1 -2
- package/dist/LinearBasicDisplay/model.js +2 -2
- package/dist/LinearGenomeView/components/ExportSvgDialog.js +35 -25
- package/dist/LinearGenomeView/components/Header.d.ts +0 -1
- package/dist/LinearGenomeView/components/Header.js +3 -1
- package/dist/LinearGenomeView/components/HelpDialog.js +2 -3
- package/dist/LinearGenomeView/components/ImportForm.d.ts +0 -1
- package/dist/LinearGenomeView/components/ImportForm.js +40 -70
- package/dist/LinearGenomeView/components/LinearGenomeView.js +6 -2
- package/dist/LinearGenomeView/components/LinearGenomeView.test.js +2 -2
- package/dist/LinearGenomeView/components/OverviewScaleBar.d.ts +21 -5
- package/dist/LinearGenomeView/components/OverviewScaleBar.js +25 -18
- package/dist/LinearGenomeView/components/ScaleBar.d.ts +6 -2
- package/dist/LinearGenomeView/components/ScaleBar.js +8 -3
- package/dist/LinearGenomeView/components/SearchBox.js +36 -72
- package/dist/LinearGenomeView/components/SearchResultsDialog.d.ts +1 -1
- package/dist/LinearGenomeView/components/SearchResultsDialog.js +0 -1
- package/dist/LinearGenomeView/components/TrackLabel.js +25 -41
- package/dist/LinearGenomeView/components/util.d.ts +12 -0
- package/dist/LinearGenomeView/components/util.js +59 -0
- package/dist/LinearGenomeView/index.d.ts +7 -11
- package/dist/LinearGenomeView/index.js +60 -33
- package/dist/LinearGenomeView/index.test.js +22 -5
- package/dist/index.d.ts +3 -3
- package/dist/index.js +22 -11
- package/package.json +3 -2
- package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +4 -89
- package/src/BaseLinearDisplay/components/Tooltip.tsx +97 -0
- package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +11 -4
- package/src/LinearBasicDisplay/model.ts +2 -4
- package/src/LinearGenomeView/components/ExportSvgDialog.tsx +24 -11
- package/src/LinearGenomeView/components/Header.tsx +2 -1
- package/src/LinearGenomeView/components/HelpDialog.tsx +5 -4
- package/src/LinearGenomeView/components/ImportForm.tsx +18 -25
- package/src/LinearGenomeView/components/LinearGenomeView.test.js +2 -2
- package/src/LinearGenomeView/components/LinearGenomeView.tsx +16 -10
- package/src/LinearGenomeView/components/OverviewScaleBar.tsx +42 -34
- package/src/LinearGenomeView/components/ScaleBar.tsx +6 -9
- package/src/LinearGenomeView/components/SearchBox.tsx +18 -29
- package/src/LinearGenomeView/components/SearchResultsDialog.tsx +0 -1
- package/src/LinearGenomeView/components/TrackLabel.tsx +25 -28
- package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +4 -21
- package/src/LinearGenomeView/components/util.ts +43 -0
- package/src/LinearGenomeView/index.test.ts +20 -5
- package/src/LinearGenomeView/index.tsx +56 -27
- package/src/index.ts +35 -30
|
@@ -82,7 +82,7 @@ function initialize() {
|
|
|
82
82
|
}).actions(function (self) {
|
|
83
83
|
return {
|
|
84
84
|
isValidRefName: function isValidRefName(str) {
|
|
85
|
-
return
|
|
85
|
+
return str === 'ctgA' || str === 'ctgB';
|
|
86
86
|
},
|
|
87
87
|
get: function get(str) {
|
|
88
88
|
return self.assemblies.get(str);
|
|
@@ -1163,8 +1163,25 @@ test('multi region', function () {
|
|
|
1163
1163
|
model.setDisplayedRegions(_volvoxDisplayedRegions.default.slice(0, 1));
|
|
1164
1164
|
model.navToLocString('ctgA ctgB');
|
|
1165
1165
|
expect(model.displayedRegions[0].refName).toBe('ctgA');
|
|
1166
|
-
expect(model.displayedRegions[1].refName).toBe('ctgB');
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1166
|
+
expect(model.displayedRegions[1].refName).toBe('ctgB');
|
|
1167
|
+
});
|
|
1168
|
+
test('space separated locstring', function () {
|
|
1169
|
+
var _initialize15 = initialize(),
|
|
1170
|
+
Session = _initialize15.Session,
|
|
1171
|
+
LinearGenomeModel = _initialize15.LinearGenomeModel;
|
|
1172
|
+
|
|
1173
|
+
var model = Session.create({
|
|
1174
|
+
configuration: {}
|
|
1175
|
+
}).setView(LinearGenomeModel.create({
|
|
1176
|
+
type: 'LinearGenomeView',
|
|
1177
|
+
tracks: [{
|
|
1178
|
+
name: 'foo track',
|
|
1179
|
+
type: 'BasicTrack'
|
|
1180
|
+
}]
|
|
1181
|
+
}));
|
|
1182
|
+
model.setWidth(800);
|
|
1183
|
+
model.setDisplayedRegions(_volvoxDisplayedRegions.default.slice(0, 1));
|
|
1184
|
+
model.navToLocString('ctgA 0 100');
|
|
1185
|
+
expect(model.offsetPx).toBe(0);
|
|
1186
|
+
expect(model.bpPerPx).toBe(0.125);
|
|
1170
1187
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -124,7 +124,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
|
|
|
124
124
|
estimatedRegionStatsP: Promise<import("@jbrowse/core/data_adapters/BaseAdapter").Stats> | undefined;
|
|
125
125
|
estimatedRegionStats: import("@jbrowse/core/data_adapters/BaseAdapter").Stats | undefined;
|
|
126
126
|
} & {
|
|
127
|
-
readonly blockType: "
|
|
127
|
+
readonly blockType: "dynamicBlocks" | "staticBlocks";
|
|
128
128
|
readonly blockDefinitions: import("@jbrowse/core/util/blockTypes").BlockSet;
|
|
129
129
|
} & {
|
|
130
130
|
readonly renderDelay: number;
|
|
@@ -300,7 +300,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
|
|
|
300
300
|
estimatedRegionStatsP: Promise<import("@jbrowse/core/data_adapters/BaseAdapter").Stats> | undefined;
|
|
301
301
|
estimatedRegionStats: import("@jbrowse/core/data_adapters/BaseAdapter").Stats | undefined;
|
|
302
302
|
} & {
|
|
303
|
-
readonly blockType: "
|
|
303
|
+
readonly blockType: "dynamicBlocks" | "staticBlocks";
|
|
304
304
|
readonly blockDefinitions: import("@jbrowse/core/util/blockTypes").BlockSet;
|
|
305
305
|
} & {
|
|
306
306
|
readonly renderDelay: number;
|
|
@@ -486,7 +486,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
|
|
|
486
486
|
estimatedRegionStatsP: Promise<import("@jbrowse/core/data_adapters/BaseAdapter").Stats> | undefined;
|
|
487
487
|
estimatedRegionStats: import("@jbrowse/core/data_adapters/BaseAdapter").Stats | undefined;
|
|
488
488
|
} & {
|
|
489
|
-
readonly blockType: "
|
|
489
|
+
readonly blockType: "dynamicBlocks" | "staticBlocks";
|
|
490
490
|
readonly blockDefinitions: import("@jbrowse/core/util/blockTypes").BlockSet;
|
|
491
491
|
} & {
|
|
492
492
|
readonly renderDelay: number;
|
package/dist/index.js
CHANGED
|
@@ -211,36 +211,37 @@ var LinearGenomeViewPlugin = /*#__PURE__*/function (_Plugin) {
|
|
|
211
211
|
switch (_context.prev = _context.next) {
|
|
212
212
|
case 0:
|
|
213
213
|
session = _ref.session, assembly = _ref.assembly, loc = _ref.loc, _ref$tracks = _ref.tracks, tracks = _ref$tracks === void 0 ? [] : _ref$tracks;
|
|
214
|
+
_context.prev = 1;
|
|
214
215
|
assemblyManager = session.assemblyManager;
|
|
215
216
|
view = session.addView('LinearGenomeView', {});
|
|
216
|
-
_context.next =
|
|
217
|
+
_context.next = 6;
|
|
217
218
|
return (0, _mobx.when)(function () {
|
|
218
219
|
return !!view.volatileWidth;
|
|
219
220
|
});
|
|
220
221
|
|
|
221
|
-
case
|
|
222
|
+
case 6:
|
|
222
223
|
if (assembly) {
|
|
223
|
-
_context.next =
|
|
224
|
+
_context.next = 8;
|
|
224
225
|
break;
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
throw new Error('No assembly provided when launching linear genome view');
|
|
228
229
|
|
|
229
|
-
case
|
|
230
|
-
_context.next =
|
|
230
|
+
case 8:
|
|
231
|
+
_context.next = 10;
|
|
231
232
|
return assemblyManager.waitForAssembly(assembly);
|
|
232
233
|
|
|
233
|
-
case
|
|
234
|
+
case 10:
|
|
234
235
|
asm = _context.sent;
|
|
235
236
|
|
|
236
237
|
if (asm) {
|
|
237
|
-
_context.next =
|
|
238
|
+
_context.next = 13;
|
|
238
239
|
break;
|
|
239
240
|
}
|
|
240
241
|
|
|
241
242
|
throw new Error("Assembly \"".concat(assembly, "\" not found when launching linear genome view"));
|
|
242
243
|
|
|
243
|
-
case
|
|
244
|
+
case 13:
|
|
244
245
|
view.navToLocString(loc, assembly);
|
|
245
246
|
idsNotFound = [];
|
|
246
247
|
tracks.forEach(function (track) {
|
|
@@ -256,18 +257,28 @@ var LinearGenomeViewPlugin = /*#__PURE__*/function (_Plugin) {
|
|
|
256
257
|
});
|
|
257
258
|
|
|
258
259
|
if (!idsNotFound.length) {
|
|
259
|
-
_context.next =
|
|
260
|
+
_context.next = 18;
|
|
260
261
|
break;
|
|
261
262
|
}
|
|
262
263
|
|
|
263
264
|
throw new Error("Could not resolve identifiers: ".concat(idsNotFound.join(',')));
|
|
264
265
|
|
|
265
|
-
case
|
|
266
|
+
case 18:
|
|
267
|
+
_context.next = 24;
|
|
268
|
+
break;
|
|
269
|
+
|
|
270
|
+
case 20:
|
|
271
|
+
_context.prev = 20;
|
|
272
|
+
_context.t0 = _context["catch"](1);
|
|
273
|
+
session.notify("".concat(_context.t0), 'error');
|
|
274
|
+
throw _context.t0;
|
|
275
|
+
|
|
276
|
+
case 24:
|
|
266
277
|
case "end":
|
|
267
278
|
return _context.stop();
|
|
268
279
|
}
|
|
269
280
|
}
|
|
270
|
-
}, _callee);
|
|
281
|
+
}, _callee, null, [[1, 20]]);
|
|
271
282
|
}));
|
|
272
283
|
|
|
273
284
|
return function (_x) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-linear-genome-view",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.11",
|
|
4
4
|
"description": "JBrowse 2 linear genome view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"clsx": "^1.0.4",
|
|
41
41
|
"copy-to-clipboard": "^3.3.1",
|
|
42
42
|
"file-saver": "^2.0.0",
|
|
43
|
+
"material-ui-popup-state": "^1.9.3",
|
|
43
44
|
"normalize-wheel": "^1.0.1",
|
|
44
45
|
"react-popper": "^2.0.0"
|
|
45
46
|
},
|
|
@@ -57,5 +58,5 @@
|
|
|
57
58
|
"publishConfig": {
|
|
58
59
|
"access": "public"
|
|
59
60
|
},
|
|
60
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "5c21beb48a21f08b0091d293f09ac99174c48f77"
|
|
61
62
|
}
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
import React, { useState, useRef
|
|
1
|
+
import React, { useState, useRef } from 'react'
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
|
-
import {
|
|
3
|
+
import { useTheme, makeStyles } from '@material-ui/core'
|
|
4
4
|
import { getConf } from '@jbrowse/core/configuration'
|
|
5
5
|
import { Menu } from '@jbrowse/core/ui'
|
|
6
|
-
import { usePopper } from 'react-popper'
|
|
7
6
|
|
|
8
7
|
// locals
|
|
8
|
+
import Tooltip from './Tooltip'
|
|
9
9
|
import LinearBlocks from './LinearBlocks'
|
|
10
10
|
import { BaseLinearDisplayModel } from '../models/BaseLinearDisplayModel'
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
return Math.round(value * 1e5) / 1e5
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const useStyles = makeStyles(theme => ({
|
|
12
|
+
const useStyles = makeStyles({
|
|
17
13
|
display: {
|
|
18
14
|
position: 'relative',
|
|
19
15
|
whiteSpace: 'nowrap',
|
|
@@ -21,89 +17,8 @@ const useStyles = makeStyles(theme => ({
|
|
|
21
17
|
width: '100%',
|
|
22
18
|
minHeight: '100%',
|
|
23
19
|
},
|
|
24
|
-
|
|
25
|
-
// these styles come from
|
|
26
|
-
// https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js
|
|
27
|
-
tooltip: {
|
|
28
|
-
pointerEvents: 'none',
|
|
29
|
-
backgroundColor: alpha(theme.palette.grey[700], 0.9),
|
|
30
|
-
borderRadius: theme.shape.borderRadius,
|
|
31
|
-
color: theme.palette.common.white,
|
|
32
|
-
fontFamily: theme.typography.fontFamily,
|
|
33
|
-
padding: '4px 8px',
|
|
34
|
-
fontSize: theme.typography.pxToRem(12),
|
|
35
|
-
lineHeight: `${round(14 / 10)}em`,
|
|
36
|
-
maxWidth: 300,
|
|
37
|
-
wordWrap: 'break-word',
|
|
38
|
-
},
|
|
39
|
-
}))
|
|
40
|
-
|
|
41
|
-
const TooltipContents = React.forwardRef<
|
|
42
|
-
HTMLDivElement,
|
|
43
|
-
{ message: React.ReactNode | string }
|
|
44
|
-
>(({ message }: { message: React.ReactNode | string }, ref) => {
|
|
45
|
-
return <div ref={ref}>{message}</div>
|
|
46
20
|
})
|
|
47
21
|
|
|
48
|
-
const Tooltip = observer(
|
|
49
|
-
({
|
|
50
|
-
model,
|
|
51
|
-
clientMouseCoord,
|
|
52
|
-
}: {
|
|
53
|
-
model: BaseLinearDisplayModel
|
|
54
|
-
clientMouseCoord: Coord
|
|
55
|
-
}) => {
|
|
56
|
-
const classes = useStyles()
|
|
57
|
-
const { featureUnderMouse } = model
|
|
58
|
-
const [width, setWidth] = useState(0)
|
|
59
|
-
const [popperElt, setPopperElt] = useState<HTMLDivElement | null>(null)
|
|
60
|
-
|
|
61
|
-
// must be memoized a la https://github.com/popperjs/react-popper/issues/391
|
|
62
|
-
const virtElement = useMemo(
|
|
63
|
-
() => ({
|
|
64
|
-
getBoundingClientRect: () => {
|
|
65
|
-
const x = clientMouseCoord[0] + width / 2 + 20
|
|
66
|
-
const y = clientMouseCoord[1]
|
|
67
|
-
return {
|
|
68
|
-
top: y,
|
|
69
|
-
left: x,
|
|
70
|
-
bottom: y,
|
|
71
|
-
right: x,
|
|
72
|
-
width: 0,
|
|
73
|
-
height: 0,
|
|
74
|
-
x,
|
|
75
|
-
y,
|
|
76
|
-
toJSON() {},
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
}),
|
|
80
|
-
[clientMouseCoord, width],
|
|
81
|
-
)
|
|
82
|
-
const { styles, attributes } = usePopper(virtElement, popperElt)
|
|
83
|
-
|
|
84
|
-
const contents = featureUnderMouse
|
|
85
|
-
? getConf(model, 'mouseover', { feature: featureUnderMouse })
|
|
86
|
-
: undefined
|
|
87
|
-
|
|
88
|
-
return featureUnderMouse && contents ? (
|
|
89
|
-
<Portal>
|
|
90
|
-
<div
|
|
91
|
-
ref={setPopperElt}
|
|
92
|
-
className={classes.tooltip}
|
|
93
|
-
// zIndex needed to go over widget drawer
|
|
94
|
-
style={{ ...styles.popper, zIndex: 100000 }}
|
|
95
|
-
{...attributes.popper}
|
|
96
|
-
>
|
|
97
|
-
<TooltipContents
|
|
98
|
-
ref={elt => setWidth(elt?.getBoundingClientRect().width || 0)}
|
|
99
|
-
message={contents}
|
|
100
|
-
/>
|
|
101
|
-
</div>
|
|
102
|
-
</Portal>
|
|
103
|
-
) : null
|
|
104
|
-
},
|
|
105
|
-
)
|
|
106
|
-
|
|
107
22
|
type Coord = [number, number]
|
|
108
23
|
const BaseLinearDisplay = observer(
|
|
109
24
|
(props: { model: BaseLinearDisplayModel; children?: React.ReactNode }) => {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React, { useState, useMemo } from 'react'
|
|
2
|
+
import { getConf } from '@jbrowse/core/configuration'
|
|
3
|
+
import { observer } from 'mobx-react'
|
|
4
|
+
import { Portal, alpha, makeStyles } from '@material-ui/core'
|
|
5
|
+
import { usePopper } from 'react-popper'
|
|
6
|
+
|
|
7
|
+
// locals
|
|
8
|
+
import { BaseLinearDisplayModel } from '../models/BaseLinearDisplayModel'
|
|
9
|
+
|
|
10
|
+
function round(value: number) {
|
|
11
|
+
return Math.round(value * 1e5) / 1e5
|
|
12
|
+
}
|
|
13
|
+
const useStyles = makeStyles(theme => ({
|
|
14
|
+
// these styles come from
|
|
15
|
+
// https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js
|
|
16
|
+
tooltip: {
|
|
17
|
+
pointerEvents: 'none',
|
|
18
|
+
backgroundColor: alpha(theme.palette.grey[700], 0.9),
|
|
19
|
+
borderRadius: theme.shape.borderRadius,
|
|
20
|
+
color: theme.palette.common.white,
|
|
21
|
+
fontFamily: theme.typography.fontFamily,
|
|
22
|
+
padding: '4px 8px',
|
|
23
|
+
fontSize: theme.typography.pxToRem(12),
|
|
24
|
+
lineHeight: `${round(14 / 10)}em`,
|
|
25
|
+
maxWidth: 300,
|
|
26
|
+
wordWrap: 'break-word',
|
|
27
|
+
},
|
|
28
|
+
}))
|
|
29
|
+
|
|
30
|
+
const TooltipContents = React.forwardRef<
|
|
31
|
+
HTMLDivElement,
|
|
32
|
+
{ message: React.ReactNode | string }
|
|
33
|
+
>(({ message }: { message: React.ReactNode | string }, ref) => {
|
|
34
|
+
return <div ref={ref}>{message}</div>
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
type Coord = [number, number]
|
|
38
|
+
const Tooltip = observer(
|
|
39
|
+
({
|
|
40
|
+
model,
|
|
41
|
+
clientMouseCoord,
|
|
42
|
+
}: {
|
|
43
|
+
model: BaseLinearDisplayModel
|
|
44
|
+
clientMouseCoord: Coord
|
|
45
|
+
}) => {
|
|
46
|
+
const classes = useStyles()
|
|
47
|
+
const { featureUnderMouse } = model
|
|
48
|
+
const [width, setWidth] = useState(0)
|
|
49
|
+
const [popperElt, setPopperElt] = useState<HTMLDivElement | null>(null)
|
|
50
|
+
|
|
51
|
+
// must be memoized a la https://github.com/popperjs/react-popper/issues/391
|
|
52
|
+
const virtElement = useMemo(
|
|
53
|
+
() => ({
|
|
54
|
+
getBoundingClientRect: () => {
|
|
55
|
+
const x = clientMouseCoord[0] + width / 2 + 20
|
|
56
|
+
const y = clientMouseCoord[1]
|
|
57
|
+
return {
|
|
58
|
+
top: y,
|
|
59
|
+
left: x,
|
|
60
|
+
bottom: y,
|
|
61
|
+
right: x,
|
|
62
|
+
width: 0,
|
|
63
|
+
height: 0,
|
|
64
|
+
x,
|
|
65
|
+
y,
|
|
66
|
+
toJSON() {},
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
}),
|
|
70
|
+
[clientMouseCoord, width],
|
|
71
|
+
)
|
|
72
|
+
const { styles, attributes } = usePopper(virtElement, popperElt)
|
|
73
|
+
|
|
74
|
+
const contents = featureUnderMouse
|
|
75
|
+
? getConf(model, 'mouseover', { feature: featureUnderMouse })
|
|
76
|
+
: undefined
|
|
77
|
+
|
|
78
|
+
return featureUnderMouse && contents ? (
|
|
79
|
+
<Portal>
|
|
80
|
+
<div
|
|
81
|
+
ref={setPopperElt}
|
|
82
|
+
className={classes.tooltip}
|
|
83
|
+
// zIndex needed to go over widget drawer
|
|
84
|
+
style={{ ...styles.popper, zIndex: 100000 }}
|
|
85
|
+
{...attributes.popper}
|
|
86
|
+
>
|
|
87
|
+
<TooltipContents
|
|
88
|
+
ref={elt => setWidth(elt?.getBoundingClientRect().width || 0)}
|
|
89
|
+
message={contents}
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
</Portal>
|
|
93
|
+
) : null
|
|
94
|
+
},
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
export default Tooltip
|
|
@@ -7,6 +7,7 @@ import { MenuItem } from '@jbrowse/core/ui'
|
|
|
7
7
|
import {
|
|
8
8
|
isAbortException,
|
|
9
9
|
getContainingView,
|
|
10
|
+
getContainingTrack,
|
|
10
11
|
getSession,
|
|
11
12
|
getViewParams,
|
|
12
13
|
isSelectionContainer,
|
|
@@ -333,8 +334,13 @@ export const BaseLinearDisplay = types
|
|
|
333
334
|
const featureWidget = session.addWidget(
|
|
334
335
|
'BaseFeatureWidget',
|
|
335
336
|
'baseFeature',
|
|
336
|
-
{
|
|
337
|
+
{
|
|
338
|
+
view: getContainingView(self),
|
|
339
|
+
track: getContainingTrack(self),
|
|
340
|
+
featureData: feature.toJSON(),
|
|
341
|
+
},
|
|
337
342
|
)
|
|
343
|
+
|
|
338
344
|
session.showWidget(featureWidget)
|
|
339
345
|
}
|
|
340
346
|
if (isSelectionContainer(session)) {
|
|
@@ -551,7 +557,7 @@ export const BaseLinearDisplay = types
|
|
|
551
557
|
self.currBpPerPx !== view.bpPerPx || !self.estimatedRegionStats,
|
|
552
558
|
rpcDriverName: self.rpcDriverName,
|
|
553
559
|
displayModel: self,
|
|
554
|
-
onFeatureClick(_: unknown, featureId
|
|
560
|
+
onFeatureClick(_: unknown, featureId?: string) {
|
|
555
561
|
const f = featureId || self.featureIdUnderMouse
|
|
556
562
|
if (!f) {
|
|
557
563
|
self.clearFeatureSelection()
|
|
@@ -566,7 +572,7 @@ export const BaseLinearDisplay = types
|
|
|
566
572
|
self.clearFeatureSelection()
|
|
567
573
|
},
|
|
568
574
|
// similar to click but opens a menu with further options
|
|
569
|
-
onFeatureContextMenu(_: unknown, featureId
|
|
575
|
+
onFeatureContextMenu(_: unknown, featureId?: string) {
|
|
570
576
|
const f = featureId || self.featureIdUnderMouse
|
|
571
577
|
if (!f) {
|
|
572
578
|
self.clearFeatureSelection()
|
|
@@ -576,7 +582,7 @@ export const BaseLinearDisplay = types
|
|
|
576
582
|
}
|
|
577
583
|
},
|
|
578
584
|
|
|
579
|
-
onMouseMove(_: unknown, featureId
|
|
585
|
+
onMouseMove(_: unknown, featureId?: string) {
|
|
580
586
|
self.setFeatureIdUnderMouse(featureId)
|
|
581
587
|
},
|
|
582
588
|
|
|
@@ -642,6 +648,7 @@ export const BaseLinearDisplay = types
|
|
|
642
648
|
const { offsetPx } = roundedDynamicBlocks[index]
|
|
643
649
|
const offset = offsetPx - viewOffsetPx
|
|
644
650
|
const clipid = getId(id, index)
|
|
651
|
+
|
|
645
652
|
return (
|
|
646
653
|
<React.Fragment key={`frag-${index}`}>
|
|
647
654
|
<defs>
|
|
@@ -42,7 +42,7 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
|
|
|
42
42
|
get showDescriptions() {
|
|
43
43
|
return (
|
|
44
44
|
self.trackShowDescriptions ??
|
|
45
|
-
getConf(self, ['renderer', '
|
|
45
|
+
getConf(self, ['renderer', 'showDescriptions'])
|
|
46
46
|
)
|
|
47
47
|
},
|
|
48
48
|
|
|
@@ -116,9 +116,7 @@ const stateModelFactory = (configSchema: AnyConfigurationSchemaType) =>
|
|
|
116
116
|
icon: VisibilityIcon,
|
|
117
117
|
type: 'checkbox',
|
|
118
118
|
checked: self.showDescriptions,
|
|
119
|
-
onClick: () =>
|
|
120
|
-
self.toggleShowDescriptions()
|
|
121
|
-
},
|
|
119
|
+
onClick: () => self.toggleShowDescriptions(),
|
|
122
120
|
},
|
|
123
121
|
{
|
|
124
122
|
label: 'Display mode',
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
|
-
import { makeStyles } from '@material-ui/core/styles'
|
|
3
2
|
import {
|
|
4
3
|
Button,
|
|
4
|
+
Checkbox,
|
|
5
|
+
CircularProgress,
|
|
5
6
|
Dialog,
|
|
6
7
|
DialogActions,
|
|
7
8
|
DialogContent,
|
|
8
9
|
DialogTitle,
|
|
9
|
-
IconButton,
|
|
10
|
-
Checkbox,
|
|
11
10
|
FormControlLabel,
|
|
12
|
-
|
|
11
|
+
IconButton,
|
|
12
|
+
TextField,
|
|
13
13
|
Typography,
|
|
14
|
+
makeStyles,
|
|
14
15
|
} from '@material-ui/core'
|
|
16
|
+
import { ErrorMessage } from '@jbrowse/core/ui'
|
|
15
17
|
import CloseIcon from '@material-ui/icons/Close'
|
|
16
18
|
import { LinearGenomeViewModel as LGV } from '..'
|
|
17
19
|
|
|
@@ -24,6 +26,15 @@ const useStyles = makeStyles(theme => ({
|
|
|
24
26
|
},
|
|
25
27
|
}))
|
|
26
28
|
|
|
29
|
+
function LoadingMessage() {
|
|
30
|
+
return (
|
|
31
|
+
<div>
|
|
32
|
+
<CircularProgress size={20} style={{ marginRight: 20 }} />
|
|
33
|
+
<Typography display="inline">Creating SVG</Typography>
|
|
34
|
+
</div>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
export default function ExportSvgDlg({
|
|
28
39
|
model,
|
|
29
40
|
handleClose,
|
|
@@ -35,6 +46,7 @@ export default function ExportSvgDlg({
|
|
|
35
46
|
const offscreenCanvas = typeof OffscreenCanvas !== 'undefined'
|
|
36
47
|
const [rasterizeLayers, setRasterizeLayers] = useState(offscreenCanvas)
|
|
37
48
|
const [loading, setLoading] = useState(false)
|
|
49
|
+
const [filename, setFilename] = useState('jbrowse.svg')
|
|
38
50
|
const [error, setError] = useState<unknown>()
|
|
39
51
|
const classes = useStyles()
|
|
40
52
|
return (
|
|
@@ -47,13 +59,15 @@ export default function ExportSvgDlg({
|
|
|
47
59
|
</DialogTitle>
|
|
48
60
|
<DialogContent>
|
|
49
61
|
{error ? (
|
|
50
|
-
<
|
|
62
|
+
<ErrorMessage error={error} />
|
|
51
63
|
) : loading ? (
|
|
52
|
-
<
|
|
53
|
-
<CircularProgress size={20} style={{ marginRight: 20 }} />
|
|
54
|
-
<Typography display="inline">Creating SVG</Typography>
|
|
55
|
-
</div>
|
|
64
|
+
<LoadingMessage />
|
|
56
65
|
) : null}
|
|
66
|
+
<TextField
|
|
67
|
+
helperText="filename"
|
|
68
|
+
value={filename}
|
|
69
|
+
onChange={event => setFilename(event.target.value)}
|
|
70
|
+
/>
|
|
57
71
|
{offscreenCanvas ? (
|
|
58
72
|
<FormControlLabel
|
|
59
73
|
control={
|
|
@@ -87,12 +101,11 @@ export default function ExportSvgDlg({
|
|
|
87
101
|
setLoading(true)
|
|
88
102
|
setError(undefined)
|
|
89
103
|
try {
|
|
90
|
-
await model.exportSvg({ rasterizeLayers })
|
|
104
|
+
await model.exportSvg({ rasterizeLayers, filename })
|
|
91
105
|
handleClose()
|
|
92
106
|
} catch (e) {
|
|
93
107
|
console.error(e)
|
|
94
108
|
setError(e)
|
|
95
|
-
} finally {
|
|
96
109
|
setLoading(false)
|
|
97
110
|
}
|
|
98
111
|
}}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
makeStyles,
|
|
8
8
|
alpha,
|
|
9
9
|
} from '@material-ui/core'
|
|
10
|
+
import { getBpDisplayStr } from '@jbrowse/core/util'
|
|
10
11
|
import SearchBox from './SearchBox'
|
|
11
12
|
|
|
12
13
|
// icons
|
|
@@ -100,7 +101,7 @@ const RegionWidth = observer(({ model }: { model: LGV }) => {
|
|
|
100
101
|
const { coarseTotalBp } = model
|
|
101
102
|
return (
|
|
102
103
|
<Typography variant="body2" color="textSecondary" className={classes.bp}>
|
|
103
|
-
{
|
|
104
|
+
{getBpDisplayStr(coarseTotalBp)}
|
|
104
105
|
</Typography>
|
|
105
106
|
)
|
|
106
107
|
})
|
|
@@ -32,11 +32,8 @@ export default function HelpDialog({
|
|
|
32
32
|
Using the search box
|
|
33
33
|
{handleClose ? (
|
|
34
34
|
<IconButton
|
|
35
|
-
data-testid="close-resultsDialog"
|
|
36
35
|
className={classes.closeButton}
|
|
37
|
-
onClick={() =>
|
|
38
|
-
handleClose()
|
|
39
|
-
}}
|
|
36
|
+
onClick={() => handleClose()}
|
|
40
37
|
>
|
|
41
38
|
<CloseIcon />
|
|
42
39
|
</IconButton>
|
|
@@ -81,6 +78,10 @@ export default function HelpDialog({
|
|
|
81
78
|
<code>chr1:1-100[rev] chr2:1-100</code> - open up the first region
|
|
82
79
|
in the horizontally flipped orientation
|
|
83
80
|
</li>
|
|
81
|
+
<li>
|
|
82
|
+
<code>chr1 100 200</code> - use whitespace separated refname, start,
|
|
83
|
+
end
|
|
84
|
+
</li>
|
|
84
85
|
</ul>
|
|
85
86
|
</DialogContent>
|
|
86
87
|
<Divider />
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
Grid,
|
|
9
9
|
makeStyles,
|
|
10
10
|
} from '@material-ui/core'
|
|
11
|
-
import { SearchType } from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
12
11
|
import ErrorMessage from '@jbrowse/core/ui/ErrorMessage'
|
|
13
12
|
import BaseResult from '@jbrowse/core/TextSearch/BaseResults'
|
|
14
13
|
import AssemblySelector from '@jbrowse/core/ui/AssemblySelector'
|
|
@@ -16,6 +15,7 @@ import CloseIcon from '@material-ui/icons/Close'
|
|
|
16
15
|
|
|
17
16
|
// locals
|
|
18
17
|
import RefNameAutocomplete from './RefNameAutocomplete'
|
|
18
|
+
import { fetchResults } from './util'
|
|
19
19
|
import { LinearGenomeViewModel, WIDGET_HEIGHT } from '..'
|
|
20
20
|
const SearchResultsDialog = lazy(() => import('./SearchResultsDialog'))
|
|
21
21
|
|
|
@@ -57,28 +57,6 @@ const ImportForm = observer(({ model }: { model: LGV }) => {
|
|
|
57
57
|
label: value,
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
-
async function fetchResults(query: string, searchType?: SearchType) {
|
|
61
|
-
if (!textSearchManager) {
|
|
62
|
-
console.warn('No text search manager')
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const textSearchResults = await textSearchManager?.search(
|
|
66
|
-
{
|
|
67
|
-
queryString: query,
|
|
68
|
-
searchType,
|
|
69
|
-
},
|
|
70
|
-
searchScope,
|
|
71
|
-
rankSearchResults,
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
const refNameResults = assembly?.allRefNames
|
|
75
|
-
?.filter(refName => refName.startsWith(query))
|
|
76
|
-
.map(r => new BaseResult({ label: r }))
|
|
77
|
-
.slice(0, 10)
|
|
78
|
-
|
|
79
|
-
return [...(refNameResults || []), ...(textSearchResults || [])]
|
|
80
|
-
}
|
|
81
|
-
|
|
82
60
|
// gets a string as input, or use stored option results from previous query,
|
|
83
61
|
// then re-query and
|
|
84
62
|
// 1) if it has multiple results: pop a dialog
|
|
@@ -105,7 +83,14 @@ const ImportForm = observer(({ model }: { model: LGV }) => {
|
|
|
105
83
|
) {
|
|
106
84
|
model.navToLocString(location, selectedAsm)
|
|
107
85
|
} else {
|
|
108
|
-
const results = await fetchResults(
|
|
86
|
+
const results = await fetchResults({
|
|
87
|
+
queryString: input,
|
|
88
|
+
searchType: 'exact',
|
|
89
|
+
searchScope,
|
|
90
|
+
rankSearchResults,
|
|
91
|
+
textSearchManager,
|
|
92
|
+
assembly,
|
|
93
|
+
})
|
|
109
94
|
if (results.length > 1) {
|
|
110
95
|
model.setSearchResults(results, input.toLowerCase())
|
|
111
96
|
return
|
|
@@ -165,7 +150,15 @@ const ImportForm = observer(({ model }: { model: LGV }) => {
|
|
|
165
150
|
<CloseIcon style={{ color: 'red' }} />
|
|
166
151
|
) : value ? (
|
|
167
152
|
<RefNameAutocomplete
|
|
168
|
-
fetchResults={
|
|
153
|
+
fetchResults={queryString =>
|
|
154
|
+
fetchResults({
|
|
155
|
+
queryString,
|
|
156
|
+
assembly,
|
|
157
|
+
textSearchManager,
|
|
158
|
+
rankSearchResults,
|
|
159
|
+
searchScope,
|
|
160
|
+
})
|
|
161
|
+
}
|
|
169
162
|
model={model}
|
|
170
163
|
assemblyName={assemblyError ? undefined : selectedAsm}
|
|
171
164
|
value={value}
|
|
@@ -79,7 +79,7 @@ describe('<LinearGenomeView />', () => {
|
|
|
79
79
|
await findByText('Foo Track')
|
|
80
80
|
// test needs to wait until it's updated to display 100 bp in the header to
|
|
81
81
|
// make snapshot pass
|
|
82
|
-
await findByText('
|
|
82
|
+
await findByText('100bp')
|
|
83
83
|
expect(container.firstChild).toMatchSnapshot()
|
|
84
84
|
})
|
|
85
85
|
it('renders two tracks, two regions', async () => {
|
|
@@ -145,7 +145,7 @@ describe('<LinearGenomeView />', () => {
|
|
|
145
145
|
<LinearGenomeView model={model} />,
|
|
146
146
|
)
|
|
147
147
|
await findByText('Foo Track')
|
|
148
|
-
await findByText('
|
|
148
|
+
await findByText('798bp')
|
|
149
149
|
await findAllByTestId('svgfeatures')
|
|
150
150
|
|
|
151
151
|
expect(container.firstChild).toMatchSnapshot()
|