@jbrowse/plugin-linear-comparative-view 2.8.0 → 2.10.0
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/LGVSyntenyDisplay/configSchemaF.d.ts +2 -0
- package/dist/LGVSyntenyDisplay/configSchemaF.js +2 -0
- package/dist/LGVSyntenyDisplay/model.d.ts +18 -7
- package/dist/LGVSyntenyDisplay/model.js +13 -3
- package/dist/LaunchLinearSyntenyView.js +6 -2
- package/dist/LinearComparativeDisplay/stateModelFactory.d.ts +35 -27
- package/dist/LinearComparativeDisplay/stateModelFactory.js +2 -0
- package/dist/LinearComparativeView/model.d.ts +141 -6
- package/dist/LinearComparativeView/model.js +4 -2
- package/dist/LinearReadVsRef/LinearReadVsRef.js +1 -1
- package/dist/LinearReadVsRef/index.js +26 -2
- package/dist/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +185 -96
- package/dist/LinearSyntenyDisplay/components/SyntenyContextMenu.d.ts +13 -0
- package/dist/LinearSyntenyDisplay/components/SyntenyContextMenu.js +57 -0
- package/dist/LinearSyntenyDisplay/components/SyntenyTooltip.d.ts +1 -3
- package/dist/LinearSyntenyDisplay/components/SyntenyTooltip.js +19 -51
- package/dist/LinearSyntenyDisplay/model.d.ts +27 -17
- package/dist/LinearSyntenyDisplay/model.js +2 -1
- package/dist/LinearSyntenyView/components/ImportForm/index.js +1 -1
- package/dist/LinearSyntenyView/model.d.ts +441 -16
- package/dist/LinearSyntenyView/model.js +8 -1
- package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +6 -6
- package/dist/SyntenyTrack/configSchema.d.ts +5 -0
- package/dist/SyntenyTrack/configSchema.js +2 -0
- package/esm/LGVSyntenyDisplay/configSchemaF.d.ts +2 -0
- package/esm/LGVSyntenyDisplay/configSchemaF.js +2 -0
- package/esm/LGVSyntenyDisplay/model.d.ts +18 -7
- package/esm/LGVSyntenyDisplay/model.js +13 -3
- package/esm/LaunchLinearSyntenyView.js +6 -2
- package/esm/LinearComparativeDisplay/stateModelFactory.d.ts +35 -27
- package/esm/LinearComparativeDisplay/stateModelFactory.js +2 -0
- package/esm/LinearComparativeView/model.d.ts +141 -6
- package/esm/LinearComparativeView/model.js +4 -2
- package/esm/LinearReadVsRef/LinearReadVsRef.js +1 -1
- package/esm/LinearReadVsRef/index.js +2 -1
- package/esm/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +186 -97
- package/esm/LinearSyntenyDisplay/components/SyntenyContextMenu.d.ts +13 -0
- package/esm/LinearSyntenyDisplay/components/SyntenyContextMenu.js +51 -0
- package/esm/LinearSyntenyDisplay/components/SyntenyTooltip.d.ts +1 -3
- package/esm/LinearSyntenyDisplay/components/SyntenyTooltip.js +18 -30
- package/esm/LinearSyntenyDisplay/model.d.ts +27 -17
- package/esm/LinearSyntenyDisplay/model.js +2 -1
- package/esm/LinearSyntenyView/components/ImportForm/index.js +1 -1
- package/esm/LinearSyntenyView/model.d.ts +441 -16
- package/esm/LinearSyntenyView/model.js +8 -1
- package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +6 -6
- package/esm/SyntenyTrack/configSchema.d.ts +5 -0
- package/esm/SyntenyTrack/configSchema.js +2 -0
- package/package.json +4 -5
|
@@ -1,16 +1,41 @@
|
|
|
1
|
-
import React, { useState, useCallback } from 'react';
|
|
1
|
+
import React, { useState, useCallback, useRef } from 'react';
|
|
2
2
|
import { observer } from 'mobx-react';
|
|
3
3
|
import { assembleLocString, getContainingView, getSession, isSessionModelWithWidgets, } from '@jbrowse/core/util';
|
|
4
|
+
import { transaction } from 'mobx';
|
|
5
|
+
import { makeStyles } from 'tss-react/mui';
|
|
4
6
|
// locals
|
|
5
7
|
import SyntenyTooltip from './SyntenyTooltip';
|
|
6
8
|
import { getId, MAX_COLOR_RANGE } from '../drawSynteny';
|
|
9
|
+
import SyntenyContextMenu from './SyntenyContextMenu';
|
|
10
|
+
const useStyles = makeStyles()({
|
|
11
|
+
pix: {
|
|
12
|
+
imageRendering: 'pixelated',
|
|
13
|
+
pointerEvents: 'none',
|
|
14
|
+
visibility: 'hidden',
|
|
15
|
+
position: 'absolute',
|
|
16
|
+
},
|
|
17
|
+
rel: {
|
|
18
|
+
position: 'relative',
|
|
19
|
+
},
|
|
20
|
+
abs: {
|
|
21
|
+
position: 'absolute',
|
|
22
|
+
},
|
|
23
|
+
none: {
|
|
24
|
+
pointEvents: 'none',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
7
27
|
const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
8
|
-
const
|
|
28
|
+
const { classes, cx } = useStyles();
|
|
29
|
+
const xOffset = useRef(0);
|
|
30
|
+
const currScrollFrame = useRef();
|
|
9
31
|
const view = getContainingView(model);
|
|
10
32
|
const height = view.middleComparativeHeight;
|
|
11
33
|
const width = view.width;
|
|
34
|
+
const [anchorEl, setAnchorEl] = useState();
|
|
12
35
|
const [tooltip, setTooltip] = useState('');
|
|
13
36
|
const [currX, setCurrX] = useState();
|
|
37
|
+
const [mouseCurrDownX, setMouseCurrDownX] = useState();
|
|
38
|
+
const [mouseInitialDownX, setMouseInitialDownX] = useState();
|
|
14
39
|
const [currY, setCurrY] = useState();
|
|
15
40
|
// these useCallbacks avoid new refs from being created on any mouseover, etc.
|
|
16
41
|
const k1 = useCallback((ref) => model.setMouseoverCanvasRef(ref),
|
|
@@ -25,108 +50,172 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
25
50
|
const k4 = useCallback((ref) => model.setCigarClickMapCanvasRef(ref),
|
|
26
51
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
27
52
|
[model, height, width]);
|
|
28
|
-
return (React.createElement("div", {
|
|
29
|
-
React.createElement("canvas", { ref: k1, width: width, height: height,
|
|
30
|
-
React.createElement("canvas", { ref: k2,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const ref2 = model.cigarClickMapCanvas;
|
|
34
|
-
if (!ref1 || !ref2) {
|
|
35
|
-
return;
|
|
53
|
+
return (React.createElement("div", { className: classes.rel },
|
|
54
|
+
React.createElement("canvas", { ref: k1, width: width, height: height, className: cx(classes.abs, classes.none) }),
|
|
55
|
+
React.createElement("canvas", { ref: k2, onWheel: event => {
|
|
56
|
+
if (Math.abs(event.deltaY) < Math.abs(event.deltaX)) {
|
|
57
|
+
xOffset.current += event.deltaX;
|
|
36
58
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
59
|
+
if (currScrollFrame.current === undefined) {
|
|
60
|
+
currScrollFrame.current = requestAnimationFrame(() => {
|
|
61
|
+
transaction(() => {
|
|
62
|
+
for (const v of view.views) {
|
|
63
|
+
v.horizontalScroll(xOffset.current);
|
|
64
|
+
}
|
|
65
|
+
xOffset.current = 0;
|
|
66
|
+
currScrollFrame.current = undefined;
|
|
67
|
+
});
|
|
68
|
+
});
|
|
42
69
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
70
|
+
}, onMouseMove: event => {
|
|
71
|
+
var _a;
|
|
72
|
+
if (mouseCurrDownX !== undefined) {
|
|
73
|
+
xOffset.current += mouseCurrDownX - event.clientX;
|
|
74
|
+
setMouseCurrDownX(event.clientX);
|
|
75
|
+
if (currScrollFrame.current === undefined) {
|
|
76
|
+
currScrollFrame.current = requestAnimationFrame(() => {
|
|
77
|
+
transaction(() => {
|
|
78
|
+
for (const v of view.views) {
|
|
79
|
+
v.horizontalScroll(xOffset.current);
|
|
80
|
+
}
|
|
81
|
+
xOffset.current = 0;
|
|
82
|
+
currScrollFrame.current = undefined;
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
55
86
|
}
|
|
56
|
-
else
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const unitMultiplier2 = Math.floor(MAX_COLOR_RANGE / cigar.length);
|
|
62
|
-
const cigarIdx = getId(r2, g2, b2, unitMultiplier2);
|
|
63
|
-
const l1 = f1.end - f1.start;
|
|
64
|
-
const l2 = f2.end - f2.start;
|
|
65
|
-
const identity = f1.identity;
|
|
66
|
-
const n1 = f1.name;
|
|
67
|
-
const n2 = f2.name;
|
|
68
|
-
const tooltip = [
|
|
69
|
-
`Loc1: ${assembleLocString(f1)}`,
|
|
70
|
-
`Loc2: ${assembleLocString(f2)}`,
|
|
71
|
-
`Inverted: ${f1.strand === -1}`,
|
|
72
|
-
`Query len: ${l1}`,
|
|
73
|
-
`Target len: ${l2}`,
|
|
74
|
-
];
|
|
75
|
-
if (identity) {
|
|
76
|
-
tooltip.push(`Identity: ${identity}`);
|
|
87
|
+
else {
|
|
88
|
+
const ref1 = model.clickMapCanvas;
|
|
89
|
+
const ref2 = model.cigarClickMapCanvas;
|
|
90
|
+
if (!ref1 || !ref2) {
|
|
91
|
+
return;
|
|
77
92
|
}
|
|
78
|
-
|
|
79
|
-
|
|
93
|
+
const rect = ref1.getBoundingClientRect();
|
|
94
|
+
const ctx1 = ref1.getContext('2d');
|
|
95
|
+
const ctx2 = ref2.getContext('2d');
|
|
96
|
+
if (!ctx1 || !ctx2) {
|
|
97
|
+
return;
|
|
80
98
|
}
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
const { clientX, clientY } = event;
|
|
100
|
+
const x = clientX - rect.left;
|
|
101
|
+
const y = clientY - rect.top;
|
|
102
|
+
setCurrX(clientX);
|
|
103
|
+
setCurrY(clientY);
|
|
104
|
+
const [r1, g1, b1] = ctx1.getImageData(x, y, 1, 1).data;
|
|
105
|
+
const [r2, g2, b2] = ctx2.getImageData(x, y, 1, 1).data;
|
|
106
|
+
const unitMultiplier = Math.floor(MAX_COLOR_RANGE / model.numFeats);
|
|
107
|
+
const id = getId(r1, g1, b1, unitMultiplier);
|
|
108
|
+
model.setMouseoverId((_a = model.featPositions[id]) === null || _a === void 0 ? void 0 : _a.f.id());
|
|
109
|
+
if (id === -1) {
|
|
110
|
+
setTooltip('');
|
|
111
|
+
}
|
|
112
|
+
else if (model.featPositions[id]) {
|
|
113
|
+
const { f, cigar } = model.featPositions[id];
|
|
114
|
+
const unitMultiplier2 = Math.floor(MAX_COLOR_RANGE / cigar.length);
|
|
115
|
+
const cigarIdx = getId(r2, g2, b2, unitMultiplier2);
|
|
116
|
+
setTooltip(getTooltip(f, cigar[cigarIdx], cigar[cigarIdx + 1]));
|
|
83
117
|
}
|
|
84
|
-
setTooltip(tooltip.join('<br/>'));
|
|
85
|
-
}
|
|
86
|
-
}, onMouseLeave: () => model.setMouseoverId(undefined), onClick: event => {
|
|
87
|
-
const ref1 = model.clickMapCanvas;
|
|
88
|
-
const ref2 = model.cigarClickMapCanvas;
|
|
89
|
-
if (!ref1 || !ref2) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
const rect = ref1.getBoundingClientRect();
|
|
93
|
-
const ctx1 = ref1.getContext('2d');
|
|
94
|
-
const ctx2 = ref2.getContext('2d');
|
|
95
|
-
if (!ctx1 || !ctx2) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const x = event.clientX - rect.left;
|
|
99
|
-
const y = event.clientY - rect.top;
|
|
100
|
-
const [r1, g1, b1] = ctx1.getImageData(x, y, 1, 1).data;
|
|
101
|
-
const unitMultiplier = Math.floor(MAX_COLOR_RANGE / model.numFeats);
|
|
102
|
-
const id = getId(r1, g1, b1, unitMultiplier);
|
|
103
|
-
const f = model.featPositions[id];
|
|
104
|
-
if (!f) {
|
|
105
|
-
return;
|
|
106
118
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
119
|
+
}, onMouseLeave: () => {
|
|
120
|
+
model.setMouseoverId(undefined);
|
|
121
|
+
setMouseInitialDownX(undefined);
|
|
122
|
+
setMouseCurrDownX(undefined);
|
|
123
|
+
}, onMouseDown: evt => {
|
|
124
|
+
setMouseCurrDownX(evt.clientX);
|
|
125
|
+
setMouseInitialDownX(evt.clientX);
|
|
126
|
+
}, onMouseUp: evt => {
|
|
127
|
+
setMouseCurrDownX(undefined);
|
|
128
|
+
if (mouseInitialDownX !== undefined &&
|
|
129
|
+
Math.abs(evt.clientX - mouseInitialDownX) < 5) {
|
|
130
|
+
onSyntenyClick(evt, model);
|
|
116
131
|
}
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
React.createElement("canvas", { ref: k4, style: {
|
|
125
|
-
imageRendering: 'pixelated',
|
|
126
|
-
pointerEvents: 'none',
|
|
127
|
-
visibility: 'hidden',
|
|
128
|
-
position: 'absolute',
|
|
129
|
-
}, width: width, height: height }),
|
|
130
|
-
model.mouseoverId && tooltip && currX && currY ? (React.createElement(SyntenyTooltip, { x: currX, y: currY, title: tooltip })) : null));
|
|
132
|
+
}, onContextMenu: evt => {
|
|
133
|
+
onSyntenyContextClick(evt, model, setAnchorEl);
|
|
134
|
+
}, "data-testid": "synteny_canvas", className: classes.abs, width: width, height: height }),
|
|
135
|
+
React.createElement("canvas", { ref: k3, className: classes.pix, width: width, height: height }),
|
|
136
|
+
React.createElement("canvas", { ref: k4, className: classes.pix, width: width, height: height }),
|
|
137
|
+
model.mouseoverId && tooltip && currX && currY ? (React.createElement(SyntenyTooltip, { title: tooltip })) : null,
|
|
138
|
+
anchorEl ? (React.createElement(SyntenyContextMenu, { model: model, anchorEl: anchorEl, onClose: () => setAnchorEl(undefined) })) : null));
|
|
131
139
|
});
|
|
140
|
+
function onSyntenyClick(event, model) {
|
|
141
|
+
const ref1 = model.clickMapCanvas;
|
|
142
|
+
const ref2 = model.cigarClickMapCanvas;
|
|
143
|
+
if (!ref1 || !ref2) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const rect = ref1.getBoundingClientRect();
|
|
147
|
+
const ctx1 = ref1.getContext('2d');
|
|
148
|
+
const ctx2 = ref2.getContext('2d');
|
|
149
|
+
if (!ctx1 || !ctx2) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const x = event.clientX - rect.left;
|
|
153
|
+
const y = event.clientY - rect.top;
|
|
154
|
+
const [r1, g1, b1] = ctx1.getImageData(x, y, 1, 1).data;
|
|
155
|
+
const unitMultiplier = Math.floor(MAX_COLOR_RANGE / model.numFeats);
|
|
156
|
+
const id = getId(r1, g1, b1, unitMultiplier);
|
|
157
|
+
const feat = model.featPositions[id];
|
|
158
|
+
if (feat) {
|
|
159
|
+
const { f } = feat;
|
|
160
|
+
model.setClickId(f.id());
|
|
161
|
+
const session = getSession(model);
|
|
162
|
+
if (isSessionModelWithWidgets(session)) {
|
|
163
|
+
session.showWidget(session.addWidget('SyntenyFeatureWidget', 'syntenyFeature', {
|
|
164
|
+
featureData: {
|
|
165
|
+
feature1: f.toJSON(),
|
|
166
|
+
feature2: f.get('mate'),
|
|
167
|
+
},
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return feat;
|
|
172
|
+
}
|
|
173
|
+
function onSyntenyContextClick(event, model, setAnchorEl) {
|
|
174
|
+
event.preventDefault();
|
|
175
|
+
const ref1 = model.clickMapCanvas;
|
|
176
|
+
const ref2 = model.cigarClickMapCanvas;
|
|
177
|
+
if (!ref1 || !ref2) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const rect = ref1.getBoundingClientRect();
|
|
181
|
+
const ctx1 = ref1.getContext('2d');
|
|
182
|
+
const ctx2 = ref2.getContext('2d');
|
|
183
|
+
if (!ctx1 || !ctx2) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const { clientX, clientY } = event;
|
|
187
|
+
const x = clientX - rect.left;
|
|
188
|
+
const y = clientY - rect.top;
|
|
189
|
+
const [r1, g1, b1] = ctx1.getImageData(x, y, 1, 1).data;
|
|
190
|
+
const unitMultiplier = Math.floor(MAX_COLOR_RANGE / model.numFeats);
|
|
191
|
+
const id = getId(r1, g1, b1, unitMultiplier);
|
|
192
|
+
const f = model.featPositions[id];
|
|
193
|
+
if (f) {
|
|
194
|
+
model.setClickId(f.f.id());
|
|
195
|
+
setAnchorEl({ clientX, clientY, feature: f });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function getTooltip(f, cigarOp, cigarOpLen) {
|
|
199
|
+
// @ts-expect-error
|
|
200
|
+
const f1 = f.toJSON();
|
|
201
|
+
const f2 = f1.mate;
|
|
202
|
+
const l1 = f1.end - f1.start;
|
|
203
|
+
const l2 = f2.end - f2.start;
|
|
204
|
+
const identity = f1.identity;
|
|
205
|
+
const n1 = f1.name;
|
|
206
|
+
const n2 = f2.name;
|
|
207
|
+
return [
|
|
208
|
+
`Loc1: ${assembleLocString(f1)}`,
|
|
209
|
+
`Loc2: ${assembleLocString(f2)}`,
|
|
210
|
+
`Inverted: ${f1.strand === -1}`,
|
|
211
|
+
`Query len: ${l1.toLocaleString('en-US')}`,
|
|
212
|
+
`Target len: ${l2.toLocaleString('en-US')}`,
|
|
213
|
+
identity ? `Identity: ${identity.toPrecision(2)}` : '',
|
|
214
|
+
cigarOp ? `CIGAR operator: ${cigarOp}${cigarOpLen}` : '',
|
|
215
|
+
n1 ? `Name 1: ${n1}` : '',
|
|
216
|
+
n2 ? `Name 1: ${n2}` : '',
|
|
217
|
+
]
|
|
218
|
+
.filter(f => !!f)
|
|
219
|
+
.join('<br/>');
|
|
220
|
+
}
|
|
132
221
|
export default LinearSyntenyRendering;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LinearSyntenyDisplayModel } from '../model';
|
|
3
|
+
interface ClickCoord {
|
|
4
|
+
clientX: number;
|
|
5
|
+
clientY: number;
|
|
6
|
+
feature: any;
|
|
7
|
+
}
|
|
8
|
+
export default function SyntenyContextMenu({ model, onClose, anchorEl, }: {
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
model: LinearSyntenyDisplayModel;
|
|
11
|
+
anchorEl: ClickCoord;
|
|
12
|
+
}): React.JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { getContainingView, getSession } from '@jbrowse/core/util';
|
|
3
|
+
import { Menu } from '@jbrowse/core/ui';
|
|
4
|
+
export default function SyntenyContextMenu({ model, onClose, anchorEl, }) {
|
|
5
|
+
const view = getContainingView(model);
|
|
6
|
+
const { clientX, clientY, feature } = anchorEl;
|
|
7
|
+
return (React.createElement(Menu, { onMenuItemClick: (event, callback) => {
|
|
8
|
+
callback(event);
|
|
9
|
+
onClose();
|
|
10
|
+
}, anchorEl: {
|
|
11
|
+
nodeType: 1,
|
|
12
|
+
getBoundingClientRect: () => {
|
|
13
|
+
const x = clientX;
|
|
14
|
+
const y = clientY;
|
|
15
|
+
return {
|
|
16
|
+
top: y,
|
|
17
|
+
left: x,
|
|
18
|
+
bottom: y,
|
|
19
|
+
right: x,
|
|
20
|
+
width: 0,
|
|
21
|
+
height: 0,
|
|
22
|
+
x,
|
|
23
|
+
y,
|
|
24
|
+
toJSON() { },
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
}, onClose: onClose, open: Boolean(anchorEl), menuItems: [
|
|
28
|
+
{
|
|
29
|
+
label: 'Center on feature',
|
|
30
|
+
onClick: () => {
|
|
31
|
+
const { f } = feature;
|
|
32
|
+
const start = f.get('start');
|
|
33
|
+
const end = f.get('end');
|
|
34
|
+
const refName = f.get('refName');
|
|
35
|
+
const mate = f.get('mate');
|
|
36
|
+
view.views[0]
|
|
37
|
+
.navToLocString(`${refName}:${start}-${end}`)
|
|
38
|
+
.catch(e => {
|
|
39
|
+
console.error(e);
|
|
40
|
+
getSession(model).notify(`${e}`, 'error');
|
|
41
|
+
});
|
|
42
|
+
view.views[1]
|
|
43
|
+
.navToLocString(`${mate.refName}:${mate.start}-${mate.end}`)
|
|
44
|
+
.catch(e => {
|
|
45
|
+
console.error(e);
|
|
46
|
+
getSession(model).notify(`${e}`, 'error');
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
] }));
|
|
51
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { observer } from 'mobx-react';
|
|
3
|
-
import { Portal, alpha } from '@mui/material';
|
|
3
|
+
import { Portal, useTheme, alpha } from '@mui/material';
|
|
4
4
|
import { makeStyles } from 'tss-react/mui';
|
|
5
|
-
import {
|
|
5
|
+
import { useClientPoint, useFloating, useInteractions, } from '@floating-ui/react';
|
|
6
6
|
import { SanitizedHTML } from '@jbrowse/core/ui';
|
|
7
7
|
function round(value) {
|
|
8
8
|
return Math.round(value * 1e5) / 1e5;
|
|
@@ -24,34 +24,22 @@ const useStyles = makeStyles()(theme => ({
|
|
|
24
24
|
wordWrap: 'break-word',
|
|
25
25
|
},
|
|
26
26
|
}));
|
|
27
|
-
const SyntenyTooltip = observer(function ({
|
|
28
|
-
|
|
29
|
-
const
|
|
27
|
+
const SyntenyTooltip = observer(function ({ title }) {
|
|
28
|
+
var _a, _b;
|
|
29
|
+
const theme = useTheme();
|
|
30
30
|
const { classes } = useStyles();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
toJSON() { },
|
|
44
|
-
};
|
|
45
|
-
},
|
|
46
|
-
}), [x, y, width]);
|
|
47
|
-
const { styles, attributes } = usePopper(virtElement, anchorEl);
|
|
48
|
-
return title ? (React.createElement(Portal, null,
|
|
49
|
-
React.createElement("div", { ref: ref => {
|
|
50
|
-
setWidth((ref === null || ref === void 0 ? void 0 : ref.getBoundingClientRect().width) || 0);
|
|
51
|
-
setAnchorEl(ref);
|
|
52
|
-
}, className: classes.tooltip,
|
|
53
|
-
// zIndex needed to go over widget drawer
|
|
54
|
-
style: { ...styles.popper, zIndex: 100000 }, ...attributes.popper },
|
|
31
|
+
const { refs, floatingStyles, context } = useFloating({
|
|
32
|
+
placement: 'right',
|
|
33
|
+
});
|
|
34
|
+
const clientPoint = useClientPoint(context);
|
|
35
|
+
const { getFloatingProps } = useInteractions([clientPoint]);
|
|
36
|
+
const popperTheme = (_a = theme === null || theme === void 0 ? void 0 : theme.components) === null || _a === void 0 ? void 0 : _a.MuiPopper;
|
|
37
|
+
return title ? (React.createElement(Portal, { container: (_b = popperTheme === null || popperTheme === void 0 ? void 0 : popperTheme.defaultProps) === null || _b === void 0 ? void 0 : _b.container },
|
|
38
|
+
React.createElement("div", { className: classes.tooltip, ref: refs.setFloating, style: {
|
|
39
|
+
...floatingStyles,
|
|
40
|
+
zIndex: 100000,
|
|
41
|
+
pointerEvents: 'none',
|
|
42
|
+
}, ...getFloatingProps() },
|
|
55
43
|
React.createElement(SanitizedHTML, { html: title })))) : null;
|
|
56
44
|
});
|
|
57
45
|
export default SyntenyTooltip;
|
|
@@ -5,7 +5,7 @@ import { Feature } from '@jbrowse/core/util';
|
|
|
5
5
|
interface Pos {
|
|
6
6
|
offsetPx: number;
|
|
7
7
|
}
|
|
8
|
-
interface FeatPos {
|
|
8
|
+
export interface FeatPos {
|
|
9
9
|
p11: Pos;
|
|
10
10
|
p12: Pos;
|
|
11
11
|
p21: Pos;
|
|
@@ -15,7 +15,8 @@ interface FeatPos {
|
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* #stateModel LinearSyntenyDisplay
|
|
18
|
-
* extends
|
|
18
|
+
* extends
|
|
19
|
+
* - [LinearComparativeDisplay](../linearcomparativedisplay)
|
|
19
20
|
*/
|
|
20
21
|
declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): import("mobx-state-tree").IModelType<{
|
|
21
22
|
id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
@@ -77,17 +78,20 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
77
78
|
rendererTypeName: string;
|
|
78
79
|
error: unknown;
|
|
79
80
|
message: string | undefined;
|
|
80
|
-
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
81
|
-
* #action
|
|
82
|
-
*/
|
|
81
|
+
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
83
82
|
}> | null;
|
|
84
83
|
readonly adapterConfig: any;
|
|
85
84
|
readonly parentTrack: any;
|
|
86
|
-
renderProps(): any;
|
|
85
|
+
renderProps(): any; /**
|
|
86
|
+
* #getter
|
|
87
|
+
*/
|
|
87
88
|
readonly rendererType: import("@jbrowse/core/pluggableElementTypes").RendererType;
|
|
88
89
|
readonly DisplayMessageComponent: import("react").FC<any> | undefined;
|
|
89
90
|
trackMenuItems(): import("@jbrowse/core/ui").MenuItem[];
|
|
90
|
-
readonly viewMenuActions: import("@jbrowse/core/ui").MenuItem[];
|
|
91
|
+
readonly viewMenuActions: import("@jbrowse/core/ui").MenuItem[]; /**
|
|
92
|
+
* #getter
|
|
93
|
+
* used for synteny svg rendering
|
|
94
|
+
*/
|
|
91
95
|
regionCannotBeRendered(): null;
|
|
92
96
|
} & {
|
|
93
97
|
setMessage(arg?: string | undefined): void;
|
|
@@ -154,17 +158,20 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
154
158
|
rendererTypeName: string;
|
|
155
159
|
error: unknown;
|
|
156
160
|
message: string | undefined;
|
|
157
|
-
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
158
|
-
* #action
|
|
159
|
-
*/
|
|
161
|
+
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
160
162
|
}> | null;
|
|
161
163
|
readonly adapterConfig: any;
|
|
162
164
|
readonly parentTrack: any;
|
|
163
|
-
renderProps(): any;
|
|
165
|
+
renderProps(): any; /**
|
|
166
|
+
* #getter
|
|
167
|
+
*/
|
|
164
168
|
readonly rendererType: import("@jbrowse/core/pluggableElementTypes").RendererType;
|
|
165
169
|
readonly DisplayMessageComponent: import("react").FC<any> | undefined;
|
|
166
170
|
trackMenuItems(): import("@jbrowse/core/ui").MenuItem[];
|
|
167
|
-
readonly viewMenuActions: import("@jbrowse/core/ui").MenuItem[];
|
|
171
|
+
readonly viewMenuActions: import("@jbrowse/core/ui").MenuItem[]; /**
|
|
172
|
+
* #getter
|
|
173
|
+
* used for synteny svg rendering
|
|
174
|
+
*/
|
|
168
175
|
regionCannotBeRendered(): null;
|
|
169
176
|
} & {
|
|
170
177
|
setMessage(arg?: string | undefined): void;
|
|
@@ -226,17 +233,20 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
226
233
|
rendererTypeName: string;
|
|
227
234
|
error: unknown;
|
|
228
235
|
message: string | undefined;
|
|
229
|
-
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
230
|
-
* #action
|
|
231
|
-
*/
|
|
236
|
+
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
232
237
|
}> | null;
|
|
233
238
|
readonly adapterConfig: any;
|
|
234
239
|
readonly parentTrack: any;
|
|
235
|
-
renderProps(): any;
|
|
240
|
+
renderProps(): any; /**
|
|
241
|
+
* #getter
|
|
242
|
+
*/
|
|
236
243
|
readonly rendererType: import("@jbrowse/core/pluggableElementTypes").RendererType;
|
|
237
244
|
readonly DisplayMessageComponent: import("react").FC<any> | undefined;
|
|
238
245
|
trackMenuItems(): import("@jbrowse/core/ui").MenuItem[];
|
|
239
|
-
readonly viewMenuActions: import("@jbrowse/core/ui").MenuItem[];
|
|
246
|
+
readonly viewMenuActions: import("@jbrowse/core/ui").MenuItem[]; /**
|
|
247
|
+
* #getter
|
|
248
|
+
* used for synteny svg rendering
|
|
249
|
+
*/
|
|
240
250
|
regionCannotBeRendered(): null;
|
|
241
251
|
} & {
|
|
242
252
|
setMessage(arg?: string | undefined): void;
|
|
@@ -4,7 +4,8 @@ import { getConf, ConfigurationReference, } from '@jbrowse/core/configuration';
|
|
|
4
4
|
import baseModelFactory from '../LinearComparativeDisplay/stateModelFactory';
|
|
5
5
|
/**
|
|
6
6
|
* #stateModel LinearSyntenyDisplay
|
|
7
|
-
* extends
|
|
7
|
+
* extends
|
|
8
|
+
* - [LinearComparativeDisplay](../linearcomparativedisplay)
|
|
8
9
|
*/
|
|
9
10
|
function stateModelFactory(configSchema) {
|
|
10
11
|
return types
|
|
@@ -17,7 +17,7 @@ const useStyles = makeStyles()(theme => ({
|
|
|
17
17
|
},
|
|
18
18
|
}));
|
|
19
19
|
function TrackSelector({ setSessionTrackData, setShowTrackId, sessionTrackData, assembly1, assembly2, model, }) {
|
|
20
|
-
const [choice, setChoice] = useState('
|
|
20
|
+
const [choice, setChoice] = useState('tracklist');
|
|
21
21
|
useEffect(() => {
|
|
22
22
|
if (choice === 'none') {
|
|
23
23
|
setSessionTrackData(undefined);
|