@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.
Files changed (84) hide show
  1. package/dist/CreateMultiWiggleExtension/index.js +14 -11
  2. package/dist/DensityRenderer/DensityRenderer.js +2 -2
  3. package/dist/LinePlotRenderer/LinePlotRenderer.js +2 -2
  4. package/dist/LinearWiggleDisplay/components/SetColorDialog.d.ts +6 -7
  5. package/dist/LinearWiggleDisplay/components/SetColorDialog.js +3 -3
  6. package/dist/LinearWiggleDisplay/components/Tooltip.js +1 -1
  7. package/dist/MultiDensityRenderer/MultiDensityRenderer.js +5 -8
  8. package/dist/MultiLineRenderer/MultiLineRenderer.js +5 -9
  9. package/dist/MultiLinearWiggleDisplay/components/DraggableDialog.d.ts +3 -4
  10. package/dist/MultiLinearWiggleDisplay/components/DraggableDialog.js +3 -3
  11. package/dist/MultiLinearWiggleDisplay/components/SetColorDialog.js +2 -96
  12. package/dist/MultiLinearWiggleDisplay/components/SourcesGrid.d.ts +8 -0
  13. package/dist/MultiLinearWiggleDisplay/components/SourcesGrid.js +138 -0
  14. package/dist/MultiLinearWiggleDisplay/components/Tooltip.d.ts +3 -2
  15. package/dist/MultiLinearWiggleDisplay/components/Tooltip.js +1 -1
  16. package/dist/MultiLinearWiggleDisplay/components/WiggleDisplayComponent.d.ts +2 -3
  17. package/dist/MultiLinearWiggleDisplay/components/WiggleDisplayComponent.js +2 -4
  18. package/dist/MultiLinearWiggleDisplay/components/util.js +2 -4
  19. package/dist/MultiRowLineRenderer/MultiRowLineRenderer.js +5 -5
  20. package/dist/MultiRowXYPlotRenderer/MultiRowXYPlotRenderer.js +5 -34
  21. package/dist/MultiWiggleAddTrackWidget/AddTrackWorkflow.js +16 -12
  22. package/dist/MultiWiggleRendering.d.ts +3 -4
  23. package/dist/MultiWiggleRendering.js +7 -5
  24. package/dist/MultiXYPlotRenderer/MultiXYPlotRenderer.js +5 -33
  25. package/dist/Tooltip.d.ts +5 -6
  26. package/dist/Tooltip.js +3 -3
  27. package/dist/WiggleRendering.d.ts +3 -4
  28. package/dist/WiggleRendering.js +3 -3
  29. package/dist/XYPlotRenderer/XYPlotRenderer.js +2 -27
  30. package/dist/drawDensity.d.ts +17 -0
  31. package/dist/drawDensity.js +66 -0
  32. package/dist/drawLine.d.ts +19 -0
  33. package/dist/drawLine.js +73 -0
  34. package/dist/drawXY.d.ts +19 -0
  35. package/dist/drawXY.js +164 -0
  36. package/dist/shared/YScaleBar.d.ts +2 -2
  37. package/dist/shared/YScaleBar.js +2 -1
  38. package/dist/shared/modelShared.d.ts +4 -1
  39. package/dist/util.d.ts +1 -0
  40. package/dist/util.js +17 -1
  41. package/esm/CreateMultiWiggleExtension/index.js +14 -11
  42. package/esm/DensityRenderer/DensityRenderer.js +1 -1
  43. package/esm/LinePlotRenderer/LinePlotRenderer.js +1 -1
  44. package/esm/LinearWiggleDisplay/components/SetColorDialog.d.ts +6 -7
  45. package/esm/LinearWiggleDisplay/components/SetColorDialog.js +3 -3
  46. package/esm/LinearWiggleDisplay/components/Tooltip.js +1 -1
  47. package/esm/MultiDensityRenderer/MultiDensityRenderer.js +4 -7
  48. package/esm/MultiLineRenderer/MultiLineRenderer.js +4 -8
  49. package/esm/MultiLinearWiggleDisplay/components/DraggableDialog.d.ts +3 -4
  50. package/esm/MultiLinearWiggleDisplay/components/DraggableDialog.js +3 -3
  51. package/esm/MultiLinearWiggleDisplay/components/SetColorDialog.js +2 -96
  52. package/esm/MultiLinearWiggleDisplay/components/SourcesGrid.d.ts +8 -0
  53. package/esm/MultiLinearWiggleDisplay/components/SourcesGrid.js +110 -0
  54. package/esm/MultiLinearWiggleDisplay/components/Tooltip.d.ts +3 -2
  55. package/esm/MultiLinearWiggleDisplay/components/Tooltip.js +1 -1
  56. package/esm/MultiLinearWiggleDisplay/components/WiggleDisplayComponent.d.ts +2 -3
  57. package/esm/MultiLinearWiggleDisplay/components/WiggleDisplayComponent.js +2 -2
  58. package/esm/MultiLinearWiggleDisplay/components/util.js +2 -4
  59. package/esm/MultiRowLineRenderer/MultiRowLineRenderer.js +4 -4
  60. package/esm/MultiRowXYPlotRenderer/MultiRowXYPlotRenderer.js +4 -10
  61. package/esm/MultiWiggleAddTrackWidget/AddTrackWorkflow.js +17 -13
  62. package/esm/MultiWiggleRendering.d.ts +3 -4
  63. package/esm/MultiWiggleRendering.js +7 -5
  64. package/esm/MultiXYPlotRenderer/MultiXYPlotRenderer.js +4 -9
  65. package/esm/Tooltip.d.ts +5 -6
  66. package/esm/Tooltip.js +3 -3
  67. package/esm/WiggleRendering.d.ts +3 -4
  68. package/esm/WiggleRendering.js +3 -3
  69. package/esm/XYPlotRenderer/XYPlotRenderer.js +1 -3
  70. package/esm/drawDensity.d.ts +17 -0
  71. package/esm/drawDensity.js +62 -0
  72. package/esm/drawLine.d.ts +19 -0
  73. package/esm/drawLine.js +69 -0
  74. package/esm/drawXY.d.ts +19 -0
  75. package/esm/{drawxy.js → drawXY.js} +17 -140
  76. package/esm/shared/YScaleBar.d.ts +2 -2
  77. package/esm/shared/YScaleBar.js +2 -1
  78. package/esm/shared/modelShared.d.ts +4 -1
  79. package/esm/util.d.ts +1 -0
  80. package/esm/util.js +15 -0
  81. package/package.json +3 -4
  82. package/dist/drawxy.d.ts +0 -50
  83. package/dist/drawxy.js +0 -289
  84. 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 _default: ({ model, orientation, }: {
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 _default;
10
+ export default YScaleBar;
@@ -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
- exports.default = (0, mobx_react_1.observer)(function YScaleBar({ model, orientation, }) {
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).addTrackConf({
27
- type: 'MultiQuantitativeTrack',
28
- trackId,
29
- name: arg.name,
30
- assemblyNames,
31
- adapter: {
32
- type: 'MultiWiggleAdapter',
33
- subadapters,
34
- },
35
- });
36
- model.view.showTrack(trackId);
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,4 +1,4 @@
1
- import { drawDensity } from '../drawxy';
1
+ import { drawDensity } from '../drawDensity';
2
2
  import WiggleBaseRenderer from '../WiggleBaseRenderer';
3
3
  export default class DensityRenderer extends WiggleBaseRenderer {
4
4
  async draw(ctx, props) {
@@ -1,6 +1,6 @@
1
1
  import WiggleBaseRenderer from '../WiggleBaseRenderer';
2
2
  import { YSCALEBAR_LABEL_OFFSET } from '../util';
3
- import { drawLine } from '../drawxy';
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 function SetColorDialog({ model, handleClose, }: {
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
- }): React.JSX.Element;
13
- declare const _default: typeof SetColorDialog;
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 observer(SetColorDialog);
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 '../drawxy';
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([...features.values()], f => f.get('source'));
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 = [...feats, ...reducedFeatures];
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 '../drawxy';
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([...features.values()], f => f.get('source'));
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 = [...feats, ...reducedFeatures];
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 function DraggableDialog(props: DialogProps & {
3
+ declare const DraggableDialog: (props: DialogProps & {
4
4
  title: string;
5
- }): React.JSX.Element;
6
- declare const _default: typeof DraggableDialog;
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 observer(DraggableDialog);
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 { getStr, isUriLocation, measureGridWidth, useLocalStorage, } from '@jbrowse/core/util';
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 ColorPicker, { ColorPopover } from '@jbrowse/core/ui/ColorPicker';
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
- }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { Source } from '../../util';
3
+ declare function SourcesGrid({ rows, onChange, showTips, }: {
4
+ rows: Source[];
5
+ onChange: (arg: Source[]) => void;
6
+ showTips: boolean;
7
+ }): React.JSX.Element;
8
+ export default SourcesGrid;