@jbrowse/plugin-wiggle 2.6.3 → 2.7.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/CreateMultiWiggleExtension/index.js +14 -11
- package/dist/DensityRenderer/DensityRenderer.js +2 -2
- package/dist/LinePlotRenderer/LinePlotRenderer.js +2 -2
- package/dist/LinearWiggleDisplay/components/SetColorDialog.d.ts +6 -7
- package/dist/LinearWiggleDisplay/components/SetColorDialog.js +3 -3
- package/dist/LinearWiggleDisplay/components/Tooltip.js +1 -1
- package/dist/MultiDensityRenderer/MultiDensityRenderer.js +5 -8
- package/dist/MultiLineRenderer/MultiLineRenderer.js +5 -9
- package/dist/MultiLinearWiggleDisplay/components/DraggableDialog.d.ts +3 -4
- package/dist/MultiLinearWiggleDisplay/components/DraggableDialog.js +3 -3
- package/dist/MultiLinearWiggleDisplay/components/SetColorDialog.js +2 -96
- package/dist/MultiLinearWiggleDisplay/components/SourcesGrid.d.ts +8 -0
- package/dist/MultiLinearWiggleDisplay/components/SourcesGrid.js +138 -0
- package/dist/MultiLinearWiggleDisplay/components/Tooltip.d.ts +3 -2
- package/dist/MultiLinearWiggleDisplay/components/Tooltip.js +1 -1
- package/dist/MultiLinearWiggleDisplay/components/WiggleDisplayComponent.d.ts +2 -3
- package/dist/MultiLinearWiggleDisplay/components/WiggleDisplayComponent.js +2 -4
- package/dist/MultiLinearWiggleDisplay/components/util.js +2 -4
- package/dist/MultiRowLineRenderer/MultiRowLineRenderer.js +5 -5
- package/dist/MultiRowXYPlotRenderer/MultiRowXYPlotRenderer.js +5 -34
- package/dist/MultiWiggleAddTrackWidget/AddTrackWorkflow.js +16 -12
- package/dist/MultiWiggleRendering.d.ts +3 -4
- package/dist/MultiWiggleRendering.js +7 -5
- package/dist/MultiXYPlotRenderer/MultiXYPlotRenderer.js +5 -33
- package/dist/Tooltip.d.ts +5 -6
- package/dist/Tooltip.js +3 -3
- package/dist/WiggleRendering.d.ts +3 -4
- package/dist/WiggleRendering.js +3 -3
- package/dist/XYPlotRenderer/XYPlotRenderer.js +2 -27
- package/dist/drawDensity.d.ts +17 -0
- package/dist/drawDensity.js +66 -0
- package/dist/drawLine.d.ts +19 -0
- package/dist/drawLine.js +73 -0
- package/dist/drawXY.d.ts +19 -0
- package/dist/drawXY.js +164 -0
- package/dist/shared/YScaleBar.d.ts +2 -2
- package/dist/shared/YScaleBar.js +2 -1
- package/dist/shared/modelShared.d.ts +4 -1
- package/dist/util.d.ts +1 -0
- package/dist/util.js +17 -1
- package/esm/CreateMultiWiggleExtension/index.js +14 -11
- package/esm/DensityRenderer/DensityRenderer.js +1 -1
- package/esm/LinePlotRenderer/LinePlotRenderer.js +1 -1
- package/esm/LinearWiggleDisplay/components/SetColorDialog.d.ts +6 -7
- package/esm/LinearWiggleDisplay/components/SetColorDialog.js +3 -3
- package/esm/LinearWiggleDisplay/components/Tooltip.js +1 -1
- package/esm/MultiDensityRenderer/MultiDensityRenderer.js +4 -7
- package/esm/MultiLineRenderer/MultiLineRenderer.js +4 -8
- package/esm/MultiLinearWiggleDisplay/components/DraggableDialog.d.ts +3 -4
- package/esm/MultiLinearWiggleDisplay/components/DraggableDialog.js +3 -3
- package/esm/MultiLinearWiggleDisplay/components/SetColorDialog.js +2 -96
- package/esm/MultiLinearWiggleDisplay/components/SourcesGrid.d.ts +8 -0
- package/esm/MultiLinearWiggleDisplay/components/SourcesGrid.js +110 -0
- package/esm/MultiLinearWiggleDisplay/components/Tooltip.d.ts +3 -2
- package/esm/MultiLinearWiggleDisplay/components/Tooltip.js +1 -1
- package/esm/MultiLinearWiggleDisplay/components/WiggleDisplayComponent.d.ts +2 -3
- package/esm/MultiLinearWiggleDisplay/components/WiggleDisplayComponent.js +2 -2
- package/esm/MultiLinearWiggleDisplay/components/util.js +2 -4
- package/esm/MultiRowLineRenderer/MultiRowLineRenderer.js +4 -4
- package/esm/MultiRowXYPlotRenderer/MultiRowXYPlotRenderer.js +4 -10
- package/esm/MultiWiggleAddTrackWidget/AddTrackWorkflow.js +17 -13
- package/esm/MultiWiggleRendering.d.ts +3 -4
- package/esm/MultiWiggleRendering.js +7 -5
- package/esm/MultiXYPlotRenderer/MultiXYPlotRenderer.js +4 -9
- package/esm/Tooltip.d.ts +5 -6
- package/esm/Tooltip.js +3 -3
- package/esm/WiggleRendering.d.ts +3 -4
- package/esm/WiggleRendering.js +3 -3
- package/esm/XYPlotRenderer/XYPlotRenderer.js +1 -3
- package/esm/drawDensity.d.ts +17 -0
- package/esm/drawDensity.js +62 -0
- package/esm/drawLine.d.ts +19 -0
- package/esm/drawLine.js +69 -0
- package/esm/drawXY.d.ts +19 -0
- package/esm/{drawxy.js → drawXY.js} +17 -140
- package/esm/shared/YScaleBar.d.ts +2 -2
- package/esm/shared/YScaleBar.js +2 -1
- package/esm/shared/modelShared.d.ts +4 -1
- package/esm/util.d.ts +1 -0
- package/esm/util.js +15 -0
- package/package.json +3 -4
- package/dist/drawxy.d.ts +0 -50
- package/dist/drawxy.js +0 -289
- package/esm/drawxy.d.ts +0 -50
package/dist/drawXY.js
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.drawXY = void 0;
|
|
4
|
+
const configuration_1 = require("@jbrowse/core/configuration");
|
|
5
|
+
const colord_1 = require("@jbrowse/core/util/colord");
|
|
6
|
+
const util_1 = require("@jbrowse/core/util");
|
|
7
|
+
// locals
|
|
8
|
+
const util_2 = require("./util");
|
|
9
|
+
function lighten(color, amount) {
|
|
10
|
+
const hslColor = color.toHsl();
|
|
11
|
+
const l = hslColor.l * (1 + amount);
|
|
12
|
+
return (0, colord_1.colord)({ ...hslColor, l: (0, util_1.clamp)(l, 0, 100) });
|
|
13
|
+
}
|
|
14
|
+
function darken(color, amount) {
|
|
15
|
+
const hslColor = color.toHsl();
|
|
16
|
+
const l = hslColor.l * (1 - amount);
|
|
17
|
+
return (0, colord_1.colord)({ ...hslColor, l: (0, util_1.clamp)(l, 0, 100) });
|
|
18
|
+
}
|
|
19
|
+
const fudgeFactor = 0.3;
|
|
20
|
+
const clipHeight = 2;
|
|
21
|
+
function drawXY(ctx, props) {
|
|
22
|
+
const { features, bpPerPx, regions, scaleOpts, height: unadjustedHeight, config, ticks, displayCrossHatches, offset = 0, colorCallback, } = props;
|
|
23
|
+
const [region] = regions;
|
|
24
|
+
const width = (region.end - region.start) / bpPerPx;
|
|
25
|
+
// the adjusted height takes into account YSCALEBAR_LABEL_OFFSET from the
|
|
26
|
+
// wiggle display, and makes the height of the actual drawn area add
|
|
27
|
+
// "padding" to the top and bottom of the display
|
|
28
|
+
const height = unadjustedHeight - offset * 2;
|
|
29
|
+
const filled = (0, configuration_1.readConfObject)(config, 'filled');
|
|
30
|
+
const clipColor = (0, configuration_1.readConfObject)(config, 'clipColor');
|
|
31
|
+
const summaryScoreMode = (0, configuration_1.readConfObject)(config, 'summaryScoreMode');
|
|
32
|
+
const pivotValue = (0, configuration_1.readConfObject)(config, 'bicolorPivotValue');
|
|
33
|
+
const minSize = (0, configuration_1.readConfObject)(config, 'minSize');
|
|
34
|
+
const scale = (0, util_2.getScale)({ ...scaleOpts, range: [0, height] });
|
|
35
|
+
const originY = (0, util_2.getOrigin)(scaleOpts.scaleType);
|
|
36
|
+
const [niceMin, niceMax] = scale.domain();
|
|
37
|
+
const toY = (n) => (0, util_1.clamp)(height - (scale(n) || 0), 0, height) + offset;
|
|
38
|
+
const toOrigin = (n) => toY(originY) - toY(n);
|
|
39
|
+
const getHeight = (n) => (filled ? toOrigin(n) : Math.max(minSize, 1));
|
|
40
|
+
let hasClipping = false;
|
|
41
|
+
let prevLeftPx = -Infinity;
|
|
42
|
+
const reducedFeatures = [];
|
|
43
|
+
const crossingOrigin = niceMin < pivotValue && niceMax > pivotValue;
|
|
44
|
+
// we handle whiskers separately to render max row, min row, and avg in three
|
|
45
|
+
// passes. this reduces subpixel rendering issues. note: for stylistic
|
|
46
|
+
// reasons, clipping indicator is only drawn for score, not min/max score
|
|
47
|
+
if (summaryScoreMode === 'whiskers') {
|
|
48
|
+
let lastCol;
|
|
49
|
+
let lastMix;
|
|
50
|
+
for (const feature of features.values()) {
|
|
51
|
+
const [leftPx, rightPx] = (0, util_1.featureSpanPx)(feature, region, bpPerPx);
|
|
52
|
+
if (feature.get('summary')) {
|
|
53
|
+
const w = Math.max(rightPx - leftPx + fudgeFactor, minSize);
|
|
54
|
+
const max = feature.get('maxScore');
|
|
55
|
+
const c = colorCallback(feature, max);
|
|
56
|
+
const effectiveC = crossingOrigin
|
|
57
|
+
? c
|
|
58
|
+
: c === lastCol
|
|
59
|
+
? lastMix
|
|
60
|
+
: (lastMix = lighten((0, colord_1.colord)(c), 0.4).toHex());
|
|
61
|
+
(0, util_2.fillRectCtx)(leftPx, toY(max), w, getHeight(max), ctx, effectiveC);
|
|
62
|
+
lastCol = c;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
lastMix = undefined;
|
|
66
|
+
lastCol = undefined;
|
|
67
|
+
for (const feature of features.values()) {
|
|
68
|
+
const [leftPx, rightPx] = (0, util_1.featureSpanPx)(feature, region, bpPerPx);
|
|
69
|
+
const score = feature.get('score');
|
|
70
|
+
const max = feature.get('maxScore');
|
|
71
|
+
const min = feature.get('minScore');
|
|
72
|
+
const summary = feature.get('summary');
|
|
73
|
+
const c = colorCallback(feature, score);
|
|
74
|
+
const effectiveC = crossingOrigin && summary
|
|
75
|
+
? c === lastCol
|
|
76
|
+
? lastMix
|
|
77
|
+
: (lastMix = (0, colord_1.colord)(colorCallback(feature, max))
|
|
78
|
+
.mix((0, colord_1.colord)(colorCallback(feature, min)))
|
|
79
|
+
.toString())
|
|
80
|
+
: c;
|
|
81
|
+
const w = Math.max(rightPx - leftPx + fudgeFactor, minSize);
|
|
82
|
+
// create reduced features, avoiding multiple features per px
|
|
83
|
+
if (Math.floor(leftPx) !== Math.floor(prevLeftPx)) {
|
|
84
|
+
reducedFeatures.push(feature);
|
|
85
|
+
prevLeftPx = leftPx;
|
|
86
|
+
}
|
|
87
|
+
hasClipping = hasClipping || score < niceMin || score > niceMax;
|
|
88
|
+
(0, util_2.fillRectCtx)(leftPx, toY(score), w, getHeight(score), ctx, effectiveC);
|
|
89
|
+
lastCol = c;
|
|
90
|
+
}
|
|
91
|
+
lastMix = undefined;
|
|
92
|
+
lastCol = undefined;
|
|
93
|
+
for (const feature of features.values()) {
|
|
94
|
+
const [leftPx, rightPx] = (0, util_1.featureSpanPx)(feature, region, bpPerPx);
|
|
95
|
+
if (feature.get('summary')) {
|
|
96
|
+
const min = feature.get('minScore');
|
|
97
|
+
const c = colorCallback(feature, min);
|
|
98
|
+
const w = Math.max(rightPx - leftPx + fudgeFactor, minSize);
|
|
99
|
+
const effectiveC = crossingOrigin
|
|
100
|
+
? c
|
|
101
|
+
: c === lastCol
|
|
102
|
+
? lastMix
|
|
103
|
+
: (lastMix = darken((0, colord_1.colord)(c), 0.4).toHex());
|
|
104
|
+
(0, util_2.fillRectCtx)(leftPx, toY(min), w, getHeight(min), ctx, effectiveC);
|
|
105
|
+
lastCol = c;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
for (const feature of features.values()) {
|
|
111
|
+
const [leftPx, rightPx] = (0, util_1.featureSpanPx)(feature, region, bpPerPx);
|
|
112
|
+
// create reduced features, avoiding multiple features per px
|
|
113
|
+
if (Math.floor(leftPx) !== Math.floor(prevLeftPx)) {
|
|
114
|
+
reducedFeatures.push(feature);
|
|
115
|
+
prevLeftPx = leftPx;
|
|
116
|
+
}
|
|
117
|
+
const score = feature.get('score');
|
|
118
|
+
const c = colorCallback(feature, score);
|
|
119
|
+
hasClipping = hasClipping || score < niceMin || score > niceMax;
|
|
120
|
+
const w = Math.max(rightPx - leftPx + fudgeFactor, minSize);
|
|
121
|
+
if (summaryScoreMode === 'max') {
|
|
122
|
+
const s = feature.get('summary') ? feature.get('maxScore') : score;
|
|
123
|
+
(0, util_2.fillRectCtx)(leftPx, toY(s), w, getHeight(s), ctx, c);
|
|
124
|
+
}
|
|
125
|
+
else if (summaryScoreMode === 'min') {
|
|
126
|
+
const s = feature.get('summary') ? feature.get('minScore') : score;
|
|
127
|
+
(0, util_2.fillRectCtx)(leftPx, toY(s), w, getHeight(s), ctx, c);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
(0, util_2.fillRectCtx)(leftPx, toY(score), w, getHeight(score), ctx, c);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// second pass: draw clipping
|
|
135
|
+
// avoid persisting the red fillstyle with save/restore
|
|
136
|
+
ctx.save();
|
|
137
|
+
if (hasClipping) {
|
|
138
|
+
ctx.fillStyle = clipColor;
|
|
139
|
+
for (const feature of features.values()) {
|
|
140
|
+
const [leftPx, rightPx] = (0, util_1.featureSpanPx)(feature, region, bpPerPx);
|
|
141
|
+
const w = rightPx - leftPx + fudgeFactor;
|
|
142
|
+
const score = feature.get('score');
|
|
143
|
+
if (score > niceMax) {
|
|
144
|
+
(0, util_2.fillRectCtx)(leftPx, offset, w, clipHeight, ctx);
|
|
145
|
+
}
|
|
146
|
+
else if (score < niceMin && scaleOpts.scaleType !== 'log') {
|
|
147
|
+
(0, util_2.fillRectCtx)(leftPx, unadjustedHeight, w, clipHeight, ctx);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
ctx.restore();
|
|
152
|
+
if (displayCrossHatches) {
|
|
153
|
+
ctx.lineWidth = 1;
|
|
154
|
+
ctx.strokeStyle = 'rgba(200,200,200,0.5)';
|
|
155
|
+
ticks.values.forEach(tick => {
|
|
156
|
+
ctx.beginPath();
|
|
157
|
+
ctx.moveTo(0, Math.round(toY(tick)));
|
|
158
|
+
ctx.lineTo(width, Math.round(toY(tick)));
|
|
159
|
+
ctx.stroke();
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return { reducedFeatures };
|
|
163
|
+
}
|
|
164
|
+
exports.drawXY = drawXY;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { axisPropsFromTickScale } from 'react-d3-axis-mod';
|
|
3
3
|
type Ticks = ReturnType<typeof axisPropsFromTickScale>;
|
|
4
|
-
declare const
|
|
4
|
+
declare const YScaleBar: ({ model, orientation, }: {
|
|
5
5
|
model: {
|
|
6
6
|
ticks?: Ticks;
|
|
7
7
|
};
|
|
8
8
|
orientation?: string | undefined;
|
|
9
9
|
}) => React.JSX.Element | null;
|
|
10
|
-
export default
|
|
10
|
+
export default YScaleBar;
|
package/dist/shared/YScaleBar.js
CHANGED
|
@@ -7,8 +7,9 @@ const react_1 = __importDefault(require("react"));
|
|
|
7
7
|
const material_1 = require("@mui/material");
|
|
8
8
|
const mobx_react_1 = require("mobx-react");
|
|
9
9
|
const react_d3_axis_mod_1 = require("react-d3-axis-mod");
|
|
10
|
-
|
|
10
|
+
const YScaleBar = (0, mobx_react_1.observer)(function ({ model, orientation, }) {
|
|
11
11
|
const { ticks } = model;
|
|
12
12
|
const theme = (0, material_1.useTheme)();
|
|
13
13
|
return ticks ? (react_1.default.createElement(react_d3_axis_mod_1.Axis, { ...ticks, shadow: 2, format: (n) => n, style: { orient: orientation === 'left' ? react_d3_axis_mod_1.LEFT : react_d3_axis_mod_1.RIGHT }, bg: theme.palette.background.default, fg: theme.palette.text.primary })) : null;
|
|
14
14
|
});
|
|
15
|
+
exports.default = YScaleBar;
|
|
@@ -247,7 +247,10 @@ export default function SharedWiggleMixin(configSchema: AnyConfigurationSchemaTy
|
|
|
247
247
|
readonly regionTooLargeReason: string;
|
|
248
248
|
} & {
|
|
249
249
|
regionCannotBeRenderedText(_region: import("@jbrowse/core/util").Region): "" | "Force load to see features";
|
|
250
|
-
regionCannotBeRendered(_region: import("@jbrowse/core/util").Region): import("react").JSX.Element | null;
|
|
250
|
+
regionCannotBeRendered(_region: import("@jbrowse/core/util").Region): import("react").JSX.Element | null; /**
|
|
251
|
+
* #getter
|
|
252
|
+
* subclasses can define these, as snpcoverage track does
|
|
253
|
+
*/
|
|
251
254
|
} & {
|
|
252
255
|
featureIdUnderMouse: string | undefined;
|
|
253
256
|
contextMenuFeature: Feature | undefined;
|
package/dist/util.d.ts
CHANGED
|
@@ -72,3 +72,4 @@ export declare function quantitativeStatsAutorun(self: {
|
|
|
72
72
|
}): void;
|
|
73
73
|
export declare function toP(s?: number): number;
|
|
74
74
|
export declare function round(value: number): number;
|
|
75
|
+
export declare function fillRectCtx(x: number, y: number, width: number, height: number, ctx: CanvasRenderingContext2D, color?: string): void;
|
package/dist/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.round = exports.toP = exports.quantitativeStatsAutorun = exports.getQuantitativeStats = exports.getNiceDomain = exports.getOrigin = exports.getScale = exports.YSCALEBAR_LABEL_OFFSET = void 0;
|
|
3
|
+
exports.fillRectCtx = exports.round = exports.toP = exports.quantitativeStatsAutorun = exports.getQuantitativeStats = exports.getNiceDomain = exports.getOrigin = exports.getScale = exports.YSCALEBAR_LABEL_OFFSET = void 0;
|
|
4
4
|
const d3_scale_1 = require("d3-scale");
|
|
5
5
|
const mobx_1 = require("mobx");
|
|
6
6
|
const util_1 = require("@jbrowse/core/util");
|
|
@@ -231,3 +231,19 @@ function round(value) {
|
|
|
231
231
|
return Math.round(value * 1e5) / 1e5;
|
|
232
232
|
}
|
|
233
233
|
exports.round = round;
|
|
234
|
+
// avoid drawing negative width features for SVG exports
|
|
235
|
+
function fillRectCtx(x, y, width, height, ctx, color) {
|
|
236
|
+
if (width < 0) {
|
|
237
|
+
x += width;
|
|
238
|
+
width = -width;
|
|
239
|
+
}
|
|
240
|
+
if (height < 0) {
|
|
241
|
+
y += height;
|
|
242
|
+
height = -height;
|
|
243
|
+
}
|
|
244
|
+
if (color) {
|
|
245
|
+
ctx.fillStyle = color;
|
|
246
|
+
}
|
|
247
|
+
ctx.fillRect(x, y, width, height);
|
|
248
|
+
}
|
|
249
|
+
exports.fillRectCtx = fillRectCtx;
|
|
@@ -23,17 +23,20 @@ export default function (pm) {
|
|
|
23
23
|
];
|
|
24
24
|
const now = +Date.now();
|
|
25
25
|
const trackId = `multitrack-${now}-sessionTrack`;
|
|
26
|
-
getSession(model)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
26
|
+
const session = getSession(model);
|
|
27
|
+
if (isSessionWithAddTracks(session)) {
|
|
28
|
+
session.addTrackConf({
|
|
29
|
+
type: 'MultiQuantitativeTrack',
|
|
30
|
+
trackId,
|
|
31
|
+
name: arg.name,
|
|
32
|
+
assemblyNames,
|
|
33
|
+
adapter: {
|
|
34
|
+
type: 'MultiWiggleAdapter',
|
|
35
|
+
subadapters,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
model.view.showTrack(trackId);
|
|
39
|
+
}
|
|
37
40
|
}
|
|
38
41
|
getSession(model).queueDialog(handleClose => [
|
|
39
42
|
ConfirmDialog,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import WiggleBaseRenderer from '../WiggleBaseRenderer';
|
|
2
2
|
import { YSCALEBAR_LABEL_OFFSET } from '../util';
|
|
3
|
-
import { drawLine } from '../
|
|
3
|
+
import { drawLine } from '../drawLine';
|
|
4
4
|
export default class LinePlotRenderer extends WiggleBaseRenderer {
|
|
5
5
|
async draw(ctx, props) {
|
|
6
6
|
return drawLine(ctx, {
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
declare
|
|
2
|
+
declare const SetColorDialog: ({ model, handleClose, }: {
|
|
3
3
|
model: {
|
|
4
|
-
color?: string;
|
|
5
|
-
posColor?: string;
|
|
6
|
-
negColor?: string;
|
|
4
|
+
color?: string | undefined;
|
|
5
|
+
posColor?: string | undefined;
|
|
6
|
+
negColor?: string | undefined;
|
|
7
7
|
setColor: (arg?: string) => void;
|
|
8
8
|
setPosColor: (arg?: string) => void;
|
|
9
9
|
setNegColor: (arg?: string) => void;
|
|
10
10
|
};
|
|
11
11
|
handleClose: () => void;
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
export default _default;
|
|
12
|
+
}) => React.JSX.Element;
|
|
13
|
+
export default SetColorDialog;
|
|
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react';
|
|
|
3
3
|
import { Button, DialogContent, DialogActions, FormControlLabel, Radio, Typography, } from '@mui/material';
|
|
4
4
|
import { Dialog } from '@jbrowse/core/ui';
|
|
5
5
|
import { ColorPicker } from '@jbrowse/core/ui/ColorPicker';
|
|
6
|
-
function SetColorDialog({ model, handleClose, }) {
|
|
6
|
+
const SetColorDialog = observer(function SetColorDialog({ model, handleClose, }) {
|
|
7
7
|
const [posneg, setPosNeg] = useState(false);
|
|
8
8
|
return (React.createElement(Dialog, { open: true, onClose: handleClose, title: "Set color" },
|
|
9
9
|
React.createElement(DialogContent, null,
|
|
@@ -30,5 +30,5 @@ function SetColorDialog({ model, handleClose, }) {
|
|
|
30
30
|
model.setColor(undefined);
|
|
31
31
|
}, color: "secondary", variant: "contained" }, "Restore default"),
|
|
32
32
|
React.createElement(Button, { variant: "contained", color: "primary", type: "submit", onClick: () => handleClose() }, "Submit"))));
|
|
33
|
-
}
|
|
34
|
-
export default
|
|
33
|
+
});
|
|
34
|
+
export default SetColorDialog;
|
|
@@ -4,7 +4,7 @@ import { observer } from 'mobx-react';
|
|
|
4
4
|
import Tooltip from '../../Tooltip';
|
|
5
5
|
import { toP } from '../../util';
|
|
6
6
|
const en = (n) => n.toLocaleString('en-US');
|
|
7
|
-
const TooltipContents = React.forwardRef(function ({ feature }, ref) {
|
|
7
|
+
const TooltipContents = React.forwardRef(function TooltipContents2({ feature }, ref) {
|
|
8
8
|
const start = feature.get('start');
|
|
9
9
|
const end = feature.get('end');
|
|
10
10
|
const name = feature.get('refName');
|
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
import { groupBy } from '@jbrowse/core/util';
|
|
2
2
|
import WiggleBaseRenderer from '../WiggleBaseRenderer';
|
|
3
|
-
import { drawDensity } from '../
|
|
3
|
+
import { drawDensity } from '../drawDensity';
|
|
4
4
|
export default class MultiXYPlotRenderer extends WiggleBaseRenderer {
|
|
5
5
|
// @ts-expect-error
|
|
6
6
|
async draw(ctx, props) {
|
|
7
7
|
const { bpPerPx, sources, regions, features } = props;
|
|
8
8
|
const [region] = regions;
|
|
9
|
-
const groups = groupBy(
|
|
9
|
+
const groups = groupBy(features.values(), f => f.get('source'));
|
|
10
10
|
const height = props.height / sources.length;
|
|
11
11
|
const width = (region.end - region.start) / bpPerPx;
|
|
12
12
|
let feats = [];
|
|
13
13
|
ctx.save();
|
|
14
14
|
sources.forEach(source => {
|
|
15
|
-
const features = groups[source.name];
|
|
16
|
-
if (!features) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
15
|
+
const features = groups[source.name] || [];
|
|
19
16
|
const { reducedFeatures } = drawDensity(ctx, {
|
|
20
17
|
...props,
|
|
21
18
|
features,
|
|
@@ -27,7 +24,7 @@ export default class MultiXYPlotRenderer extends WiggleBaseRenderer {
|
|
|
27
24
|
ctx.lineTo(width, height);
|
|
28
25
|
ctx.stroke();
|
|
29
26
|
ctx.translate(0, height);
|
|
30
|
-
feats =
|
|
27
|
+
feats = feats.concat(reducedFeatures);
|
|
31
28
|
});
|
|
32
29
|
ctx.restore();
|
|
33
30
|
return { reducedFeatures: feats };
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import { groupBy } from '@jbrowse/core/util';
|
|
2
|
-
import { drawLine } from '../
|
|
2
|
+
import { drawLine } from '../drawLine';
|
|
3
3
|
import WiggleBaseRenderer from '../WiggleBaseRenderer';
|
|
4
4
|
export default class MultiLineRenderer extends WiggleBaseRenderer {
|
|
5
5
|
// @ts-expect-error
|
|
6
6
|
async draw(ctx, props) {
|
|
7
7
|
const { sources, features } = props;
|
|
8
|
-
const groups = groupBy(
|
|
8
|
+
const groups = groupBy(features.values(), f => f.get('source'));
|
|
9
9
|
let feats = [];
|
|
10
10
|
sources.forEach(source => {
|
|
11
|
-
const features = groups[source.name];
|
|
12
|
-
if (!features) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
11
|
const { reducedFeatures } = drawLine(ctx, {
|
|
16
12
|
...props,
|
|
17
|
-
features,
|
|
13
|
+
features: groups[source.name] || [],
|
|
18
14
|
colorCallback: () => source.color || 'blue',
|
|
19
15
|
});
|
|
20
|
-
feats =
|
|
16
|
+
feats = feats.concat(reducedFeatures);
|
|
21
17
|
});
|
|
22
18
|
return { reducedFeatures: feats };
|
|
23
19
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { DialogProps } from '@mui/material';
|
|
3
|
-
declare
|
|
3
|
+
declare const DraggableDialog: (props: DialogProps & {
|
|
4
4
|
title: string;
|
|
5
|
-
})
|
|
6
|
-
|
|
7
|
-
export default _default;
|
|
5
|
+
}) => React.JSX.Element;
|
|
6
|
+
export default DraggableDialog;
|
|
@@ -18,7 +18,7 @@ function PaperComponent(props) {
|
|
|
18
18
|
return (React.createElement(Draggable, { handle: "#draggable-dialog-title", cancel: '[class*="MuiDialogContent-root"]' },
|
|
19
19
|
React.createElement(Paper, { ...props })));
|
|
20
20
|
}
|
|
21
|
-
function DraggableDialog(props) {
|
|
21
|
+
const DraggableDialog = observer(function DraggableDialog(props) {
|
|
22
22
|
const { classes } = useStyles();
|
|
23
23
|
const { title, children, onClose } = props;
|
|
24
24
|
return (React.createElement(Dialog, { ...props, PaperComponent: PaperComponent, "aria-labelledby": "draggable-dialog-title" // this area is important for the draggable functionality
|
|
@@ -33,5 +33,5 @@ function DraggableDialog(props) {
|
|
|
33
33
|
React.createElement(CloseIcon, null))) : null),
|
|
34
34
|
React.createElement(Divider, null),
|
|
35
35
|
children)));
|
|
36
|
-
}
|
|
37
|
-
export default
|
|
36
|
+
});
|
|
37
|
+
export default DraggableDialog;
|
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { Button, DialogContent, DialogActions } from '@mui/material';
|
|
3
3
|
import { makeStyles } from 'tss-react/mui';
|
|
4
|
-
import {
|
|
5
|
-
import { DataGrid } from '@mui/x-data-grid';
|
|
4
|
+
import { useLocalStorage } from '@jbrowse/core/util';
|
|
6
5
|
import clone from 'clone';
|
|
7
6
|
// locals
|
|
8
7
|
import DraggableDialog from './DraggableDialog';
|
|
9
|
-
import
|
|
10
|
-
import { moveUp, moveDown } from './util';
|
|
11
|
-
// icons
|
|
12
|
-
import KeyboardDoubleArrowUpIcon from '@mui/icons-material/KeyboardDoubleArrowUp';
|
|
13
|
-
import KeyboardDoubleArrowDownIcon from '@mui/icons-material/KeyboardDoubleArrowDown';
|
|
14
|
-
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
|
15
|
-
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
|
|
16
|
-
import UriLink from '@jbrowse/core/BaseFeatureWidget/BaseFeatureDetail/UriLink';
|
|
8
|
+
import SourcesGrid from './SourcesGrid';
|
|
17
9
|
const useStyles = makeStyles()({
|
|
18
10
|
content: {
|
|
19
11
|
minWidth: 800,
|
|
@@ -53,89 +45,3 @@ export default function SetColorDialog({ model, handleClose, }) {
|
|
|
53
45
|
handleClose();
|
|
54
46
|
} }, "Submit"))));
|
|
55
47
|
}
|
|
56
|
-
function SourcesGrid({ rows, onChange, showTips, }) {
|
|
57
|
-
const [anchorEl, setAnchorEl] = useState(null);
|
|
58
|
-
const [selected, setSelected] = useState([]);
|
|
59
|
-
// @ts-expect-error
|
|
60
|
-
const { name: _name, color: _color, baseUri: _baseUri, ...rest } = rows[0];
|
|
61
|
-
const [widgetColor, setWidgetColor] = useState('blue');
|
|
62
|
-
const [currSort, setCurrSort] = useState({
|
|
63
|
-
idx: 0,
|
|
64
|
-
field: null,
|
|
65
|
-
});
|
|
66
|
-
return (React.createElement("div", null,
|
|
67
|
-
React.createElement(Button, { disabled: !selected.length, onClick: event => setAnchorEl(event.currentTarget) }, "Change color of selected items"),
|
|
68
|
-
React.createElement(Button, { onClick: () => onChange(moveUp([...rows], selected)), disabled: !selected.length },
|
|
69
|
-
React.createElement(KeyboardArrowUpIcon, null),
|
|
70
|
-
showTips ? 'Move selected items up' : null),
|
|
71
|
-
React.createElement(Button, { onClick: () => onChange(moveDown([...rows], selected)), disabled: !selected.length },
|
|
72
|
-
React.createElement(KeyboardArrowDownIcon, null),
|
|
73
|
-
showTips ? 'Move selected items down' : null),
|
|
74
|
-
React.createElement(Button, { onClick: () => onChange(moveUp([...rows], selected, rows.length)), disabled: !selected.length },
|
|
75
|
-
React.createElement(KeyboardDoubleArrowUpIcon, null),
|
|
76
|
-
showTips ? 'Move selected items to top' : null),
|
|
77
|
-
React.createElement(Button, { onClick: () => onChange(moveDown([...rows], selected, rows.length)), disabled: !selected.length },
|
|
78
|
-
React.createElement(KeyboardDoubleArrowDownIcon, null),
|
|
79
|
-
showTips ? 'Move selected items to bottom' : null),
|
|
80
|
-
React.createElement(ColorPopover, { anchorEl: anchorEl, color: widgetColor, onChange: c => {
|
|
81
|
-
setWidgetColor(c);
|
|
82
|
-
selected.forEach(id => {
|
|
83
|
-
const elt = rows.find(f => f.name === id);
|
|
84
|
-
if (elt) {
|
|
85
|
-
elt.color = c;
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
onChange([...rows]);
|
|
89
|
-
}, onClose: () => setAnchorEl(null) }),
|
|
90
|
-
React.createElement("div", { style: { height: 400, width: '100%' } },
|
|
91
|
-
React.createElement(DataGrid, { getRowId: row => row.name, checkboxSelection: true, disableRowSelectionOnClick: true, onRowSelectionModelChange: arg => setSelected(arg), rows: rows, rowHeight: 25, columnHeaderHeight: 33, columns: [
|
|
92
|
-
{
|
|
93
|
-
field: 'color',
|
|
94
|
-
headerName: 'Color',
|
|
95
|
-
renderCell: params => {
|
|
96
|
-
const { value, id } = params;
|
|
97
|
-
return (React.createElement(ColorPicker, { color: value || 'blue', onChange: c => {
|
|
98
|
-
const elt = rows.find(f => f.name === id);
|
|
99
|
-
if (elt) {
|
|
100
|
-
elt.color = c;
|
|
101
|
-
}
|
|
102
|
-
onChange([...rows]);
|
|
103
|
-
} }));
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
{
|
|
107
|
-
field: 'name',
|
|
108
|
-
sortingOrder: [null],
|
|
109
|
-
headerName: 'Name',
|
|
110
|
-
width: measureGridWidth(rows.map(r => r.name)),
|
|
111
|
-
},
|
|
112
|
-
...Object.keys(rest).map(val => ({
|
|
113
|
-
field: val,
|
|
114
|
-
sortingOrder: [null],
|
|
115
|
-
renderCell: (params) => {
|
|
116
|
-
const { value } = params;
|
|
117
|
-
return isUriLocation(value) ? (React.createElement(UriLink, { value: value })) : (getStr(value));
|
|
118
|
-
},
|
|
119
|
-
// @ts-ignore
|
|
120
|
-
width: measureGridWidth(rows.map(r => r[val])),
|
|
121
|
-
})),
|
|
122
|
-
], sortModel: [
|
|
123
|
-
/* we control the sort as a controlled component using onSortModelChange */
|
|
124
|
-
], onSortModelChange: args => {
|
|
125
|
-
const sort = args[0];
|
|
126
|
-
const idx = (currSort.idx + 1) % 2;
|
|
127
|
-
const field = (sort === null || sort === void 0 ? void 0 : sort.field) || currSort.field;
|
|
128
|
-
setCurrSort({ idx, field });
|
|
129
|
-
onChange(field
|
|
130
|
-
? [...rows].sort((a, b) => {
|
|
131
|
-
// @ts-expect-error
|
|
132
|
-
const aa = getStr(a[field]);
|
|
133
|
-
// @ts-expect-error
|
|
134
|
-
const bb = getStr(b[field]);
|
|
135
|
-
return idx === 1
|
|
136
|
-
? aa.localeCompare(bb)
|
|
137
|
-
: bb.localeCompare(aa);
|
|
138
|
-
})
|
|
139
|
-
: rows);
|
|
140
|
-
} }))));
|
|
141
|
-
}
|