@jbrowse/plugin-breakpoint-split-view 2.15.0 → 2.15.2
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/BreakpointSplitView/BreakpointSplitView.d.ts +29 -1
- package/dist/BreakpointSplitView/BreakpointSplitView.js +71 -32
- package/dist/BreakpointSplitView/components/AlignmentConnections.js +43 -12
- package/dist/BreakpointSplitView/components/BreakpointSplitView.js +12 -10
- package/dist/BreakpointSplitView/components/BreakpointSplitViewOverlay.js +6 -5
- package/dist/BreakpointSplitView/components/Overlay.js +8 -3
- package/dist/BreakpointSplitView/components/PairedFeatures.d.ts +9 -0
- package/dist/BreakpointSplitView/components/PairedFeatures.js +100 -0
- package/dist/BreakpointSplitView/components/getOrientationColor.d.ts +41 -0
- package/dist/BreakpointSplitView/components/getOrientationColor.js +111 -0
- package/dist/BreakpointSplitView/components/util.d.ts +1 -0
- package/dist/BreakpointSplitView/components/util.js +26 -0
- package/dist/BreakpointSplitView/model.d.ts +24 -5
- package/dist/BreakpointSplitView/model.js +35 -7
- package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +5 -8
- package/dist/BreakpointSplitView/util.d.ts +1 -0
- package/dist/BreakpointSplitView/util.js +1 -0
- package/esm/BreakpointSplitView/BreakpointSplitView.d.ts +29 -1
- package/esm/BreakpointSplitView/BreakpointSplitView.js +71 -32
- package/esm/BreakpointSplitView/components/AlignmentConnections.js +44 -13
- package/esm/BreakpointSplitView/components/BreakpointSplitView.js +11 -9
- package/esm/BreakpointSplitView/components/BreakpointSplitViewOverlay.js +6 -5
- package/esm/BreakpointSplitView/components/Overlay.js +8 -3
- package/esm/BreakpointSplitView/components/PairedFeatures.d.ts +9 -0
- package/esm/BreakpointSplitView/components/PairedFeatures.js +75 -0
- package/esm/BreakpointSplitView/components/getOrientationColor.d.ts +41 -0
- package/esm/BreakpointSplitView/components/getOrientationColor.js +103 -0
- package/esm/BreakpointSplitView/components/util.d.ts +1 -0
- package/esm/BreakpointSplitView/components/util.js +25 -0
- package/esm/BreakpointSplitView/model.d.ts +24 -5
- package/esm/BreakpointSplitView/model.js +35 -7
- package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +5 -8
- package/esm/BreakpointSplitView/util.d.ts +1 -0
- package/esm/BreakpointSplitView/util.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React, { useState, useMemo } from 'react';
|
|
2
|
+
import { getSession } from '@jbrowse/core/util';
|
|
3
|
+
import { observer } from 'mobx-react';
|
|
4
|
+
import { getSnapshot } from 'mobx-state-tree';
|
|
5
|
+
// locals
|
|
6
|
+
import { getMatchedPairedFeatures } from './util';
|
|
7
|
+
import { yPos, getPxFromCoordinate, useNextFrame } from '../util';
|
|
8
|
+
const [LEFT] = [0, 1, 2, 3];
|
|
9
|
+
const PairedFeatures = observer(function ({ model, trackId, parentRef: ref, getTrackYPosOverride, }) {
|
|
10
|
+
const { views } = model;
|
|
11
|
+
const session = getSession(model);
|
|
12
|
+
const { assemblyManager } = session;
|
|
13
|
+
const totalFeatures = model.getTrackFeatures(trackId);
|
|
14
|
+
const layoutMatches = useMemo(() => model.getMatchedFeaturesInLayout(trackId, getMatchedPairedFeatures(totalFeatures)), [totalFeatures, trackId, model]);
|
|
15
|
+
const [mouseoverElt, setMouseoverElt] = useState();
|
|
16
|
+
const snap = getSnapshot(model);
|
|
17
|
+
useNextFrame(snap);
|
|
18
|
+
const assembly = assemblyManager.get(views[0].assemblyNames[0]);
|
|
19
|
+
if (!assembly) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
let yoff = 0;
|
|
23
|
+
if (ref.current) {
|
|
24
|
+
const rect = ref.current.getBoundingClientRect();
|
|
25
|
+
yoff = rect.top;
|
|
26
|
+
}
|
|
27
|
+
return (React.createElement("g", { stroke: "green", strokeWidth: 5, fill: "none", "data-testid": layoutMatches.length ? `${trackId}-loaded` : trackId }, layoutMatches.map(chunk => {
|
|
28
|
+
const ret = [];
|
|
29
|
+
// we follow a path in the list of chunks, not from top to bottom, just
|
|
30
|
+
// in series following x1,y1 -> x2,y2
|
|
31
|
+
for (let i = 0; i < chunk.length - 1; i += 1) {
|
|
32
|
+
const { layout: c1, feature: f1, level: level1 } = chunk[i];
|
|
33
|
+
const { layout: c2, feature: f2, level: level2 } = chunk[i + 1];
|
|
34
|
+
const id = f1.id();
|
|
35
|
+
if (!c1 || !c2) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const f1origref = f1.get('refName');
|
|
39
|
+
const f2origref = f2.get('refName');
|
|
40
|
+
const f1ref = assembly.getCanonicalRefName(f1origref);
|
|
41
|
+
const f2ref = assembly.getCanonicalRefName(f2origref);
|
|
42
|
+
if (!f1ref || !f2ref) {
|
|
43
|
+
throw new Error(`unable to find ref for ${f1ref || f2ref}`);
|
|
44
|
+
}
|
|
45
|
+
const x1 = getPxFromCoordinate(views[level1], f1ref, c1[LEFT]);
|
|
46
|
+
const x2 = getPxFromCoordinate(views[level2], f2ref, c2[LEFT]);
|
|
47
|
+
const tracks = views.map(v => v.getTrack(trackId));
|
|
48
|
+
const y1 = yPos(trackId, level1, views, tracks, c1, getTrackYPosOverride) -
|
|
49
|
+
yoff;
|
|
50
|
+
const y2 = yPos(trackId, level2, views, tracks, c2, getTrackYPosOverride) -
|
|
51
|
+
yoff;
|
|
52
|
+
const path = [
|
|
53
|
+
'M', // move to
|
|
54
|
+
x1,
|
|
55
|
+
y1,
|
|
56
|
+
'L', // line to
|
|
57
|
+
x2,
|
|
58
|
+
y2,
|
|
59
|
+
].join(' ');
|
|
60
|
+
ret.push(React.createElement("path", { d: path, "data-testid": "r2", key: JSON.stringify(path), strokeWidth: id === mouseoverElt ? 10 : 5, onClick: () => {
|
|
61
|
+
var _a, _b, _c;
|
|
62
|
+
const featureWidget = (_a = session.addWidget) === null || _a === void 0 ? void 0 : _a.call(session, 'VariantFeatureWidget', 'variantFeature', {
|
|
63
|
+
featureData: (_b = totalFeatures.get(id)) === null || _b === void 0 ? void 0 : _b.toJSON(),
|
|
64
|
+
});
|
|
65
|
+
(_c = session.showWidget) === null || _c === void 0 ? void 0 : _c.call(session, featureWidget);
|
|
66
|
+
}, onMouseOver: () => {
|
|
67
|
+
setMouseoverElt(id);
|
|
68
|
+
}, onMouseOut: () => {
|
|
69
|
+
setMouseoverElt(undefined);
|
|
70
|
+
} }));
|
|
71
|
+
}
|
|
72
|
+
return ret;
|
|
73
|
+
})));
|
|
74
|
+
});
|
|
75
|
+
export default PairedFeatures;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare const orientationTypes: {
|
|
2
|
+
fr: Record<string, string>;
|
|
3
|
+
rf: Record<string, string>;
|
|
4
|
+
ff: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
export declare const pairMap: {
|
|
7
|
+
readonly LR: "color_pair_lr";
|
|
8
|
+
readonly LL: "color_pair_ll";
|
|
9
|
+
readonly RR: "color_pair_rr";
|
|
10
|
+
readonly RL: "color_pair_rl";
|
|
11
|
+
};
|
|
12
|
+
export declare const strokeColor: {
|
|
13
|
+
color_fwd_strand_not_proper: string;
|
|
14
|
+
color_rev_strand_not_proper: string;
|
|
15
|
+
color_fwd_strand: string;
|
|
16
|
+
color_rev_strand: string;
|
|
17
|
+
color_fwd_missing_mate: string;
|
|
18
|
+
color_rev_missing_mate: string;
|
|
19
|
+
color_fwd_diff_chr: string;
|
|
20
|
+
color_rev_diff_chr: string;
|
|
21
|
+
color_pair_lr: string;
|
|
22
|
+
color_pair_rr: string;
|
|
23
|
+
color_pair_rl: string;
|
|
24
|
+
color_pair_ll: string;
|
|
25
|
+
color_nostrand: string;
|
|
26
|
+
color_interchrom: string;
|
|
27
|
+
color_longinsert: string;
|
|
28
|
+
color_shortinsert: string;
|
|
29
|
+
color_unknown: string;
|
|
30
|
+
};
|
|
31
|
+
export declare function getPairedOrientationColorOrDefault(f: {
|
|
32
|
+
pair_orientation?: string;
|
|
33
|
+
}): string | undefined;
|
|
34
|
+
export declare function getLongReadOrientationColorOrDefault(s1: number, s2: number): string;
|
|
35
|
+
export declare function getLongReadOrientationAbnormal(s1: number, s2: number): boolean;
|
|
36
|
+
export declare function isAbnormalOrientation(f: {
|
|
37
|
+
pair_orientation?: string;
|
|
38
|
+
}): boolean;
|
|
39
|
+
export declare function getPairedOrientationColor(f: {
|
|
40
|
+
pair_orientation?: string;
|
|
41
|
+
}): string;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { alpha } from '@mui/material';
|
|
2
|
+
// orientation definitions from igv.js, see also
|
|
3
|
+
// https://software.broadinstitute.org/software/igv/interpreting_pair_orientations
|
|
4
|
+
export const orientationTypes = {
|
|
5
|
+
fr: {
|
|
6
|
+
F1R2: 'LR',
|
|
7
|
+
F2R1: 'LR',
|
|
8
|
+
F1F2: 'LL',
|
|
9
|
+
F2F1: 'LL',
|
|
10
|
+
R1R2: 'RR',
|
|
11
|
+
R2R1: 'RR',
|
|
12
|
+
R1F2: 'RL',
|
|
13
|
+
R2F1: 'RL',
|
|
14
|
+
},
|
|
15
|
+
rf: {
|
|
16
|
+
R1F2: 'LR',
|
|
17
|
+
R2F1: 'LR',
|
|
18
|
+
R1R2: 'LL',
|
|
19
|
+
R2R1: 'LL',
|
|
20
|
+
F1F2: 'RR',
|
|
21
|
+
F2F1: 'RR',
|
|
22
|
+
F1R2: 'RL',
|
|
23
|
+
F2R1: 'RL',
|
|
24
|
+
},
|
|
25
|
+
ff: {
|
|
26
|
+
F2F1: 'LR',
|
|
27
|
+
R1R2: 'LR',
|
|
28
|
+
F2R1: 'LL',
|
|
29
|
+
R1F2: 'LL',
|
|
30
|
+
R2F1: 'RR',
|
|
31
|
+
F1R2: 'RR',
|
|
32
|
+
R2R1: 'RL',
|
|
33
|
+
F1F2: 'RL',
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
export const pairMap = {
|
|
37
|
+
LR: 'color_pair_lr',
|
|
38
|
+
LL: 'color_pair_ll',
|
|
39
|
+
RR: 'color_pair_rr',
|
|
40
|
+
RL: 'color_pair_rl',
|
|
41
|
+
};
|
|
42
|
+
// manually calculated by running
|
|
43
|
+
// const color = require('color')
|
|
44
|
+
// Object.fromEntries(Object.entries(fillColor).map(([key,val])=>{
|
|
45
|
+
// return [key, color(val).darken('0.3').hex()]
|
|
46
|
+
// }))
|
|
47
|
+
// this avoids (expensive) use of Color module at runtime
|
|
48
|
+
export const strokeColor = {
|
|
49
|
+
color_fwd_strand_not_proper: alpha('#CA6767', 0.8),
|
|
50
|
+
color_rev_strand_not_proper: alpha('#7272AA', 0.8),
|
|
51
|
+
color_fwd_strand: alpha('#DC2A2A', 0.8),
|
|
52
|
+
color_rev_strand: alpha('#4141BA', 0.8),
|
|
53
|
+
color_fwd_missing_mate: alpha('#921111', 0.8),
|
|
54
|
+
color_rev_missing_mate: alpha('#111192', 0.8),
|
|
55
|
+
color_fwd_diff_chr: alpha('#000000', 0.8),
|
|
56
|
+
color_rev_diff_chr: alpha('#696969', 0.8),
|
|
57
|
+
color_pair_lr: alpha('#8C8C8C', 0.8),
|
|
58
|
+
color_pair_rr: alpha('#00005A', 0.8),
|
|
59
|
+
color_pair_rl: alpha('#005A5A', 0.8),
|
|
60
|
+
color_pair_ll: alpha('#005A00', 0.8),
|
|
61
|
+
color_nostrand: alpha('#8C8C8C', 0.8),
|
|
62
|
+
color_interchrom: alpha('#5A005A', 0.8),
|
|
63
|
+
color_longinsert: alpha('#B30000', 0.8),
|
|
64
|
+
color_shortinsert: alpha('#FF3A5C', 0.8),
|
|
65
|
+
color_unknown: alpha('#555', 0.8),
|
|
66
|
+
};
|
|
67
|
+
const defaultColor = strokeColor.color_unknown;
|
|
68
|
+
export function getPairedOrientationColorOrDefault(f) {
|
|
69
|
+
const type = orientationTypes.fr;
|
|
70
|
+
const r = type[f.pair_orientation || ''];
|
|
71
|
+
const type2 = pairMap[r];
|
|
72
|
+
return r === 'LR' ? undefined : strokeColor[type2];
|
|
73
|
+
}
|
|
74
|
+
export function getLongReadOrientationColorOrDefault(s1, s2) {
|
|
75
|
+
if (s1 === -1 && s2 === 1) {
|
|
76
|
+
return strokeColor.color_pair_rr;
|
|
77
|
+
}
|
|
78
|
+
else if (s1 === 1 && s2 === -1) {
|
|
79
|
+
return strokeColor.color_pair_ll;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
return strokeColor.color_unknown;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function getLongReadOrientationAbnormal(s1, s2) {
|
|
86
|
+
if (s1 === -1 && s2 === 1) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
else if (s1 === 1 && s2 === -1) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export function isAbnormalOrientation(f) {
|
|
97
|
+
const type = orientationTypes.fr;
|
|
98
|
+
const r = type[f.pair_orientation || ''];
|
|
99
|
+
return r !== 'LR';
|
|
100
|
+
}
|
|
101
|
+
export function getPairedOrientationColor(f) {
|
|
102
|
+
return getPairedOrientationColorOrDefault(f) || defaultColor;
|
|
103
|
+
}
|
|
@@ -5,3 +5,4 @@ export declare function hasPairedReads(features: Map<string, Feature>): boolean;
|
|
|
5
5
|
export declare function findMatchingAlt(feat1: Feature, feat2: Feature): import("@gmod/vcf").Breakend | undefined;
|
|
6
6
|
export declare function getMatchedBreakendFeatures(feats: Map<string, Feature>): Feature[][];
|
|
7
7
|
export declare function getMatchedTranslocationFeatures(feats: Map<string, Feature>): Feature[][];
|
|
8
|
+
export declare function getMatchedPairedFeatures(feats: Map<string, Feature>): Feature[][];
|
|
@@ -107,3 +107,28 @@ export function getMatchedTranslocationFeatures(feats) {
|
|
|
107
107
|
}
|
|
108
108
|
return ret;
|
|
109
109
|
}
|
|
110
|
+
// Getting "matched" TRA means just return all TRA
|
|
111
|
+
export function getMatchedPairedFeatures(feats) {
|
|
112
|
+
const candidates = new Map();
|
|
113
|
+
const alreadySeen = new Set();
|
|
114
|
+
for (const f of feats.values()) {
|
|
115
|
+
if (!alreadySeen.has(f.id()) && f.get('type') === 'paired_feature') {
|
|
116
|
+
const r1 = f.id().replace('-r1', '');
|
|
117
|
+
const r2 = f.id().replace('-r2', '');
|
|
118
|
+
if (f.id().endsWith('-r1')) {
|
|
119
|
+
if (!candidates.get(r1)) {
|
|
120
|
+
candidates.set(r1, []);
|
|
121
|
+
}
|
|
122
|
+
candidates.get(r1).push(f);
|
|
123
|
+
}
|
|
124
|
+
else if (f.id().endsWith('-r2')) {
|
|
125
|
+
if (!candidates.get(r2)) {
|
|
126
|
+
candidates.set(r2, []);
|
|
127
|
+
}
|
|
128
|
+
candidates.get(r2).push(f);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
alreadySeen.add(f.id());
|
|
132
|
+
}
|
|
133
|
+
return [...candidates.values()].filter(v => v.length > 1);
|
|
134
|
+
}
|
|
@@ -282,9 +282,14 @@ export default function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
282
282
|
} & {
|
|
283
283
|
/**
|
|
284
284
|
* #getter
|
|
285
|
-
* Find all track ids that match across multiple views
|
|
285
|
+
* Find all track ids that match across multiple views, or return just
|
|
286
|
+
* the single view's track if only a single row is used
|
|
286
287
|
*/
|
|
287
|
-
readonly matchedTracks:
|
|
288
|
+
readonly matchedTracks: (import("mobx-state-tree").IMSTArray<import("mobx-state-tree").IAnyType> & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IArrayType<import("mobx-state-tree").IAnyType>>) | {
|
|
289
|
+
configuration: {
|
|
290
|
+
trackId: string;
|
|
291
|
+
};
|
|
292
|
+
}[];
|
|
288
293
|
/**
|
|
289
294
|
* #method
|
|
290
295
|
* Get tracks with a given trackId across multiple views
|
|
@@ -292,11 +297,15 @@ export default function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
292
297
|
getMatchedTracks(trackConfigId: string): any[];
|
|
293
298
|
/**
|
|
294
299
|
* #method
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
* since they do not have a mate e.g. they are one sided
|
|
300
|
+
* Translocation features are handled differently since they do not have
|
|
301
|
+
* a mate e.g. they are one sided
|
|
298
302
|
*/
|
|
299
303
|
hasTranslocations(trackConfigId: string): Feature | undefined;
|
|
304
|
+
/**
|
|
305
|
+
* #method
|
|
306
|
+
* Paired features similar to breakends, but simpler, like BEDPE
|
|
307
|
+
*/
|
|
308
|
+
hasPairedFeatures(trackConfigId: string): Feature | undefined;
|
|
300
309
|
/**
|
|
301
310
|
* #method
|
|
302
311
|
* Get a composite map of featureId-\>feature map for a track across
|
|
@@ -338,6 +347,10 @@ export default function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
338
347
|
* #action
|
|
339
348
|
*/
|
|
340
349
|
setMatchedTrackFeatures(obj: Record<string, Feature[][]>): void;
|
|
350
|
+
/**
|
|
351
|
+
* #action
|
|
352
|
+
*/
|
|
353
|
+
reverseViewOrder(): void;
|
|
341
354
|
} & {
|
|
342
355
|
afterAttach(): void;
|
|
343
356
|
/**
|
|
@@ -346,6 +359,12 @@ export default function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
346
359
|
menuItems(): ({
|
|
347
360
|
label: string;
|
|
348
361
|
subMenu: import("@jbrowse/core/ui").MenuItem[];
|
|
362
|
+
} | {
|
|
363
|
+
label: string;
|
|
364
|
+
onClick: () => void;
|
|
365
|
+
type?: undefined;
|
|
366
|
+
checked?: undefined;
|
|
367
|
+
icon?: undefined;
|
|
349
368
|
} | {
|
|
350
369
|
label: string;
|
|
351
370
|
type: string;
|
|
@@ -17,9 +17,13 @@ function calc(track, f) {
|
|
|
17
17
|
return (_b = (_a = track.displays[0]).searchFeatureByID) === null || _b === void 0 ? void 0 : _b.call(_a, f.id());
|
|
18
18
|
}
|
|
19
19
|
async function getBlockFeatures(model, track) {
|
|
20
|
+
var _a;
|
|
20
21
|
const { views } = model;
|
|
21
22
|
const { rpcManager, assemblyManager } = getSession(model);
|
|
22
|
-
const assemblyName = model.views[0].assemblyNames[0];
|
|
23
|
+
const assemblyName = (_a = model.views[0]) === null || _a === void 0 ? void 0 : _a.assemblyNames[0];
|
|
24
|
+
if (!assemblyName) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
23
27
|
const assembly = await assemblyManager.waitForAssembly(assemblyName);
|
|
24
28
|
if (!assembly) {
|
|
25
29
|
return undefined; // throw new Error(`assembly not found: "${assemblyName}"`)
|
|
@@ -90,10 +94,13 @@ export default function stateModelFactory(pluginManager) {
|
|
|
90
94
|
.views(self => ({
|
|
91
95
|
/**
|
|
92
96
|
* #getter
|
|
93
|
-
* Find all track ids that match across multiple views
|
|
97
|
+
* Find all track ids that match across multiple views, or return just
|
|
98
|
+
* the single view's track if only a single row is used
|
|
94
99
|
*/
|
|
95
100
|
get matchedTracks() {
|
|
96
|
-
return
|
|
101
|
+
return self.views.length === 1
|
|
102
|
+
? self.views[0].tracks
|
|
103
|
+
: intersect(elt => elt.configuration.trackId, ...self.views.map(view => view.tracks));
|
|
97
104
|
},
|
|
98
105
|
/**
|
|
99
106
|
* #method
|
|
@@ -106,13 +113,19 @@ export default function stateModelFactory(pluginManager) {
|
|
|
106
113
|
},
|
|
107
114
|
/**
|
|
108
115
|
* #method
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* since they do not have a mate e.g. they are one sided
|
|
116
|
+
* Translocation features are handled differently since they do not have
|
|
117
|
+
* a mate e.g. they are one sided
|
|
112
118
|
*/
|
|
113
119
|
hasTranslocations(trackConfigId) {
|
|
114
120
|
return [...this.getTrackFeatures(trackConfigId).values()].find(f => f.get('type') === 'translocation');
|
|
115
121
|
},
|
|
122
|
+
/**
|
|
123
|
+
* #method
|
|
124
|
+
* Paired features similar to breakends, but simpler, like BEDPE
|
|
125
|
+
*/
|
|
126
|
+
hasPairedFeatures(trackConfigId) {
|
|
127
|
+
return [...this.getTrackFeatures(trackConfigId).values()].find(f => f.get('type') === 'paired_feature');
|
|
128
|
+
},
|
|
116
129
|
/**
|
|
117
130
|
* #method
|
|
118
131
|
* Get a composite map of featureId-\>feature map for a track across
|
|
@@ -210,6 +223,12 @@ export default function stateModelFactory(pluginManager) {
|
|
|
210
223
|
setMatchedTrackFeatures(obj) {
|
|
211
224
|
self.matchedTrackFeatures = obj;
|
|
212
225
|
},
|
|
226
|
+
/**
|
|
227
|
+
* #action
|
|
228
|
+
*/
|
|
229
|
+
reverseViewOrder() {
|
|
230
|
+
self.views.reverse();
|
|
231
|
+
},
|
|
213
232
|
}))
|
|
214
233
|
.actions(self => ({
|
|
215
234
|
afterAttach() {
|
|
@@ -236,7 +255,16 @@ export default function stateModelFactory(pluginManager) {
|
|
|
236
255
|
return [
|
|
237
256
|
...self.views
|
|
238
257
|
.map((view, idx) => [idx, view.menuItems()])
|
|
239
|
-
.map(f => ({
|
|
258
|
+
.map(f => ({
|
|
259
|
+
label: `Row ${f[0] + 1} view menu`,
|
|
260
|
+
subMenu: f[1],
|
|
261
|
+
})),
|
|
262
|
+
{
|
|
263
|
+
label: 'Reverse view order',
|
|
264
|
+
onClick: () => {
|
|
265
|
+
self.reverseViewOrder();
|
|
266
|
+
},
|
|
267
|
+
},
|
|
240
268
|
{
|
|
241
269
|
label: 'Show intra-view links',
|
|
242
270
|
type: 'checkbox',
|
|
@@ -32,10 +32,7 @@ export async function renderToSvg(model, opts) {
|
|
|
32
32
|
const trackLabelMaxLen = getTrackNameMaxLen(views, fontSize, session) + 40;
|
|
33
33
|
const trackLabelOffset = trackLabels === 'left' ? trackLabelMaxLen : 0;
|
|
34
34
|
const textOffset = trackLabels === 'offset' ? textHeight : 0;
|
|
35
|
-
const trackOffsets = [
|
|
36
|
-
getTrackOffsets(views[0], textOffset, fontSize + offset),
|
|
37
|
-
getTrackOffsets(views[1], textOffset, fontSize + heights[0] + offset),
|
|
38
|
-
];
|
|
35
|
+
const trackOffsets = views.map((view, idx) => getTrackOffsets(view, textOffset, fontSize + (idx > 0 ? heights[idx - 1] : 0) + offset));
|
|
39
36
|
const w = width + trackLabelOffset;
|
|
40
37
|
const t = createJBrowseTheme(theme);
|
|
41
38
|
// the xlink namespace is used for rendering <image> tag
|
|
@@ -43,16 +40,16 @@ export async function renderToSvg(model, opts) {
|
|
|
43
40
|
React.createElement(Wrapper, null,
|
|
44
41
|
React.createElement("svg", { width: width, height: totalHeightSvg, xmlns: "http://www.w3.org/2000/svg", xmlnsXlink: "http://www.w3.org/1999/xlink", viewBox: [0, 0, w + shift * 2, totalHeightSvg].toString() },
|
|
45
42
|
React.createElement(SVGBackground, { width: w, height: totalHeightSvg, shift: shift }),
|
|
46
|
-
React.createElement("g", { transform: `translate(${shift} ${fontSize})` },
|
|
43
|
+
views[0] ? (React.createElement("g", { transform: `translate(${shift} ${fontSize})` },
|
|
47
44
|
React.createElement("g", { transform: `translate(${trackLabelOffset})` },
|
|
48
45
|
React.createElement("text", { x: 0, fontSize: fontSize, fill: t.palette.text.primary }, views[0].assemblyNames.join(', ')),
|
|
49
46
|
React.createElement(SVGRuler, { model: displayResults[0].view, fontSize: fontSize })),
|
|
50
|
-
React.createElement(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults[0].view, displayResults: displayResults[0].data, offset: offset, trackLabelOffset: trackLabelOffset })),
|
|
51
|
-
React.createElement("g", { transform: `translate(${shift} ${fontSize + heights[0]})` },
|
|
47
|
+
React.createElement(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults[0].view, displayResults: displayResults[0].data, offset: offset, trackLabelOffset: trackLabelOffset }))) : null,
|
|
48
|
+
views[1] ? (React.createElement("g", { transform: `translate(${shift} ${fontSize + heights[0]})` },
|
|
52
49
|
React.createElement("g", { transform: `translate(${trackLabelOffset})` },
|
|
53
50
|
React.createElement("text", { x: 0, fontSize: fontSize, fill: t.palette.text.primary }, views[1].assemblyNames.join(', ')),
|
|
54
51
|
React.createElement(SVGRuler, { model: displayResults[1].view, fontSize: fontSize })),
|
|
55
|
-
React.createElement(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults[1].view, displayResults: displayResults[1].data, offset: offset, trackLabelOffset: trackLabelOffset })),
|
|
52
|
+
React.createElement(SVGTracks, { textHeight: textHeight, trackLabels: trackLabels, fontSize: fontSize, model: displayResults[1].view, displayResults: displayResults[1].data, offset: offset, trackLabelOffset: trackLabelOffset }))) : null,
|
|
56
53
|
React.createElement("defs", null,
|
|
57
54
|
React.createElement("clipPath", { id: "clip-bsv" },
|
|
58
55
|
React.createElement("rect", { x: 0, y: 0, width: width, height: totalHeightSvg }))),
|
|
@@ -11,6 +11,7 @@ interface Display {
|
|
|
11
11
|
interface Track {
|
|
12
12
|
displays: Display[];
|
|
13
13
|
}
|
|
14
|
+
export declare function heightFromSpecificLevel(views: LGV[], trackId: string, level: number, getYPosOverride?: (trackId: string, level: number) => number): number;
|
|
14
15
|
export declare function getPxFromCoordinate(view: LGV, refName: string, coord: number): number;
|
|
15
16
|
export declare function yPos(trackId: string, level: number, views: LGV[], tracks: Track[], c: LayoutRecord, getYPosOverride?: (trackId: string, level: number) => number): number;
|
|
16
17
|
export declare const useNextFrame: (variable: unknown) => void;
|
|
@@ -4,7 +4,7 @@ const [, TOP, , BOTTOM] = [0, 1, 2, 3];
|
|
|
4
4
|
function cheight(chunk) {
|
|
5
5
|
return chunk[BOTTOM] - chunk[TOP];
|
|
6
6
|
}
|
|
7
|
-
function heightFromSpecificLevel(views, trackId, level, getYPosOverride) {
|
|
7
|
+
export function heightFromSpecificLevel(views, trackId, level, getYPosOverride) {
|
|
8
8
|
var _a;
|
|
9
9
|
return getYPosOverride
|
|
10
10
|
? getYPosOverride(trackId, level)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-breakpoint-split-view",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.2",
|
|
4
4
|
"description": "JBrowse 2 breakpoint detail split view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -58,5 +58,5 @@
|
|
|
58
58
|
"publishConfig": {
|
|
59
59
|
"access": "public"
|
|
60
60
|
},
|
|
61
|
-
"gitHead": "
|
|
61
|
+
"gitHead": "8a58cefbfe39af4c97bcb6ead354d72c9fef9224"
|
|
62
62
|
}
|