@jbrowse/plugin-linear-comparative-view 2.15.4 → 2.16.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/LaunchLinearSyntenyView.js +41 -11
- package/dist/LinearComparativeDisplay/stateModelFactory.d.ts +14 -9
- package/dist/LinearComparativeDisplay/stateModelFactory.js +8 -9
- package/dist/LinearComparativeView/components/Header.d.ts +2 -3
- package/dist/LinearComparativeView/components/Header.js +72 -62
- package/dist/LinearComparativeView/components/HeaderSearchBoxes.d.ts +6 -0
- package/dist/LinearComparativeView/components/HeaderSearchBoxes.js +34 -0
- package/dist/LinearComparativeView/components/LinearComparativeRenderArea.d.ts +6 -0
- package/dist/LinearComparativeView/components/LinearComparativeRenderArea.js +61 -0
- package/dist/LinearComparativeView/components/LinearComparativeView.d.ts +2 -4
- package/dist/LinearComparativeView/components/LinearComparativeView.js +3 -67
- package/dist/LinearComparativeView/components/Rubberband.js +1 -1
- package/dist/LinearComparativeView/index.js +3 -0
- package/dist/LinearComparativeView/model.d.ts +265 -12
- package/dist/LinearComparativeView/model.js +45 -75
- package/dist/LinearSyntenyDisplay/afterAttach.js +5 -3
- package/dist/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +32 -24
- package/dist/LinearSyntenyDisplay/components/SyntenyContextMenu.js +12 -6
- package/dist/LinearSyntenyDisplay/components/util.d.ts +2 -1
- package/dist/LinearSyntenyDisplay/components/util.js +5 -5
- package/dist/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
- package/dist/LinearSyntenyDisplay/drawSynteny.js +28 -22
- package/dist/LinearSyntenyDisplay/index.js +1 -1
- package/dist/LinearSyntenyDisplay/model.d.ts +12 -11
- package/dist/LinearSyntenyDisplay/model.js +7 -0
- package/dist/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts} +2 -3
- package/dist/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js} +3 -3
- package/dist/LinearSyntenyView/components/ImportForm/LinearSyntenyImportForm.js +195 -0
- package/dist/LinearSyntenyView/components/ImportForm/Spacer.d.ts +2 -0
- package/dist/LinearSyntenyView/components/ImportForm/Spacer.js +10 -0
- package/dist/LinearSyntenyView/components/ImportForm/TrackSelector.d.ts +10 -0
- package/dist/LinearSyntenyView/components/ImportForm/{ImportSyntenyTrackSelector.js → TrackSelector.js} +15 -20
- package/dist/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.d.ts +14 -0
- package/dist/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.js +52 -0
- package/dist/LinearSyntenyView/components/LinearSyntenyView.js +3 -3
- package/dist/LinearSyntenyView/index.js +1 -1
- package/dist/LinearSyntenyView/model.d.ts +267 -9
- package/dist/LinearSyntenyView/model.js +2 -2
- package/dist/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.d.ts +12 -0
- package/dist/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.js +19 -0
- package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.d.ts +1 -3
- package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +36 -27
- package/dist/LinearSyntenyViewHelper/index.d.ts +2 -0
- package/dist/LinearSyntenyViewHelper/index.js +25 -0
- package/dist/LinearSyntenyViewHelper/stateModelFactory.d.ts +30 -0
- package/dist/LinearSyntenyViewHelper/stateModelFactory.js +105 -0
- package/dist/index.js +2 -0
- package/esm/LaunchLinearSyntenyView.js +41 -11
- package/esm/LinearComparativeDisplay/stateModelFactory.d.ts +14 -9
- package/esm/LinearComparativeDisplay/stateModelFactory.js +9 -10
- package/esm/LinearComparativeView/components/Header.d.ts +2 -3
- package/esm/LinearComparativeView/components/Header.js +73 -63
- package/esm/LinearComparativeView/components/HeaderSearchBoxes.d.ts +6 -0
- package/esm/LinearComparativeView/components/HeaderSearchBoxes.js +29 -0
- package/esm/LinearComparativeView/components/LinearComparativeRenderArea.d.ts +6 -0
- package/esm/LinearComparativeView/components/LinearComparativeRenderArea.js +56 -0
- package/esm/LinearComparativeView/components/LinearComparativeView.d.ts +2 -4
- package/esm/LinearComparativeView/components/LinearComparativeView.js +3 -67
- package/esm/LinearComparativeView/components/Rubberband.js +1 -1
- package/esm/LinearComparativeView/index.js +3 -0
- package/esm/LinearComparativeView/model.d.ts +265 -12
- package/esm/LinearComparativeView/model.js +47 -77
- package/esm/LinearSyntenyDisplay/afterAttach.js +6 -4
- package/esm/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +33 -25
- package/esm/LinearSyntenyDisplay/components/SyntenyContextMenu.js +12 -6
- package/esm/LinearSyntenyDisplay/components/util.d.ts +2 -1
- package/esm/LinearSyntenyDisplay/components/util.js +5 -5
- package/esm/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
- package/esm/LinearSyntenyDisplay/drawSynteny.js +28 -22
- package/esm/LinearSyntenyDisplay/index.js +1 -1
- package/esm/LinearSyntenyDisplay/model.d.ts +12 -11
- package/esm/LinearSyntenyDisplay/model.js +8 -1
- package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts} +2 -3
- package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js} +3 -3
- package/esm/LinearSyntenyView/components/ImportForm/LinearSyntenyImportForm.js +167 -0
- package/esm/LinearSyntenyView/components/ImportForm/Spacer.d.ts +2 -0
- package/esm/LinearSyntenyView/components/ImportForm/Spacer.js +4 -0
- package/esm/LinearSyntenyView/components/ImportForm/TrackSelector.d.ts +10 -0
- package/esm/LinearSyntenyView/components/ImportForm/{ImportSyntenyTrackSelector.js → TrackSelector.js} +15 -20
- package/esm/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.d.ts +14 -0
- package/esm/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.js +23 -0
- package/esm/LinearSyntenyView/components/LinearSyntenyView.js +3 -3
- package/esm/LinearSyntenyView/index.js +1 -1
- package/esm/LinearSyntenyView/model.d.ts +267 -9
- package/esm/LinearSyntenyView/model.js +2 -2
- package/esm/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.d.ts +12 -0
- package/esm/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.js +13 -0
- package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.d.ts +1 -3
- package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +38 -29
- package/esm/LinearSyntenyViewHelper/index.d.ts +2 -0
- package/esm/LinearSyntenyViewHelper/index.js +19 -0
- package/esm/LinearSyntenyViewHelper/stateModelFactory.d.ts +30 -0
- package/esm/LinearSyntenyViewHelper/stateModelFactory.js +102 -0
- package/esm/index.js +2 -0
- package/package.json +2 -2
- package/dist/LinearSyntenyView/components/ImportForm/ImportSyntenyTrackSelector.d.ts +0 -9
- package/dist/LinearSyntenyView/components/ImportForm/index.js +0 -138
- package/esm/LinearSyntenyView/components/ImportForm/ImportSyntenyTrackSelector.d.ts +0 -9
- package/esm/LinearSyntenyView/components/ImportForm/index.js +0 -110
- /package/dist/LinearSyntenyView/components/ImportForm/{index.d.ts → LinearSyntenyImportForm.d.ts} +0 -0
- /package/esm/LinearSyntenyView/components/ImportForm/{index.d.ts → LinearSyntenyImportForm.d.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useCallback, useRef, lazy } from 'react';
|
|
1
|
+
import React, { useState, useCallback, useRef, lazy, useEffect } from 'react';
|
|
2
2
|
import { observer } from 'mobx-react';
|
|
3
3
|
import { getContainingView } from '@jbrowse/core/util';
|
|
4
4
|
import { transaction } from 'mobx';
|
|
@@ -17,21 +17,21 @@ const useStyles = makeStyles()({
|
|
|
17
17
|
rel: {
|
|
18
18
|
position: 'relative',
|
|
19
19
|
},
|
|
20
|
-
|
|
20
|
+
mouseoverCanvas: {
|
|
21
21
|
position: 'absolute',
|
|
22
|
-
},
|
|
23
|
-
none: {
|
|
24
22
|
pointEvents: 'none',
|
|
25
23
|
},
|
|
24
|
+
mainCanvas: {
|
|
25
|
+
position: 'absolute',
|
|
26
|
+
},
|
|
26
27
|
});
|
|
27
28
|
const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
28
|
-
const { classes
|
|
29
|
+
const { classes } = useStyles();
|
|
29
30
|
const xOffset = useRef(0);
|
|
30
|
-
const currScrollFrame = useRef();
|
|
31
31
|
const view = getContainingView(model);
|
|
32
|
-
const height = view.middleComparativeHeight;
|
|
33
32
|
const width = view.width;
|
|
34
33
|
const delta = useRef(0);
|
|
34
|
+
const scheduled = useRef(false);
|
|
35
35
|
const timeout = useRef();
|
|
36
36
|
const [anchorEl, setAnchorEl] = useState();
|
|
37
37
|
const [tooltip, setTooltip] = useState('');
|
|
@@ -39,7 +39,8 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
39
39
|
const [mouseCurrDownX, setMouseCurrDownX] = useState();
|
|
40
40
|
const [mouseInitialDownX, setMouseInitialDownX] = useState();
|
|
41
41
|
const [currY, setCurrY] = useState();
|
|
42
|
-
const { mouseoverId } = model;
|
|
42
|
+
const { mouseoverId, height } = model;
|
|
43
|
+
const k2p = useRef();
|
|
43
44
|
// these useCallbacks avoid new refs from being created on any mouseover,
|
|
44
45
|
// etc.
|
|
45
46
|
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
@@ -51,6 +52,13 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
51
52
|
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
52
53
|
const k2 = useCallback((ref) => {
|
|
53
54
|
model.setMainCanvasRef(ref);
|
|
55
|
+
k2p.current = ref; // this ref is additionally used in useEffect below
|
|
56
|
+
},
|
|
57
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
58
|
+
[model, height, width]);
|
|
59
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
var _a;
|
|
54
62
|
function onWheel(event) {
|
|
55
63
|
event.preventDefault();
|
|
56
64
|
if (event.ctrlKey) {
|
|
@@ -62,11 +70,12 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
62
70
|
clearTimeout(timeout.current);
|
|
63
71
|
}
|
|
64
72
|
timeout.current = setTimeout(() => {
|
|
73
|
+
var _a;
|
|
65
74
|
for (const v of view.views) {
|
|
66
75
|
v.setScaleFactor(1);
|
|
67
76
|
v.zoomTo(delta.current > 0
|
|
68
77
|
? v.bpPerPx * (1 + delta.current)
|
|
69
|
-
: v.bpPerPx / (1 - delta.current), event.clientX - ((
|
|
78
|
+
: v.bpPerPx / (1 - delta.current), event.clientX - (((_a = k2p.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().left) || 0));
|
|
70
79
|
}
|
|
71
80
|
delta.current = 0;
|
|
72
81
|
}, 300);
|
|
@@ -75,29 +84,27 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
75
84
|
if (Math.abs(event.deltaY) < Math.abs(event.deltaX)) {
|
|
76
85
|
xOffset.current += event.deltaX / 2;
|
|
77
86
|
}
|
|
78
|
-
if (
|
|
79
|
-
|
|
87
|
+
if (!scheduled.current) {
|
|
88
|
+
scheduled.current = true;
|
|
89
|
+
window.requestAnimationFrame(() => {
|
|
80
90
|
transaction(() => {
|
|
81
91
|
for (const v of view.views) {
|
|
82
92
|
v.horizontalScroll(xOffset.current);
|
|
83
93
|
}
|
|
84
94
|
xOffset.current = 0;
|
|
85
|
-
|
|
95
|
+
scheduled.current = false;
|
|
86
96
|
});
|
|
87
97
|
});
|
|
88
98
|
}
|
|
89
99
|
}
|
|
90
100
|
}
|
|
91
|
-
|
|
92
|
-
// this is a react 19-ism to have a cleanup in the ref callback
|
|
93
|
-
// https://react.dev/blog/2024/04/25/react-19#cleanup-functions-for-refs
|
|
94
|
-
// note: it warns in earlier versions of react
|
|
101
|
+
(_a = k2p.current) === null || _a === void 0 ? void 0 : _a.addEventListener('wheel', onWheel);
|
|
95
102
|
return () => {
|
|
96
|
-
|
|
103
|
+
var _a;
|
|
104
|
+
(_a = k2p.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('wheel', onWheel);
|
|
97
105
|
};
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
[model, height, width]);
|
|
106
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
107
|
+
}, [model, height, width]);
|
|
101
108
|
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
102
109
|
const k3 = useCallback((ref) => {
|
|
103
110
|
model.setClickMapCanvasRef(ref);
|
|
@@ -111,20 +118,21 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
111
118
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
112
119
|
[model, height, width]);
|
|
113
120
|
return (React.createElement("div", { className: classes.rel },
|
|
114
|
-
React.createElement("canvas", { ref: k1, width: width, height: height, className:
|
|
121
|
+
React.createElement("canvas", { ref: k1, width: width, height: height, className: classes.mouseoverCanvas }),
|
|
115
122
|
React.createElement("canvas", { ref: k2, onMouseMove: event => {
|
|
116
123
|
var _a;
|
|
117
124
|
if (mouseCurrDownX !== undefined) {
|
|
118
125
|
xOffset.current += mouseCurrDownX - event.clientX;
|
|
119
126
|
setMouseCurrDownX(event.clientX);
|
|
120
|
-
if (
|
|
121
|
-
|
|
127
|
+
if (!scheduled.current) {
|
|
128
|
+
scheduled.current = true;
|
|
129
|
+
window.requestAnimationFrame(() => {
|
|
122
130
|
transaction(() => {
|
|
123
131
|
for (const v of view.views) {
|
|
124
132
|
v.horizontalScroll(xOffset.current);
|
|
125
133
|
}
|
|
126
134
|
xOffset.current = 0;
|
|
127
|
-
|
|
135
|
+
scheduled.current = false;
|
|
128
136
|
});
|
|
129
137
|
});
|
|
130
138
|
}
|
|
@@ -176,7 +184,7 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
176
184
|
}
|
|
177
185
|
}, onContextMenu: evt => {
|
|
178
186
|
onSynContextClick(evt, model, setAnchorEl);
|
|
179
|
-
}, "data-testid": "synteny_canvas", className: classes.
|
|
187
|
+
}, "data-testid": "synteny_canvas", className: classes.mainCanvas, width: width, height: height }),
|
|
180
188
|
React.createElement("canvas", { ref: k3, className: classes.pix, width: width, height: height }),
|
|
181
189
|
React.createElement("canvas", { ref: k4, className: classes.pix, width: width, height: height }),
|
|
182
190
|
mouseoverId && tooltip && currX && currY ? (React.createElement(SyntenyTooltip, { title: tooltip })) : null,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { getContainingView, getSession } from '@jbrowse/core/util';
|
|
3
3
|
import { Menu } from '@jbrowse/core/ui';
|
|
4
|
+
import { getParent } from 'mobx-state-tree';
|
|
4
5
|
export default function SyntenyContextMenu({ model, onClose, anchorEl, }) {
|
|
5
6
|
const view = getContainingView(model);
|
|
6
7
|
const { clientX, clientY, feature } = anchorEl;
|
|
@@ -29,17 +30,22 @@ export default function SyntenyContextMenu({ model, onClose, anchorEl, }) {
|
|
|
29
30
|
label: 'Center on feature',
|
|
30
31
|
onClick: () => {
|
|
31
32
|
const { f } = feature;
|
|
33
|
+
const track = getParent(model, 4);
|
|
32
34
|
const start = f.get('start');
|
|
33
35
|
const end = f.get('end');
|
|
34
36
|
const refName = f.get('refName');
|
|
35
37
|
const mate = f.get('mate');
|
|
36
|
-
view.views[
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
const l1 = view.views[track.level];
|
|
39
|
+
const l2 = view.views[track.level + 1];
|
|
40
|
+
l1.navToLocString(`${refName}:${start}-${end}`).catch((e) => {
|
|
41
|
+
const err = `${l1.assemblyNames[0]}:${e}`;
|
|
42
|
+
console.error(err);
|
|
43
|
+
getSession(model).notifyError(err, e);
|
|
39
44
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
l2.navToLocString(`${mate.refName}:${mate.start}-${mate.end}`).catch((e) => {
|
|
46
|
+
const err = `${l2.assemblyNames[0]}:${e}`;
|
|
47
|
+
console.error(err);
|
|
48
|
+
getSession(model).notifyError(err, e);
|
|
43
49
|
});
|
|
44
50
|
},
|
|
45
51
|
},
|
|
@@ -19,10 +19,11 @@ interface FeatPos {
|
|
|
19
19
|
f: Feature;
|
|
20
20
|
cigar: string[];
|
|
21
21
|
}
|
|
22
|
-
export declare function drawMatchSimple({ feature, ctx, offsets, cb, height, drawCurves, oobLimit, viewWidth, hideTiny, }: {
|
|
22
|
+
export declare function drawMatchSimple({ feature, ctx, offsets, level, cb, height, drawCurves, oobLimit, viewWidth, hideTiny, }: {
|
|
23
23
|
feature: FeatPos;
|
|
24
24
|
ctx: CanvasRenderingContext2D;
|
|
25
25
|
offsets: number[];
|
|
26
|
+
level: number;
|
|
26
27
|
oobLimit: number;
|
|
27
28
|
viewWidth: number;
|
|
28
29
|
cb: (ctx: CanvasRenderingContext2D) => void;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { assembleLocString, doesIntersect2, getSession, isSessionModelWithWidgets, getContainingTrack, getContainingView, } from '@jbrowse/core/util';
|
|
2
2
|
// locals
|
|
3
3
|
import { getId, MAX_COLOR_RANGE } from '../drawSynteny';
|
|
4
|
-
export function drawMatchSimple({ feature, ctx, offsets, cb, height, drawCurves, oobLimit, viewWidth, hideTiny, }) {
|
|
4
|
+
export function drawMatchSimple({ feature, ctx, offsets, level, cb, height, drawCurves, oobLimit, viewWidth, hideTiny, }) {
|
|
5
5
|
const { p11, p12, p21, p22 } = feature;
|
|
6
|
-
const x11 = p11.offsetPx - offsets[
|
|
7
|
-
const x12 = p12.offsetPx - offsets[
|
|
8
|
-
const x21 = p21.offsetPx - offsets[1];
|
|
9
|
-
const x22 = p22.offsetPx - offsets[1];
|
|
6
|
+
const x11 = p11.offsetPx - offsets[level];
|
|
7
|
+
const x12 = p12.offsetPx - offsets[level];
|
|
8
|
+
const x21 = p21.offsetPx - offsets[level + 1];
|
|
9
|
+
const x22 = p22.offsetPx - offsets[level + 1];
|
|
10
10
|
const l1 = Math.abs(x12 - x11);
|
|
11
11
|
const l2 = Math.abs(x22 - x21);
|
|
12
12
|
const y1 = 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LinearSyntenyDisplayModel } from './model';
|
|
2
2
|
export declare const MAX_COLOR_RANGE: number;
|
|
3
3
|
export declare function getId(r: number, g: number, b: number, unitMultiplier: number): number;
|
|
4
|
-
export declare function drawRef(model: LinearSyntenyDisplayModel, ctx1: CanvasRenderingContext2D, ctx3?: CanvasRenderingContext2D):
|
|
4
|
+
export declare function drawRef(model: LinearSyntenyDisplayModel, ctx1: CanvasRenderingContext2D, ctx3?: CanvasRenderingContext2D): void;
|
|
5
5
|
export declare function drawMouseoverSynteny(model: LinearSyntenyDisplayModel): void;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { doesIntersect2, getContainingView } from '@jbrowse/core/util';
|
|
2
2
|
import { draw, drawMatchSimple } from './components/util';
|
|
3
|
+
import { getParent } from 'mobx-state-tree';
|
|
3
4
|
export const MAX_COLOR_RANGE = 255 * 255 * 255; // max color range
|
|
4
5
|
function makeColor(idx) {
|
|
5
6
|
const r = Math.floor(idx / (255 * 255)) % 255;
|
|
@@ -23,27 +24,28 @@ export function getId(r, g, b, unitMultiplier) {
|
|
|
23
24
|
export function drawRef(model, ctx1, ctx3) {
|
|
24
25
|
var _a;
|
|
25
26
|
const view = getContainingView(model);
|
|
27
|
+
// @ts-expect-error
|
|
28
|
+
const level = getParent(model, 4).level;
|
|
26
29
|
const drawCurves = view.drawCurves;
|
|
27
30
|
const drawCIGAR = view.drawCIGAR;
|
|
28
|
-
const height =
|
|
31
|
+
const { height, featPositions } = model;
|
|
29
32
|
const width = view.width;
|
|
30
33
|
const bpPerPxs = view.views.map(v => v.bpPerPx);
|
|
31
34
|
if (ctx3) {
|
|
32
35
|
ctx3.imageSmoothingEnabled = false;
|
|
33
36
|
}
|
|
34
37
|
ctx1.beginPath();
|
|
35
|
-
const featPos = model.featPositions;
|
|
36
38
|
const offsets = view.views.map(v => v.offsetPx);
|
|
37
|
-
const unitMultiplier = Math.floor(MAX_COLOR_RANGE /
|
|
39
|
+
const unitMultiplier = Math.floor(MAX_COLOR_RANGE / featPositions.length);
|
|
38
40
|
// this loop is optimized to draw many thin lines with a single ctx.stroke
|
|
39
41
|
// call, a separate loop below draws larger boxes
|
|
40
42
|
ctx1.fillStyle = colorMap.M;
|
|
41
43
|
ctx1.strokeStyle = colorMap.M;
|
|
42
|
-
for (const { p11, p12, p21, p22 } of
|
|
43
|
-
const x11 = p11.offsetPx - offsets[
|
|
44
|
-
const x12 = p12.offsetPx - offsets[
|
|
45
|
-
const x21 = p21.offsetPx - offsets[1];
|
|
46
|
-
const x22 = p22.offsetPx - offsets[1];
|
|
44
|
+
for (const { p11, p12, p21, p22 } of featPositions) {
|
|
45
|
+
const x11 = p11.offsetPx - offsets[level];
|
|
46
|
+
const x12 = p12.offsetPx - offsets[level];
|
|
47
|
+
const x21 = p21.offsetPx - offsets[level + 1];
|
|
48
|
+
const x22 = p22.offsetPx - offsets[level + 1];
|
|
47
49
|
const l1 = Math.abs(x12 - x11);
|
|
48
50
|
const l2 = Math.abs(x22 - x21);
|
|
49
51
|
const y1 = 0;
|
|
@@ -69,11 +71,11 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
69
71
|
// ctx.stroke once is much more efficient than calling stroke() many times
|
|
70
72
|
ctx1.fillStyle = colorMap.M;
|
|
71
73
|
ctx1.strokeStyle = colorMap.M;
|
|
72
|
-
for (const { p11, p12, p21, p22, f, cigar } of
|
|
73
|
-
const x11 = p11.offsetPx - offsets[
|
|
74
|
-
const x12 = p12.offsetPx - offsets[
|
|
75
|
-
const x21 = p21.offsetPx - offsets[1];
|
|
76
|
-
const x22 = p22.offsetPx - offsets[1];
|
|
74
|
+
for (const { p11, p12, p21, p22, f, cigar } of featPositions) {
|
|
75
|
+
const x11 = p11.offsetPx - offsets[level];
|
|
76
|
+
const x12 = p12.offsetPx - offsets[level];
|
|
77
|
+
const x21 = p21.offsetPx - offsets[level + 1];
|
|
78
|
+
const x22 = p22.offsetPx - offsets[level + 1];
|
|
77
79
|
const l1 = Math.abs(x12 - x11);
|
|
78
80
|
const l2 = Math.abs(x22 - x21);
|
|
79
81
|
const minX = Math.min(x21, x22);
|
|
@@ -108,8 +110,8 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
108
110
|
px1 = cx1;
|
|
109
111
|
px2 = cx2;
|
|
110
112
|
}
|
|
111
|
-
const d1 = len / bpPerPxs[
|
|
112
|
-
const d2 = len / bpPerPxs[1];
|
|
113
|
+
const d1 = len / bpPerPxs[level];
|
|
114
|
+
const d2 = len / bpPerPxs[level + 1];
|
|
113
115
|
if (op === 'M' || op === '=' || op === 'X') {
|
|
114
116
|
cx1 += d1 * rev1;
|
|
115
117
|
cx2 += d2 * rev2;
|
|
@@ -135,9 +137,9 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
135
137
|
continuingFlag = true;
|
|
136
138
|
}
|
|
137
139
|
else {
|
|
138
|
-
// allow rendering the dominant color when using continuing
|
|
139
|
-
// if the last element of continuing was a large
|
|
140
|
-
// just use match
|
|
140
|
+
// allow rendering the dominant color when using continuing
|
|
141
|
+
// flag if the last element of continuing was a large
|
|
142
|
+
// feature, else just use match
|
|
141
143
|
ctx1.fillStyle =
|
|
142
144
|
colorMap[(continuingFlag && d1 > 1) || d2 > 1 ? op : 'M'];
|
|
143
145
|
continuingFlag = false;
|
|
@@ -162,8 +164,8 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
162
164
|
}
|
|
163
165
|
ctx2.imageSmoothingEnabled = false;
|
|
164
166
|
ctx2.clearRect(0, 0, width, height);
|
|
165
|
-
for (let i = 0; i <
|
|
166
|
-
const feature =
|
|
167
|
+
for (let i = 0; i < featPositions.length; i++) {
|
|
168
|
+
const feature = featPositions[i];
|
|
167
169
|
const idx = i * unitMultiplier + 1;
|
|
168
170
|
ctx2.fillStyle = makeColor(idx);
|
|
169
171
|
// too many click map false positives with colored stroked lines
|
|
@@ -174,6 +176,7 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
174
176
|
feature,
|
|
175
177
|
ctx: ctx2,
|
|
176
178
|
drawCurves,
|
|
179
|
+
level,
|
|
177
180
|
offsets,
|
|
178
181
|
oobLimit,
|
|
179
182
|
viewWidth: view.width,
|
|
@@ -181,7 +184,6 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
181
184
|
height,
|
|
182
185
|
});
|
|
183
186
|
}
|
|
184
|
-
return undefined;
|
|
185
187
|
}
|
|
186
188
|
export function drawMouseoverSynteny(model) {
|
|
187
189
|
var _a;
|
|
@@ -189,10 +191,12 @@ export function drawMouseoverSynteny(model) {
|
|
|
189
191
|
const highResolutionScaling = 1;
|
|
190
192
|
const view = getContainingView(model);
|
|
191
193
|
const drawCurves = view.drawCurves;
|
|
192
|
-
const height =
|
|
194
|
+
const height = model.height;
|
|
193
195
|
const width = view.width;
|
|
194
196
|
const ctx = (_a = model.mouseoverCanvas) === null || _a === void 0 ? void 0 : _a.getContext('2d');
|
|
195
197
|
const offsets = view.views.map(v => v.offsetPx);
|
|
198
|
+
// @ts-expect-error
|
|
199
|
+
const level = getParent(model, 4).level;
|
|
196
200
|
if (!ctx) {
|
|
197
201
|
return;
|
|
198
202
|
}
|
|
@@ -207,6 +211,7 @@ export function drawMouseoverSynteny(model) {
|
|
|
207
211
|
ctx.fill();
|
|
208
212
|
},
|
|
209
213
|
feature: feature1,
|
|
214
|
+
level,
|
|
210
215
|
ctx,
|
|
211
216
|
oobLimit,
|
|
212
217
|
viewWidth: view.width,
|
|
@@ -224,6 +229,7 @@ export function drawMouseoverSynteny(model) {
|
|
|
224
229
|
},
|
|
225
230
|
feature: feature2,
|
|
226
231
|
ctx,
|
|
232
|
+
level,
|
|
227
233
|
oobLimit,
|
|
228
234
|
viewWidth: view.width,
|
|
229
235
|
drawCurves,
|
|
@@ -11,7 +11,7 @@ export default function LinearSyntenyDisplayF(pluginManager) {
|
|
|
11
11
|
configSchema,
|
|
12
12
|
stateModel: stateModelFactory(configSchema),
|
|
13
13
|
trackType: 'SyntenyTrack',
|
|
14
|
-
viewType: '
|
|
14
|
+
viewType: 'LinearSyntenyViewHelper',
|
|
15
15
|
ReactComponent: lazy(() => import('./components/Component')),
|
|
16
16
|
});
|
|
17
17
|
});
|
|
@@ -24,7 +24,6 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
24
24
|
} & {
|
|
25
25
|
type: import("mobx-state-tree").ISimpleType<"LinearComparativeDisplay">;
|
|
26
26
|
configuration: AnyConfigurationSchemaType;
|
|
27
|
-
height: import("mobx-state-tree").IType<number | undefined, number, number>;
|
|
28
27
|
} & {
|
|
29
28
|
/**
|
|
30
29
|
* #property
|
|
@@ -69,7 +68,9 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
69
68
|
rendererTypeName: string;
|
|
70
69
|
error: unknown;
|
|
71
70
|
message: string | undefined;
|
|
72
|
-
} & import("mobx-state-tree"
|
|
71
|
+
} & import("mobx-state-tree" /**
|
|
72
|
+
* #action
|
|
73
|
+
*/).IStateTreeNode<import("mobx-state-tree").IModelType<{
|
|
73
74
|
id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
74
75
|
type: import("mobx-state-tree").ISimpleType<string>;
|
|
75
76
|
rpcDriverName: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<string>>;
|
|
@@ -77,9 +78,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
77
78
|
rendererTypeName: string;
|
|
78
79
|
error: unknown;
|
|
79
80
|
message: string | undefined;
|
|
80
|
-
}, import("mobx-state-tree"
|
|
81
|
-
* #action
|
|
82
|
-
*/)._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
81
|
+
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
83
82
|
}> | null;
|
|
84
83
|
readonly adapterConfig: any;
|
|
85
84
|
readonly parentTrack: any;
|
|
@@ -116,7 +115,6 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
116
115
|
} & import("mobx-state-tree/dist/internal").NonEmptyObject & any & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>);
|
|
117
116
|
} & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>);
|
|
118
117
|
} & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>;
|
|
119
|
-
height: number;
|
|
120
118
|
} & import("mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
121
119
|
rendererTypeName: string;
|
|
122
120
|
error: unknown;
|
|
@@ -152,7 +150,9 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
152
150
|
rendererTypeName: string;
|
|
153
151
|
error: unknown;
|
|
154
152
|
message: string | undefined;
|
|
155
|
-
} & import("mobx-state-tree"
|
|
153
|
+
} & import("mobx-state-tree" /**
|
|
154
|
+
* #action
|
|
155
|
+
*/).IStateTreeNode<import("mobx-state-tree").IModelType<{
|
|
156
156
|
id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
157
157
|
type: import("mobx-state-tree").ISimpleType<string>;
|
|
158
158
|
rpcDriverName: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<string>>;
|
|
@@ -160,9 +160,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
160
160
|
rendererTypeName: string;
|
|
161
161
|
error: unknown;
|
|
162
162
|
message: string | undefined;
|
|
163
|
-
}, import("mobx-state-tree"
|
|
164
|
-
* #action
|
|
165
|
-
*/)._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
163
|
+
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
166
164
|
}> | null;
|
|
167
165
|
readonly adapterConfig: any;
|
|
168
166
|
readonly parentTrack: any;
|
|
@@ -188,7 +186,6 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
188
186
|
} & {
|
|
189
187
|
type: import("mobx-state-tree").ISimpleType<"LinearComparativeDisplay">;
|
|
190
188
|
configuration: AnyConfigurationSchemaType;
|
|
191
|
-
height: import("mobx-state-tree").IType<number | undefined, number, number>;
|
|
192
189
|
}, {
|
|
193
190
|
rendererTypeName: string;
|
|
194
191
|
error: unknown;
|
|
@@ -314,6 +311,10 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
314
311
|
* #getter
|
|
315
312
|
*/
|
|
316
313
|
readonly trackIds: string[];
|
|
314
|
+
/**
|
|
315
|
+
* #getter
|
|
316
|
+
*/
|
|
317
|
+
readonly height: number;
|
|
317
318
|
/**
|
|
318
319
|
* #getter
|
|
319
320
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { types } from 'mobx-state-tree';
|
|
1
|
+
import { types, getParent } from 'mobx-state-tree';
|
|
2
2
|
import { getConf, ConfigurationReference, } from '@jbrowse/core/configuration';
|
|
3
3
|
// locals
|
|
4
4
|
import baseModelFactory from '../LinearComparativeDisplay/stateModelFactory';
|
|
@@ -111,6 +111,13 @@ function stateModelFactory(configSchema) {
|
|
|
111
111
|
get trackIds() {
|
|
112
112
|
return getConf(self, 'trackIds');
|
|
113
113
|
},
|
|
114
|
+
/**
|
|
115
|
+
* #getter
|
|
116
|
+
*/
|
|
117
|
+
get height() {
|
|
118
|
+
// @ts-expect-error
|
|
119
|
+
return getParent(self, 4).height;
|
|
120
|
+
},
|
|
114
121
|
/**
|
|
115
122
|
* #getter
|
|
116
123
|
*/
|
package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts}
RENAMED
|
@@ -2,10 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import { SnapshotIn } from 'mobx-state-tree';
|
|
3
3
|
import { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
4
4
|
type Conf = SnapshotIn<AnyConfigurationModel>;
|
|
5
|
-
declare const ImportCustomTrack: ({ assembly1, assembly2,
|
|
6
|
-
sessionTrackData: Conf;
|
|
5
|
+
declare const ImportCustomTrack: ({ assembly1, assembly2, setUserOpenedSyntenyTrack, }: {
|
|
7
6
|
assembly1: string;
|
|
8
7
|
assembly2: string;
|
|
9
|
-
|
|
8
|
+
setUserOpenedSyntenyTrack: (arg: Conf) => void;
|
|
10
9
|
}) => React.JSX.Element;
|
|
11
10
|
export default ImportCustomTrack;
|
package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js}
RENAMED
|
@@ -66,7 +66,7 @@ function getAdapter({ radioOption, assembly1, assembly2, fileLocation, indexFile
|
|
|
66
66
|
throw new Error(`Unknown to detect type ${radioOption} from filename (select radio button to clarify)`);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
const ImportCustomTrack = observer(function ({ assembly1, assembly2,
|
|
69
|
+
const ImportCustomTrack = observer(function ({ assembly1, assembly2, setUserOpenedSyntenyTrack, }) {
|
|
70
70
|
const [bed2Location, setBed2Location] = useState();
|
|
71
71
|
const [bed1Location, setBed1Location] = useState();
|
|
72
72
|
const [fileLocation, setFileLocation] = useState();
|
|
@@ -81,7 +81,7 @@ const ImportCustomTrack = observer(function ({ assembly1, assembly2, setSessionT
|
|
|
81
81
|
const fn = fileName ? basename(fileName) : 'MyTrack';
|
|
82
82
|
const trackId = `${fn}-${Date.now()}`;
|
|
83
83
|
setError(undefined);
|
|
84
|
-
|
|
84
|
+
setUserOpenedSyntenyTrack({
|
|
85
85
|
trackId,
|
|
86
86
|
name: fn,
|
|
87
87
|
assemblyNames: [assembly2, assembly1],
|
|
@@ -111,7 +111,7 @@ const ImportCustomTrack = observer(function ({ assembly1, assembly2, setSessionT
|
|
|
111
111
|
fileLocation,
|
|
112
112
|
indexFileLocation,
|
|
113
113
|
radioOption,
|
|
114
|
-
|
|
114
|
+
setUserOpenedSyntenyTrack,
|
|
115
115
|
]);
|
|
116
116
|
return (React.createElement(Paper, { style: { padding: 12 } },
|
|
117
117
|
error ? React.createElement(ErrorMessage, { error: error }) : null,
|