@jbrowse/plugin-linear-comparative-view 2.15.4 → 2.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LGVSyntenyDisplay/components/LaunchSyntenyViewDialog.d.ts +2 -1
- package/dist/LGVSyntenyDisplay/components/LaunchSyntenyViewDialog.js +4 -2
- package/dist/LGVSyntenyDisplay/components/util.d.ts +4 -1
- package/dist/LGVSyntenyDisplay/components/util.js +7 -15
- package/dist/LGVSyntenyDisplay/model.d.ts +26 -14
- package/dist/LGVSyntenyDisplay/model.js +23 -1
- package/dist/LaunchLinearSyntenyView.js +41 -11
- package/dist/LinearComparativeDisplay/stateModelFactory.d.ts +42 -14
- package/dist/LinearComparativeDisplay/stateModelFactory.js +20 -10
- 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 -4
- package/dist/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +47 -32
- package/dist/LinearSyntenyDisplay/components/SyntenyContextMenu.js +10 -6
- package/dist/LinearSyntenyDisplay/components/util.d.ts +7 -2
- package/dist/LinearSyntenyDisplay/components/util.js +12 -14
- package/dist/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
- package/dist/LinearSyntenyDisplay/drawSynteny.js +29 -25
- package/dist/LinearSyntenyDisplay/index.js +1 -1
- package/dist/LinearSyntenyDisplay/model.d.ts +48 -10
- package/dist/LinearSyntenyDisplay/model.js +38 -15
- 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/SyntenyFeatureDetail/SyntenyFeatureDetail.d.ts +14 -0
- package/dist/SyntenyFeatureDetail/SyntenyFeatureDetail.js +100 -0
- package/dist/SyntenyFeatureDetail/index.d.ts +2 -0
- package/dist/SyntenyFeatureDetail/index.js +56 -0
- package/dist/index.js +4 -0
- package/esm/LGVSyntenyDisplay/components/LaunchSyntenyViewDialog.d.ts +2 -1
- package/esm/LGVSyntenyDisplay/components/LaunchSyntenyViewDialog.js +4 -2
- package/esm/LGVSyntenyDisplay/components/util.d.ts +4 -1
- package/esm/LGVSyntenyDisplay/components/util.js +8 -16
- package/esm/LGVSyntenyDisplay/model.d.ts +26 -14
- package/esm/LGVSyntenyDisplay/model.js +25 -3
- package/esm/LaunchLinearSyntenyView.js +41 -11
- package/esm/LinearComparativeDisplay/stateModelFactory.d.ts +42 -14
- package/esm/LinearComparativeDisplay/stateModelFactory.js +21 -11
- 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 +5 -4
- package/esm/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +48 -33
- package/esm/LinearSyntenyDisplay/components/SyntenyContextMenu.js +10 -6
- package/esm/LinearSyntenyDisplay/components/util.d.ts +7 -2
- package/esm/LinearSyntenyDisplay/components/util.js +12 -14
- package/esm/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
- package/esm/LinearSyntenyDisplay/drawSynteny.js +29 -25
- package/esm/LinearSyntenyDisplay/index.js +1 -1
- package/esm/LinearSyntenyDisplay/model.d.ts +48 -10
- package/esm/LinearSyntenyDisplay/model.js +38 -15
- 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/SyntenyFeatureDetail/SyntenyFeatureDetail.d.ts +14 -0
- package/esm/SyntenyFeatureDetail/SyntenyFeatureDetail.js +72 -0
- package/esm/SyntenyFeatureDetail/index.d.ts +2 -0
- package/esm/SyntenyFeatureDetail/index.js +27 -0
- package/esm/index.js +4 -0
- package/package.json +3 -3
- 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,23 @@ const useStyles = makeStyles()({
|
|
|
17
17
|
rel: {
|
|
18
18
|
position: 'relative',
|
|
19
19
|
},
|
|
20
|
-
|
|
20
|
+
mouseoverCanvas: {
|
|
21
|
+
imageRendering: 'pixelated',
|
|
21
22
|
position: 'absolute',
|
|
22
|
-
},
|
|
23
|
-
none: {
|
|
24
23
|
pointEvents: 'none',
|
|
25
24
|
},
|
|
25
|
+
mainCanvas: {
|
|
26
|
+
position: 'absolute',
|
|
27
|
+
},
|
|
26
28
|
});
|
|
27
29
|
const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
28
|
-
const { classes
|
|
30
|
+
const { classes } = useStyles();
|
|
31
|
+
const { mouseoverId, height } = model;
|
|
29
32
|
const xOffset = useRef(0);
|
|
30
|
-
const currScrollFrame = useRef();
|
|
31
33
|
const view = getContainingView(model);
|
|
32
|
-
const height = view.middleComparativeHeight;
|
|
33
34
|
const width = view.width;
|
|
34
35
|
const delta = useRef(0);
|
|
36
|
+
const scheduled = useRef(false);
|
|
35
37
|
const timeout = useRef();
|
|
36
38
|
const [anchorEl, setAnchorEl] = useState();
|
|
37
39
|
const [tooltip, setTooltip] = useState('');
|
|
@@ -39,18 +41,25 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
39
41
|
const [mouseCurrDownX, setMouseCurrDownX] = useState();
|
|
40
42
|
const [mouseInitialDownX, setMouseInitialDownX] = useState();
|
|
41
43
|
const [currY, setCurrY] = useState();
|
|
42
|
-
const
|
|
44
|
+
const mainSyntenyCanvasRefp = useRef();
|
|
43
45
|
// these useCallbacks avoid new refs from being created on any mouseover,
|
|
44
46
|
// etc.
|
|
45
47
|
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
46
|
-
const
|
|
48
|
+
const mouseoverDetectionCanvasRef = useCallback((ref) => {
|
|
47
49
|
model.setMouseoverCanvasRef(ref);
|
|
48
50
|
},
|
|
49
51
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
50
52
|
[model, height, width]);
|
|
51
53
|
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
52
|
-
const
|
|
54
|
+
const mainSyntenyCanvasRef = useCallback((ref) => {
|
|
53
55
|
model.setMainCanvasRef(ref);
|
|
56
|
+
mainSyntenyCanvasRefp.current = ref; // this ref is additionally used in useEffect below
|
|
57
|
+
},
|
|
58
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59
|
+
[model, height, width]);
|
|
60
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
var _a;
|
|
54
63
|
function onWheel(event) {
|
|
55
64
|
event.preventDefault();
|
|
56
65
|
if (event.ctrlKey) {
|
|
@@ -62,11 +71,14 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
62
71
|
clearTimeout(timeout.current);
|
|
63
72
|
}
|
|
64
73
|
timeout.current = setTimeout(() => {
|
|
74
|
+
var _a;
|
|
65
75
|
for (const v of view.views) {
|
|
66
76
|
v.setScaleFactor(1);
|
|
67
77
|
v.zoomTo(delta.current > 0
|
|
68
78
|
? v.bpPerPx * (1 + delta.current)
|
|
69
|
-
: v.bpPerPx / (1 - delta.current), event.clientX -
|
|
79
|
+
: v.bpPerPx / (1 - delta.current), event.clientX -
|
|
80
|
+
(((_a = mainSyntenyCanvasRefp.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().left) ||
|
|
81
|
+
0));
|
|
70
82
|
}
|
|
71
83
|
delta.current = 0;
|
|
72
84
|
}, 300);
|
|
@@ -75,56 +87,55 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
75
87
|
if (Math.abs(event.deltaY) < Math.abs(event.deltaX)) {
|
|
76
88
|
xOffset.current += event.deltaX / 2;
|
|
77
89
|
}
|
|
78
|
-
if (
|
|
79
|
-
|
|
90
|
+
if (!scheduled.current) {
|
|
91
|
+
scheduled.current = true;
|
|
92
|
+
window.requestAnimationFrame(() => {
|
|
80
93
|
transaction(() => {
|
|
81
94
|
for (const v of view.views) {
|
|
82
95
|
v.horizontalScroll(xOffset.current);
|
|
83
96
|
}
|
|
84
97
|
xOffset.current = 0;
|
|
85
|
-
|
|
98
|
+
scheduled.current = false;
|
|
86
99
|
});
|
|
87
100
|
});
|
|
88
101
|
}
|
|
89
102
|
}
|
|
90
103
|
}
|
|
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
|
|
104
|
+
(_a = mainSyntenyCanvasRefp.current) === null || _a === void 0 ? void 0 : _a.addEventListener('wheel', onWheel);
|
|
95
105
|
return () => {
|
|
96
|
-
|
|
106
|
+
var _a;
|
|
107
|
+
(_a = mainSyntenyCanvasRefp.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('wheel', onWheel);
|
|
97
108
|
};
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
[model, height, width]);
|
|
109
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
110
|
+
}, [model, height, width]);
|
|
101
111
|
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
102
|
-
const
|
|
112
|
+
const clickMapCanvasRef = useCallback((ref) => {
|
|
103
113
|
model.setClickMapCanvasRef(ref);
|
|
104
114
|
},
|
|
105
115
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
106
116
|
[model, height, width]);
|
|
107
117
|
// biome-ignore lint/correctness/useExhaustiveDependencies:
|
|
108
|
-
const
|
|
118
|
+
const cigarClickMapCanvasRef = useCallback((ref) => {
|
|
109
119
|
model.setCigarClickMapCanvasRef(ref);
|
|
110
120
|
},
|
|
111
121
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
112
122
|
[model, height, width]);
|
|
113
123
|
return (React.createElement("div", { className: classes.rel },
|
|
114
|
-
React.createElement("canvas", { ref:
|
|
115
|
-
React.createElement("canvas", { ref:
|
|
124
|
+
React.createElement("canvas", { ref: mouseoverDetectionCanvasRef, width: width, height: height, className: classes.mouseoverCanvas }),
|
|
125
|
+
React.createElement("canvas", { ref: mainSyntenyCanvasRef, onMouseMove: event => {
|
|
116
126
|
var _a;
|
|
117
127
|
if (mouseCurrDownX !== undefined) {
|
|
118
128
|
xOffset.current += mouseCurrDownX - event.clientX;
|
|
119
129
|
setMouseCurrDownX(event.clientX);
|
|
120
|
-
if (
|
|
121
|
-
|
|
130
|
+
if (!scheduled.current) {
|
|
131
|
+
scheduled.current = true;
|
|
132
|
+
window.requestAnimationFrame(() => {
|
|
122
133
|
transaction(() => {
|
|
123
134
|
for (const v of view.views) {
|
|
124
135
|
v.horizontalScroll(xOffset.current);
|
|
125
136
|
}
|
|
126
137
|
xOffset.current = 0;
|
|
127
|
-
|
|
138
|
+
scheduled.current = false;
|
|
128
139
|
});
|
|
129
140
|
});
|
|
130
141
|
}
|
|
@@ -158,7 +169,11 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
158
169
|
const { f, cigar } = model.featPositions[id];
|
|
159
170
|
const unitMultiplier2 = Math.floor(MAX_COLOR_RANGE / cigar.length);
|
|
160
171
|
const cigarIdx = getId(r2, g2, b2, unitMultiplier2);
|
|
161
|
-
setTooltip(getTooltip(
|
|
172
|
+
setTooltip(getTooltip({
|
|
173
|
+
feature: f,
|
|
174
|
+
cigarOp: cigar[cigarIdx],
|
|
175
|
+
cigarOpLen: cigar[cigarIdx + 1],
|
|
176
|
+
}));
|
|
162
177
|
}
|
|
163
178
|
}
|
|
164
179
|
}, onMouseLeave: () => {
|
|
@@ -176,9 +191,9 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
|
|
|
176
191
|
}
|
|
177
192
|
}, onContextMenu: evt => {
|
|
178
193
|
onSynContextClick(evt, model, setAnchorEl);
|
|
179
|
-
}, "data-testid": "synteny_canvas", className: classes.
|
|
180
|
-
React.createElement("canvas", { ref:
|
|
181
|
-
React.createElement("canvas", { ref:
|
|
194
|
+
}, "data-testid": "synteny_canvas", className: classes.mainCanvas, width: width, height: height }),
|
|
195
|
+
React.createElement("canvas", { ref: clickMapCanvasRef, className: classes.pix, width: width, height: height }),
|
|
196
|
+
React.createElement("canvas", { ref: cigarClickMapCanvasRef, className: classes.pix, width: width, height: height }),
|
|
182
197
|
mouseoverId && tooltip && currX && currY ? (React.createElement(SyntenyTooltip, { title: tooltip })) : null,
|
|
183
198
|
anchorEl ? (React.createElement(SyntenyContextMenu, { model: model, anchorEl: anchorEl, onClose: () => {
|
|
184
199
|
setAnchorEl(undefined);
|
|
@@ -33,13 +33,17 @@ export default function SyntenyContextMenu({ model, onClose, anchorEl, }) {
|
|
|
33
33
|
const end = f.get('end');
|
|
34
34
|
const refName = f.get('refName');
|
|
35
35
|
const mate = f.get('mate');
|
|
36
|
-
view.views[
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const l1 = view.views[model.level];
|
|
37
|
+
const l2 = view.views[model.level + 1];
|
|
38
|
+
l1.navToLocString(`${refName}:${start}-${end}`).catch((e) => {
|
|
39
|
+
const err = `${l1.assemblyNames[0]}:${e}`;
|
|
40
|
+
console.error(err);
|
|
41
|
+
getSession(model).notifyError(err, e);
|
|
39
42
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
l2.navToLocString(`${mate.refName}:${mate.start}-${mate.end}`).catch((e) => {
|
|
44
|
+
const err = `${l2.assemblyNames[0]}:${e}`;
|
|
45
|
+
console.error(err);
|
|
46
|
+
getSession(model).notifyError(err, e);
|
|
43
47
|
});
|
|
44
48
|
},
|
|
45
49
|
},
|
|
@@ -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;
|
|
@@ -35,5 +36,9 @@ export declare function drawBox(ctx: CanvasRenderingContext2D, x1: number, x2: n
|
|
|
35
36
|
export declare function drawBezierBox(ctx: CanvasRenderingContext2D, x1: number, x2: number, y1: number, x3: number, x4: number, y2: number, mid: number): void;
|
|
36
37
|
export declare function onSynClick(event: React.MouseEvent, model: LinearSyntenyDisplayModel): import("../model").FeatPos | undefined;
|
|
37
38
|
export declare function onSynContextClick(event: React.MouseEvent, model: LinearSyntenyDisplayModel, setAnchorEl: (arg: ClickCoord) => void): void;
|
|
38
|
-
export declare function getTooltip(
|
|
39
|
+
export declare function getTooltip({ feature, cigarOp, cigarOpLen, }: {
|
|
40
|
+
feature: Feature;
|
|
41
|
+
cigarOp?: string;
|
|
42
|
+
cigarOpLen?: string;
|
|
43
|
+
}): string;
|
|
39
44
|
export {};
|
|
@@ -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;
|
|
@@ -54,7 +54,6 @@ export function drawBox(ctx, x1, x2, y1, x3, x4, y2) {
|
|
|
54
54
|
ctx.lineTo(x3, y2);
|
|
55
55
|
ctx.lineTo(x4, y2);
|
|
56
56
|
ctx.closePath();
|
|
57
|
-
ctx.fill();
|
|
58
57
|
}
|
|
59
58
|
export function drawBezierBox(ctx, x1, x2, y1, x3, x4, y2, mid) {
|
|
60
59
|
const len1 = Math.abs(x1 - x2);
|
|
@@ -74,13 +73,11 @@ export function drawBezierBox(ctx, x1, x2, y1, x3, x4, y2, mid) {
|
|
|
74
73
|
ctx.lineTo(x4, y2);
|
|
75
74
|
ctx.bezierCurveTo(x4, mid, x1, mid, x1, y1);
|
|
76
75
|
ctx.closePath();
|
|
77
|
-
ctx.fill();
|
|
78
76
|
}
|
|
79
77
|
export function onSynClick(event, model) {
|
|
80
78
|
const view = getContainingView(model);
|
|
81
79
|
const track = getContainingTrack(model);
|
|
82
|
-
const ref1 = model
|
|
83
|
-
const ref2 = model.cigarClickMapCanvas;
|
|
80
|
+
const { featPositions, numFeats, clickMapCanvas: ref1, cigarClickMapCanvas: ref2, level, } = model;
|
|
84
81
|
if (!ref1 || !ref2) {
|
|
85
82
|
return;
|
|
86
83
|
}
|
|
@@ -93,18 +90,19 @@ export function onSynClick(event, model) {
|
|
|
93
90
|
const x = event.clientX - rect.left;
|
|
94
91
|
const y = event.clientY - rect.top;
|
|
95
92
|
const [r1, g1, b1] = ctx1.getImageData(x, y, 1, 1).data;
|
|
96
|
-
const unitMultiplier = Math.floor(MAX_COLOR_RANGE /
|
|
93
|
+
const unitMultiplier = Math.floor(MAX_COLOR_RANGE / numFeats);
|
|
97
94
|
const id = getId(r1, g1, b1, unitMultiplier);
|
|
98
|
-
const feat =
|
|
95
|
+
const feat = featPositions[id];
|
|
99
96
|
if (feat) {
|
|
100
97
|
const { f } = feat;
|
|
101
98
|
model.setClickId(f.id());
|
|
102
99
|
const session = getSession(model);
|
|
103
100
|
if (isSessionModelWithWidgets(session)) {
|
|
104
|
-
session.showWidget(session.addWidget('
|
|
101
|
+
session.showWidget(session.addWidget('SyntenyFeatureWidget', 'syntenyFeature', {
|
|
105
102
|
view,
|
|
106
103
|
track,
|
|
107
104
|
featureData: f.toJSON(),
|
|
105
|
+
level,
|
|
108
106
|
}));
|
|
109
107
|
}
|
|
110
108
|
}
|
|
@@ -135,9 +133,9 @@ export function onSynContextClick(event, model, setAnchorEl) {
|
|
|
135
133
|
setAnchorEl({ clientX, clientY, feature: f });
|
|
136
134
|
}
|
|
137
135
|
}
|
|
138
|
-
export function getTooltip(
|
|
136
|
+
export function getTooltip({ feature, cigarOp, cigarOpLen, }) {
|
|
139
137
|
// @ts-expect-error
|
|
140
|
-
const f1 =
|
|
138
|
+
const f1 = feature.toJSON();
|
|
141
139
|
const f2 = f1.mate;
|
|
142
140
|
const l1 = f1.end - f1.start;
|
|
143
141
|
const l2 = f2.end - f2.start;
|
|
@@ -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;
|
|
@@ -25,25 +25,24 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
25
25
|
const view = getContainingView(model);
|
|
26
26
|
const drawCurves = view.drawCurves;
|
|
27
27
|
const drawCIGAR = view.drawCIGAR;
|
|
28
|
-
const height =
|
|
28
|
+
const { level, height, featPositions } = model;
|
|
29
29
|
const width = view.width;
|
|
30
30
|
const bpPerPxs = view.views.map(v => v.bpPerPx);
|
|
31
31
|
if (ctx3) {
|
|
32
32
|
ctx3.imageSmoothingEnabled = false;
|
|
33
33
|
}
|
|
34
34
|
ctx1.beginPath();
|
|
35
|
-
const featPos = model.featPositions;
|
|
36
35
|
const offsets = view.views.map(v => v.offsetPx);
|
|
37
|
-
const unitMultiplier = Math.floor(MAX_COLOR_RANGE /
|
|
36
|
+
const unitMultiplier = Math.floor(MAX_COLOR_RANGE / featPositions.length);
|
|
38
37
|
// this loop is optimized to draw many thin lines with a single ctx.stroke
|
|
39
38
|
// call, a separate loop below draws larger boxes
|
|
40
39
|
ctx1.fillStyle = colorMap.M;
|
|
41
40
|
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];
|
|
41
|
+
for (const { p11, p12, p21, p22 } of featPositions) {
|
|
42
|
+
const x11 = p11.offsetPx - offsets[level];
|
|
43
|
+
const x12 = p12.offsetPx - offsets[level];
|
|
44
|
+
const x21 = p21.offsetPx - offsets[level + 1];
|
|
45
|
+
const x22 = p22.offsetPx - offsets[level + 1];
|
|
47
46
|
const l1 = Math.abs(x12 - x11);
|
|
48
47
|
const l2 = Math.abs(x22 - x21);
|
|
49
48
|
const y1 = 0;
|
|
@@ -69,11 +68,11 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
69
68
|
// ctx.stroke once is much more efficient than calling stroke() many times
|
|
70
69
|
ctx1.fillStyle = colorMap.M;
|
|
71
70
|
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];
|
|
71
|
+
for (const { p11, p12, p21, p22, f, cigar } of featPositions) {
|
|
72
|
+
const x11 = p11.offsetPx - offsets[level];
|
|
73
|
+
const x12 = p12.offsetPx - offsets[level];
|
|
74
|
+
const x21 = p21.offsetPx - offsets[level + 1];
|
|
75
|
+
const x22 = p22.offsetPx - offsets[level + 1];
|
|
77
76
|
const l1 = Math.abs(x12 - x11);
|
|
78
77
|
const l2 = Math.abs(x22 - x21);
|
|
79
78
|
const minX = Math.min(x21, x22);
|
|
@@ -108,8 +107,8 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
108
107
|
px1 = cx1;
|
|
109
108
|
px2 = cx2;
|
|
110
109
|
}
|
|
111
|
-
const d1 = len / bpPerPxs[
|
|
112
|
-
const d2 = len / bpPerPxs[1];
|
|
110
|
+
const d1 = len / bpPerPxs[level];
|
|
111
|
+
const d2 = len / bpPerPxs[level + 1];
|
|
113
112
|
if (op === 'M' || op === '=' || op === 'X') {
|
|
114
113
|
cx1 += d1 * rev1;
|
|
115
114
|
cx2 += d2 * rev2;
|
|
@@ -135,16 +134,18 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
135
134
|
continuingFlag = true;
|
|
136
135
|
}
|
|
137
136
|
else {
|
|
138
|
-
// allow rendering the dominant color when using continuing
|
|
139
|
-
// if the last element of continuing was a large
|
|
140
|
-
// just use match
|
|
137
|
+
// allow rendering the dominant color when using continuing
|
|
138
|
+
// flag if the last element of continuing was a large
|
|
139
|
+
// feature, else just use match
|
|
141
140
|
ctx1.fillStyle =
|
|
142
141
|
colorMap[(continuingFlag && d1 > 1) || d2 > 1 ? op : 'M'];
|
|
143
142
|
continuingFlag = false;
|
|
144
143
|
draw(ctx1, px1, cx1, y1, cx2, px2, y2, mid, drawCurves);
|
|
144
|
+
ctx1.fill();
|
|
145
145
|
if (ctx3) {
|
|
146
146
|
ctx3.fillStyle = makeColor(idx);
|
|
147
147
|
draw(ctx3, px1, cx1, y1, cx2, px2, y2, mid, drawCurves);
|
|
148
|
+
ctx3.fill();
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
151
|
}
|
|
@@ -152,6 +153,7 @@ export function drawRef(model, ctx1, ctx3) {
|
|
|
152
153
|
}
|
|
153
154
|
else {
|
|
154
155
|
draw(ctx1, x11, x12, y1, x22, x21, y2, mid, drawCurves);
|
|
156
|
+
ctx1.fill();
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
159
|
}
|
|
@@ -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,15 +184,14 @@ 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;
|
|
188
|
-
const { clickId, mouseoverId } = model;
|
|
190
|
+
const { level, clickId, mouseoverId } = 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);
|
|
@@ -199,14 +201,16 @@ export function drawMouseoverSynteny(model) {
|
|
|
199
201
|
ctx.resetTransform();
|
|
200
202
|
ctx.scale(highResolutionScaling, highResolutionScaling);
|
|
201
203
|
ctx.clearRect(0, 0, width, height);
|
|
204
|
+
ctx.strokeStyle = 'rgba(0, 0, 0, 0.9)';
|
|
205
|
+
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
|
|
202
206
|
const feature1 = model.featMap[mouseoverId || ''];
|
|
203
207
|
if (feature1) {
|
|
204
|
-
ctx.fillStyle = 'rgb(0,0,0,0.1)';
|
|
205
208
|
drawMatchSimple({
|
|
206
209
|
cb: ctx => {
|
|
207
210
|
ctx.fill();
|
|
208
211
|
},
|
|
209
212
|
feature: feature1,
|
|
213
|
+
level,
|
|
210
214
|
ctx,
|
|
211
215
|
oobLimit,
|
|
212
216
|
viewWidth: view.width,
|
|
@@ -217,13 +221,13 @@ export function drawMouseoverSynteny(model) {
|
|
|
217
221
|
}
|
|
218
222
|
const feature2 = model.featMap[clickId || ''];
|
|
219
223
|
if (feature2) {
|
|
220
|
-
ctx.strokeStyle = 'rgb(0, 0, 0, 0.9)';
|
|
221
224
|
drawMatchSimple({
|
|
222
225
|
cb: ctx => {
|
|
223
226
|
ctx.stroke();
|
|
224
227
|
},
|
|
225
228
|
feature: feature2,
|
|
226
229
|
ctx,
|
|
230
|
+
level,
|
|
227
231
|
oobLimit,
|
|
228
232
|
viewWidth: view.width,
|
|
229
233
|
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
|
|
@@ -77,9 +76,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
77
76
|
rendererTypeName: string;
|
|
78
77
|
error: unknown;
|
|
79
78
|
message: string | undefined;
|
|
80
|
-
}, import("mobx-state-tree"
|
|
81
|
-
* #action
|
|
82
|
-
*/)._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
79
|
+
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
83
80
|
}> | null;
|
|
84
81
|
readonly adapterConfig: any;
|
|
85
82
|
readonly parentTrack: any;
|
|
@@ -99,6 +96,8 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
99
96
|
features: Feature[] | undefined;
|
|
100
97
|
message: string | undefined;
|
|
101
98
|
} & {
|
|
99
|
+
readonly level: number;
|
|
100
|
+
readonly height: number;
|
|
102
101
|
renderProps(): {
|
|
103
102
|
rpcDriverName: string | undefined;
|
|
104
103
|
displayModel: {
|
|
@@ -114,9 +113,13 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
114
113
|
setSubschema(slotName: string, data: Record<string, unknown>): Record<string, unknown> | ({
|
|
115
114
|
[x: string]: any;
|
|
116
115
|
} & import("mobx-state-tree/dist/internal").NonEmptyObject & any & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>);
|
|
117
|
-
} & import("mobx-state-tree"
|
|
116
|
+
} & import("mobx-state-tree" /**
|
|
117
|
+
* #volatile
|
|
118
|
+
* canvas for drawing mouseover shading this is separate from the other
|
|
119
|
+
* code for speed: don't have to redraw entire canvas to do a feature's
|
|
120
|
+
* mouseover shading
|
|
121
|
+
*/).IStateTreeNode<AnyConfigurationSchemaType>);
|
|
118
122
|
} & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>;
|
|
119
|
-
height: number;
|
|
120
123
|
} & import("mobx-state-tree/dist/internal").NonEmptyObject & {
|
|
121
124
|
rendererTypeName: string;
|
|
122
125
|
error: unknown;
|
|
@@ -160,9 +163,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
160
163
|
rendererTypeName: string;
|
|
161
164
|
error: unknown;
|
|
162
165
|
message: string | undefined;
|
|
163
|
-
}, import("mobx-state-tree"
|
|
164
|
-
* #action
|
|
165
|
-
*/)._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
166
|
+
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
166
167
|
}> | null;
|
|
167
168
|
readonly adapterConfig: any;
|
|
168
169
|
readonly parentTrack: any;
|
|
@@ -188,7 +189,6 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
188
189
|
} & {
|
|
189
190
|
type: import("mobx-state-tree").ISimpleType<"LinearComparativeDisplay">;
|
|
190
191
|
configuration: AnyConfigurationSchemaType;
|
|
191
|
-
height: import("mobx-state-tree").IType<number | undefined, number, number>;
|
|
192
192
|
}, {
|
|
193
193
|
rendererTypeName: string;
|
|
194
194
|
error: unknown;
|
|
@@ -264,13 +264,51 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
264
264
|
} & {
|
|
265
265
|
afterAttach(): void;
|
|
266
266
|
} & {
|
|
267
|
+
/**
|
|
268
|
+
* #volatile
|
|
269
|
+
* canvas used for drawing visible screen
|
|
270
|
+
*/
|
|
267
271
|
mainCanvas: HTMLCanvasElement | null;
|
|
272
|
+
/**
|
|
273
|
+
* #volatile
|
|
274
|
+
* canvas used for drawing click map with feature ids this renders a
|
|
275
|
+
* unique color per alignment, so that it can be re-traced after a
|
|
276
|
+
* feature click with getImageData at that pixel
|
|
277
|
+
*/
|
|
268
278
|
clickMapCanvas: HTMLCanvasElement | null;
|
|
279
|
+
/**
|
|
280
|
+
* #volatile
|
|
281
|
+
* canvas used for drawing click map with cigar data this can show if you
|
|
282
|
+
* are mousing over a insertion/deletion. it is similar in purpose to the
|
|
283
|
+
* clickMapRef but was not feasible to pack this into the clickMapRef
|
|
284
|
+
*/
|
|
269
285
|
cigarClickMapCanvas: HTMLCanvasElement | null;
|
|
286
|
+
/**
|
|
287
|
+
* #volatile
|
|
288
|
+
* canvas for drawing mouseover shading this is separate from the other
|
|
289
|
+
* code for speed: don't have to redraw entire canvas to do a feature's
|
|
290
|
+
* mouseover shading
|
|
291
|
+
*/
|
|
270
292
|
mouseoverCanvas: HTMLCanvasElement | null;
|
|
293
|
+
/**
|
|
294
|
+
* #volatile
|
|
295
|
+
* assigned by reaction
|
|
296
|
+
*/
|
|
271
297
|
featPositions: FeatPos[];
|
|
298
|
+
/**
|
|
299
|
+
* #volatile
|
|
300
|
+
* currently mouse'd over feature
|
|
301
|
+
*/
|
|
272
302
|
mouseoverId: string | undefined;
|
|
303
|
+
/**
|
|
304
|
+
* #volatile
|
|
305
|
+
* currently click'd over feature
|
|
306
|
+
*/
|
|
273
307
|
clickId: string | undefined;
|
|
308
|
+
/**
|
|
309
|
+
* #volatile
|
|
310
|
+
* currently mouseover'd CIGAR subfeature
|
|
311
|
+
*/
|
|
274
312
|
cigarMouseoverId: number;
|
|
275
313
|
} & {
|
|
276
314
|
/**
|
|
@@ -20,28 +20,51 @@ function stateModelFactory(configSchema) {
|
|
|
20
20
|
configuration: ConfigurationReference(configSchema),
|
|
21
21
|
}))
|
|
22
22
|
.volatile(() => ({
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* #volatile
|
|
25
|
+
* canvas used for drawing visible screen
|
|
26
|
+
*/
|
|
24
27
|
mainCanvas: null,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
/**
|
|
29
|
+
* #volatile
|
|
30
|
+
* canvas used for drawing click map with feature ids this renders a
|
|
31
|
+
* unique color per alignment, so that it can be re-traced after a
|
|
32
|
+
* feature click with getImageData at that pixel
|
|
33
|
+
*/
|
|
28
34
|
clickMapCanvas: null,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
/**
|
|
36
|
+
* #volatile
|
|
37
|
+
* canvas used for drawing click map with cigar data this can show if you
|
|
38
|
+
* are mousing over a insertion/deletion. it is similar in purpose to the
|
|
39
|
+
* clickMapRef but was not feasible to pack this into the clickMapRef
|
|
40
|
+
*/
|
|
33
41
|
cigarClickMapCanvas: null,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
/**
|
|
43
|
+
* #volatile
|
|
44
|
+
* canvas for drawing mouseover shading this is separate from the other
|
|
45
|
+
* code for speed: don't have to redraw entire canvas to do a feature's
|
|
46
|
+
* mouseover shading
|
|
47
|
+
*/
|
|
37
48
|
mouseoverCanvas: null,
|
|
38
|
-
|
|
49
|
+
/**
|
|
50
|
+
* #volatile
|
|
51
|
+
* assigned by reaction
|
|
52
|
+
*/
|
|
39
53
|
featPositions: [],
|
|
40
|
-
|
|
54
|
+
/**
|
|
55
|
+
* #volatile
|
|
56
|
+
* currently mouse'd over feature
|
|
57
|
+
*/
|
|
41
58
|
mouseoverId: undefined,
|
|
42
|
-
|
|
59
|
+
/**
|
|
60
|
+
* #volatile
|
|
61
|
+
* currently click'd over feature
|
|
62
|
+
*/
|
|
43
63
|
clickId: undefined,
|
|
44
|
-
|
|
64
|
+
/**
|
|
65
|
+
* #volatile
|
|
66
|
+
* currently mouseover'd CIGAR subfeature
|
|
67
|
+
*/
|
|
45
68
|
cigarMouseoverId: -1,
|
|
46
69
|
}))
|
|
47
70
|
.actions(self => ({
|