@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.
Files changed (121) hide show
  1. package/dist/LGVSyntenyDisplay/components/LaunchSyntenyViewDialog.d.ts +2 -1
  2. package/dist/LGVSyntenyDisplay/components/LaunchSyntenyViewDialog.js +4 -2
  3. package/dist/LGVSyntenyDisplay/components/util.d.ts +4 -1
  4. package/dist/LGVSyntenyDisplay/components/util.js +7 -15
  5. package/dist/LGVSyntenyDisplay/model.d.ts +26 -14
  6. package/dist/LGVSyntenyDisplay/model.js +23 -1
  7. package/dist/LaunchLinearSyntenyView.js +41 -11
  8. package/dist/LinearComparativeDisplay/stateModelFactory.d.ts +42 -14
  9. package/dist/LinearComparativeDisplay/stateModelFactory.js +20 -10
  10. package/dist/LinearComparativeView/components/Header.d.ts +2 -3
  11. package/dist/LinearComparativeView/components/Header.js +72 -62
  12. package/dist/LinearComparativeView/components/HeaderSearchBoxes.d.ts +6 -0
  13. package/dist/LinearComparativeView/components/HeaderSearchBoxes.js +34 -0
  14. package/dist/LinearComparativeView/components/LinearComparativeRenderArea.d.ts +6 -0
  15. package/dist/LinearComparativeView/components/LinearComparativeRenderArea.js +61 -0
  16. package/dist/LinearComparativeView/components/LinearComparativeView.d.ts +2 -4
  17. package/dist/LinearComparativeView/components/LinearComparativeView.js +3 -67
  18. package/dist/LinearComparativeView/components/Rubberband.js +1 -1
  19. package/dist/LinearComparativeView/index.js +3 -0
  20. package/dist/LinearComparativeView/model.d.ts +265 -12
  21. package/dist/LinearComparativeView/model.js +45 -75
  22. package/dist/LinearSyntenyDisplay/afterAttach.js +5 -4
  23. package/dist/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +47 -32
  24. package/dist/LinearSyntenyDisplay/components/SyntenyContextMenu.js +10 -6
  25. package/dist/LinearSyntenyDisplay/components/util.d.ts +7 -2
  26. package/dist/LinearSyntenyDisplay/components/util.js +12 -14
  27. package/dist/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
  28. package/dist/LinearSyntenyDisplay/drawSynteny.js +29 -25
  29. package/dist/LinearSyntenyDisplay/index.js +1 -1
  30. package/dist/LinearSyntenyDisplay/model.d.ts +48 -10
  31. package/dist/LinearSyntenyDisplay/model.js +38 -15
  32. package/dist/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts} +2 -3
  33. package/dist/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js} +3 -3
  34. package/dist/LinearSyntenyView/components/ImportForm/LinearSyntenyImportForm.js +195 -0
  35. package/dist/LinearSyntenyView/components/ImportForm/Spacer.d.ts +2 -0
  36. package/dist/LinearSyntenyView/components/ImportForm/Spacer.js +10 -0
  37. package/dist/LinearSyntenyView/components/ImportForm/TrackSelector.d.ts +10 -0
  38. package/dist/LinearSyntenyView/components/ImportForm/{ImportSyntenyTrackSelector.js → TrackSelector.js} +15 -20
  39. package/dist/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.d.ts +14 -0
  40. package/dist/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.js +52 -0
  41. package/dist/LinearSyntenyView/components/LinearSyntenyView.js +3 -3
  42. package/dist/LinearSyntenyView/index.js +1 -1
  43. package/dist/LinearSyntenyView/model.d.ts +267 -9
  44. package/dist/LinearSyntenyView/model.js +2 -2
  45. package/dist/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.d.ts +12 -0
  46. package/dist/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.js +19 -0
  47. package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.d.ts +1 -3
  48. package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +36 -27
  49. package/dist/LinearSyntenyViewHelper/index.d.ts +2 -0
  50. package/dist/LinearSyntenyViewHelper/index.js +25 -0
  51. package/dist/LinearSyntenyViewHelper/stateModelFactory.d.ts +30 -0
  52. package/dist/LinearSyntenyViewHelper/stateModelFactory.js +105 -0
  53. package/dist/SyntenyFeatureDetail/SyntenyFeatureDetail.d.ts +14 -0
  54. package/dist/SyntenyFeatureDetail/SyntenyFeatureDetail.js +100 -0
  55. package/dist/SyntenyFeatureDetail/index.d.ts +2 -0
  56. package/dist/SyntenyFeatureDetail/index.js +56 -0
  57. package/dist/index.js +4 -0
  58. package/esm/LGVSyntenyDisplay/components/LaunchSyntenyViewDialog.d.ts +2 -1
  59. package/esm/LGVSyntenyDisplay/components/LaunchSyntenyViewDialog.js +4 -2
  60. package/esm/LGVSyntenyDisplay/components/util.d.ts +4 -1
  61. package/esm/LGVSyntenyDisplay/components/util.js +8 -16
  62. package/esm/LGVSyntenyDisplay/model.d.ts +26 -14
  63. package/esm/LGVSyntenyDisplay/model.js +25 -3
  64. package/esm/LaunchLinearSyntenyView.js +41 -11
  65. package/esm/LinearComparativeDisplay/stateModelFactory.d.ts +42 -14
  66. package/esm/LinearComparativeDisplay/stateModelFactory.js +21 -11
  67. package/esm/LinearComparativeView/components/Header.d.ts +2 -3
  68. package/esm/LinearComparativeView/components/Header.js +73 -63
  69. package/esm/LinearComparativeView/components/HeaderSearchBoxes.d.ts +6 -0
  70. package/esm/LinearComparativeView/components/HeaderSearchBoxes.js +29 -0
  71. package/esm/LinearComparativeView/components/LinearComparativeRenderArea.d.ts +6 -0
  72. package/esm/LinearComparativeView/components/LinearComparativeRenderArea.js +56 -0
  73. package/esm/LinearComparativeView/components/LinearComparativeView.d.ts +2 -4
  74. package/esm/LinearComparativeView/components/LinearComparativeView.js +3 -67
  75. package/esm/LinearComparativeView/components/Rubberband.js +1 -1
  76. package/esm/LinearComparativeView/index.js +3 -0
  77. package/esm/LinearComparativeView/model.d.ts +265 -12
  78. package/esm/LinearComparativeView/model.js +47 -77
  79. package/esm/LinearSyntenyDisplay/afterAttach.js +5 -4
  80. package/esm/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +48 -33
  81. package/esm/LinearSyntenyDisplay/components/SyntenyContextMenu.js +10 -6
  82. package/esm/LinearSyntenyDisplay/components/util.d.ts +7 -2
  83. package/esm/LinearSyntenyDisplay/components/util.js +12 -14
  84. package/esm/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
  85. package/esm/LinearSyntenyDisplay/drawSynteny.js +29 -25
  86. package/esm/LinearSyntenyDisplay/index.js +1 -1
  87. package/esm/LinearSyntenyDisplay/model.d.ts +48 -10
  88. package/esm/LinearSyntenyDisplay/model.js +38 -15
  89. package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts} +2 -3
  90. package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js} +3 -3
  91. package/esm/LinearSyntenyView/components/ImportForm/LinearSyntenyImportForm.js +167 -0
  92. package/esm/LinearSyntenyView/components/ImportForm/Spacer.d.ts +2 -0
  93. package/esm/LinearSyntenyView/components/ImportForm/Spacer.js +4 -0
  94. package/esm/LinearSyntenyView/components/ImportForm/TrackSelector.d.ts +10 -0
  95. package/esm/LinearSyntenyView/components/ImportForm/{ImportSyntenyTrackSelector.js → TrackSelector.js} +15 -20
  96. package/esm/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.d.ts +14 -0
  97. package/esm/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.js +23 -0
  98. package/esm/LinearSyntenyView/components/LinearSyntenyView.js +3 -3
  99. package/esm/LinearSyntenyView/index.js +1 -1
  100. package/esm/LinearSyntenyView/model.d.ts +267 -9
  101. package/esm/LinearSyntenyView/model.js +2 -2
  102. package/esm/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.d.ts +12 -0
  103. package/esm/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.js +13 -0
  104. package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.d.ts +1 -3
  105. package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +38 -29
  106. package/esm/LinearSyntenyViewHelper/index.d.ts +2 -0
  107. package/esm/LinearSyntenyViewHelper/index.js +19 -0
  108. package/esm/LinearSyntenyViewHelper/stateModelFactory.d.ts +30 -0
  109. package/esm/LinearSyntenyViewHelper/stateModelFactory.js +102 -0
  110. package/esm/SyntenyFeatureDetail/SyntenyFeatureDetail.d.ts +14 -0
  111. package/esm/SyntenyFeatureDetail/SyntenyFeatureDetail.js +72 -0
  112. package/esm/SyntenyFeatureDetail/index.d.ts +2 -0
  113. package/esm/SyntenyFeatureDetail/index.js +27 -0
  114. package/esm/index.js +4 -0
  115. package/package.json +3 -3
  116. package/dist/LinearSyntenyView/components/ImportForm/ImportSyntenyTrackSelector.d.ts +0 -9
  117. package/dist/LinearSyntenyView/components/ImportForm/index.js +0 -138
  118. package/esm/LinearSyntenyView/components/ImportForm/ImportSyntenyTrackSelector.d.ts +0 -9
  119. package/esm/LinearSyntenyView/components/ImportForm/index.js +0 -110
  120. /package/dist/LinearSyntenyView/components/ImportForm/{index.d.ts → LinearSyntenyImportForm.d.ts} +0 -0
  121. /package/esm/LinearSyntenyView/components/ImportForm/{index.d.ts → LinearSyntenyImportForm.d.ts} +0 -0
@@ -45,21 +45,23 @@ const useStyles = (0, mui_1.makeStyles)()({
45
45
  rel: {
46
46
  position: 'relative',
47
47
  },
48
- abs: {
48
+ mouseoverCanvas: {
49
+ imageRendering: 'pixelated',
49
50
  position: 'absolute',
50
- },
51
- none: {
52
51
  pointEvents: 'none',
53
52
  },
53
+ mainCanvas: {
54
+ position: 'absolute',
55
+ },
54
56
  });
55
57
  const LinearSyntenyRendering = (0, mobx_react_1.observer)(function ({ model, }) {
56
- const { classes, cx } = useStyles();
58
+ const { classes } = useStyles();
59
+ const { mouseoverId, height } = model;
57
60
  const xOffset = (0, react_1.useRef)(0);
58
- const currScrollFrame = (0, react_1.useRef)();
59
61
  const view = (0, util_1.getContainingView)(model);
60
- const height = view.middleComparativeHeight;
61
62
  const width = view.width;
62
63
  const delta = (0, react_1.useRef)(0);
64
+ const scheduled = (0, react_1.useRef)(false);
63
65
  const timeout = (0, react_1.useRef)();
64
66
  const [anchorEl, setAnchorEl] = (0, react_1.useState)();
65
67
  const [tooltip, setTooltip] = (0, react_1.useState)('');
@@ -67,18 +69,25 @@ const LinearSyntenyRendering = (0, mobx_react_1.observer)(function ({ model, })
67
69
  const [mouseCurrDownX, setMouseCurrDownX] = (0, react_1.useState)();
68
70
  const [mouseInitialDownX, setMouseInitialDownX] = (0, react_1.useState)();
69
71
  const [currY, setCurrY] = (0, react_1.useState)();
70
- const { mouseoverId } = model;
72
+ const mainSyntenyCanvasRefp = (0, react_1.useRef)();
71
73
  // these useCallbacks avoid new refs from being created on any mouseover,
72
74
  // etc.
73
75
  // biome-ignore lint/correctness/useExhaustiveDependencies:
74
- const k1 = (0, react_1.useCallback)((ref) => {
76
+ const mouseoverDetectionCanvasRef = (0, react_1.useCallback)((ref) => {
75
77
  model.setMouseoverCanvasRef(ref);
76
78
  },
77
79
  // eslint-disable-next-line react-hooks/exhaustive-deps
78
80
  [model, height, width]);
79
81
  // biome-ignore lint/correctness/useExhaustiveDependencies:
80
- const k2 = (0, react_1.useCallback)((ref) => {
82
+ const mainSyntenyCanvasRef = (0, react_1.useCallback)((ref) => {
81
83
  model.setMainCanvasRef(ref);
84
+ mainSyntenyCanvasRefp.current = ref; // this ref is additionally used in useEffect below
85
+ },
86
+ // eslint-disable-next-line react-hooks/exhaustive-deps
87
+ [model, height, width]);
88
+ // biome-ignore lint/correctness/useExhaustiveDependencies:
89
+ (0, react_1.useEffect)(() => {
90
+ var _a;
82
91
  function onWheel(event) {
83
92
  event.preventDefault();
84
93
  if (event.ctrlKey) {
@@ -90,11 +99,14 @@ const LinearSyntenyRendering = (0, mobx_react_1.observer)(function ({ model, })
90
99
  clearTimeout(timeout.current);
91
100
  }
92
101
  timeout.current = setTimeout(() => {
102
+ var _a;
93
103
  for (const v of view.views) {
94
104
  v.setScaleFactor(1);
95
105
  v.zoomTo(delta.current > 0
96
106
  ? v.bpPerPx * (1 + delta.current)
97
- : v.bpPerPx / (1 - delta.current), event.clientX - ((ref === null || ref === void 0 ? void 0 : ref.getBoundingClientRect().left) || 0));
107
+ : v.bpPerPx / (1 - delta.current), event.clientX -
108
+ (((_a = mainSyntenyCanvasRefp.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().left) ||
109
+ 0));
98
110
  }
99
111
  delta.current = 0;
100
112
  }, 300);
@@ -103,56 +115,55 @@ const LinearSyntenyRendering = (0, mobx_react_1.observer)(function ({ model, })
103
115
  if (Math.abs(event.deltaY) < Math.abs(event.deltaX)) {
104
116
  xOffset.current += event.deltaX / 2;
105
117
  }
106
- if (currScrollFrame.current === undefined) {
107
- currScrollFrame.current = requestAnimationFrame(() => {
118
+ if (!scheduled.current) {
119
+ scheduled.current = true;
120
+ window.requestAnimationFrame(() => {
108
121
  (0, mobx_1.transaction)(() => {
109
122
  for (const v of view.views) {
110
123
  v.horizontalScroll(xOffset.current);
111
124
  }
112
125
  xOffset.current = 0;
113
- currScrollFrame.current = undefined;
126
+ scheduled.current = false;
114
127
  });
115
128
  });
116
129
  }
117
130
  }
118
131
  }
119
- ref === null || ref === void 0 ? void 0 : ref.addEventListener('wheel', onWheel);
120
- // this is a react 19-ism to have a cleanup in the ref callback
121
- // https://react.dev/blog/2024/04/25/react-19#cleanup-functions-for-refs
122
- // note: it warns in earlier versions of react
132
+ (_a = mainSyntenyCanvasRefp.current) === null || _a === void 0 ? void 0 : _a.addEventListener('wheel', onWheel);
123
133
  return () => {
124
- ref === null || ref === void 0 ? void 0 : ref.removeEventListener('wheel', onWheel);
134
+ var _a;
135
+ (_a = mainSyntenyCanvasRefp.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('wheel', onWheel);
125
136
  };
126
- },
127
- // eslint-disable-next-line react-hooks/exhaustive-deps
128
- [model, height, width]);
137
+ // eslint-disable-next-line react-hooks/exhaustive-deps
138
+ }, [model, height, width]);
129
139
  // biome-ignore lint/correctness/useExhaustiveDependencies:
130
- const k3 = (0, react_1.useCallback)((ref) => {
140
+ const clickMapCanvasRef = (0, react_1.useCallback)((ref) => {
131
141
  model.setClickMapCanvasRef(ref);
132
142
  },
133
143
  // eslint-disable-next-line react-hooks/exhaustive-deps
134
144
  [model, height, width]);
135
145
  // biome-ignore lint/correctness/useExhaustiveDependencies:
136
- const k4 = (0, react_1.useCallback)((ref) => {
146
+ const cigarClickMapCanvasRef = (0, react_1.useCallback)((ref) => {
137
147
  model.setCigarClickMapCanvasRef(ref);
138
148
  },
139
149
  // eslint-disable-next-line react-hooks/exhaustive-deps
140
150
  [model, height, width]);
141
151
  return (react_1.default.createElement("div", { className: classes.rel },
142
- react_1.default.createElement("canvas", { ref: k1, width: width, height: height, className: cx(classes.abs, classes.none) }),
143
- react_1.default.createElement("canvas", { ref: k2, onMouseMove: event => {
152
+ react_1.default.createElement("canvas", { ref: mouseoverDetectionCanvasRef, width: width, height: height, className: classes.mouseoverCanvas }),
153
+ react_1.default.createElement("canvas", { ref: mainSyntenyCanvasRef, onMouseMove: event => {
144
154
  var _a;
145
155
  if (mouseCurrDownX !== undefined) {
146
156
  xOffset.current += mouseCurrDownX - event.clientX;
147
157
  setMouseCurrDownX(event.clientX);
148
- if (currScrollFrame.current === undefined) {
149
- currScrollFrame.current = requestAnimationFrame(() => {
158
+ if (!scheduled.current) {
159
+ scheduled.current = true;
160
+ window.requestAnimationFrame(() => {
150
161
  (0, mobx_1.transaction)(() => {
151
162
  for (const v of view.views) {
152
163
  v.horizontalScroll(xOffset.current);
153
164
  }
154
165
  xOffset.current = 0;
155
- currScrollFrame.current = undefined;
166
+ scheduled.current = false;
156
167
  });
157
168
  });
158
169
  }
@@ -186,7 +197,11 @@ const LinearSyntenyRendering = (0, mobx_react_1.observer)(function ({ model, })
186
197
  const { f, cigar } = model.featPositions[id];
187
198
  const unitMultiplier2 = Math.floor(drawSynteny_1.MAX_COLOR_RANGE / cigar.length);
188
199
  const cigarIdx = (0, drawSynteny_1.getId)(r2, g2, b2, unitMultiplier2);
189
- setTooltip((0, util_2.getTooltip)(f, cigar[cigarIdx], cigar[cigarIdx + 1]));
200
+ setTooltip((0, util_2.getTooltip)({
201
+ feature: f,
202
+ cigarOp: cigar[cigarIdx],
203
+ cigarOpLen: cigar[cigarIdx + 1],
204
+ }));
190
205
  }
191
206
  }
192
207
  }, onMouseLeave: () => {
@@ -204,9 +219,9 @@ const LinearSyntenyRendering = (0, mobx_react_1.observer)(function ({ model, })
204
219
  }
205
220
  }, onContextMenu: evt => {
206
221
  (0, util_2.onSynContextClick)(evt, model, setAnchorEl);
207
- }, "data-testid": "synteny_canvas", className: classes.abs, width: width, height: height }),
208
- react_1.default.createElement("canvas", { ref: k3, className: classes.pix, width: width, height: height }),
209
- react_1.default.createElement("canvas", { ref: k4, className: classes.pix, width: width, height: height }),
222
+ }, "data-testid": "synteny_canvas", className: classes.mainCanvas, width: width, height: height }),
223
+ react_1.default.createElement("canvas", { ref: clickMapCanvasRef, className: classes.pix, width: width, height: height }),
224
+ react_1.default.createElement("canvas", { ref: cigarClickMapCanvasRef, className: classes.pix, width: width, height: height }),
210
225
  mouseoverId && tooltip && currX && currY ? (react_1.default.createElement(SyntenyTooltip, { title: tooltip })) : null,
211
226
  anchorEl ? (react_1.default.createElement(SyntenyContextMenu_1.default, { model: model, anchorEl: anchorEl, onClose: () => {
212
227
  setAnchorEl(undefined);
@@ -39,13 +39,17 @@ function SyntenyContextMenu({ model, onClose, anchorEl, }) {
39
39
  const end = f.get('end');
40
40
  const refName = f.get('refName');
41
41
  const mate = f.get('mate');
42
- view.views[0].navToLocString(`${refName}:${start}-${end}`).catch((e) => {
43
- console.error(e);
44
- (0, util_1.getSession)(model).notifyError(`${e}`, e);
42
+ const l1 = view.views[model.level];
43
+ const l2 = view.views[model.level + 1];
44
+ l1.navToLocString(`${refName}:${start}-${end}`).catch((e) => {
45
+ const err = `${l1.assemblyNames[0]}:${e}`;
46
+ console.error(err);
47
+ (0, util_1.getSession)(model).notifyError(err, e);
45
48
  });
46
- view.views[1].navToLocString(`${mate.refName}:${mate.start}-${mate.end}`).catch((e) => {
47
- console.error(e);
48
- (0, util_1.getSession)(model).notifyError(`${e}`, e);
49
+ l2.navToLocString(`${mate.refName}:${mate.start}-${mate.end}`).catch((e) => {
50
+ const err = `${l2.assemblyNames[0]}:${e}`;
51
+ console.error(err);
52
+ (0, util_1.getSession)(model).notifyError(err, e);
49
53
  });
50
54
  },
51
55
  },
@@ -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(f: Feature, cigarOp?: string, cigarOpLen?: string): string;
39
+ export declare function getTooltip({ feature, cigarOp, cigarOpLen, }: {
40
+ feature: Feature;
41
+ cigarOp?: string;
42
+ cigarOpLen?: string;
43
+ }): string;
39
44
  export {};
@@ -10,12 +10,12 @@ exports.getTooltip = getTooltip;
10
10
  const util_1 = require("@jbrowse/core/util");
11
11
  // locals
12
12
  const drawSynteny_1 = require("../drawSynteny");
13
- function drawMatchSimple({ feature, ctx, offsets, cb, height, drawCurves, oobLimit, viewWidth, hideTiny, }) {
13
+ function drawMatchSimple({ feature, ctx, offsets, level, cb, height, drawCurves, oobLimit, viewWidth, hideTiny, }) {
14
14
  const { p11, p12, p21, p22 } = feature;
15
- const x11 = p11.offsetPx - offsets[0];
16
- const x12 = p12.offsetPx - offsets[0];
17
- const x21 = p21.offsetPx - offsets[1];
18
- const x22 = p22.offsetPx - offsets[1];
15
+ const x11 = p11.offsetPx - offsets[level];
16
+ const x12 = p12.offsetPx - offsets[level];
17
+ const x21 = p21.offsetPx - offsets[level + 1];
18
+ const x22 = p22.offsetPx - offsets[level + 1];
19
19
  const l1 = Math.abs(x12 - x11);
20
20
  const l2 = Math.abs(x22 - x21);
21
21
  const y1 = 0;
@@ -63,7 +63,6 @@ function drawBox(ctx, x1, x2, y1, x3, x4, y2) {
63
63
  ctx.lineTo(x3, y2);
64
64
  ctx.lineTo(x4, y2);
65
65
  ctx.closePath();
66
- ctx.fill();
67
66
  }
68
67
  function drawBezierBox(ctx, x1, x2, y1, x3, x4, y2, mid) {
69
68
  const len1 = Math.abs(x1 - x2);
@@ -83,13 +82,11 @@ function drawBezierBox(ctx, x1, x2, y1, x3, x4, y2, mid) {
83
82
  ctx.lineTo(x4, y2);
84
83
  ctx.bezierCurveTo(x4, mid, x1, mid, x1, y1);
85
84
  ctx.closePath();
86
- ctx.fill();
87
85
  }
88
86
  function onSynClick(event, model) {
89
87
  const view = (0, util_1.getContainingView)(model);
90
88
  const track = (0, util_1.getContainingTrack)(model);
91
- const ref1 = model.clickMapCanvas;
92
- const ref2 = model.cigarClickMapCanvas;
89
+ const { featPositions, numFeats, clickMapCanvas: ref1, cigarClickMapCanvas: ref2, level, } = model;
93
90
  if (!ref1 || !ref2) {
94
91
  return;
95
92
  }
@@ -102,18 +99,19 @@ function onSynClick(event, model) {
102
99
  const x = event.clientX - rect.left;
103
100
  const y = event.clientY - rect.top;
104
101
  const [r1, g1, b1] = ctx1.getImageData(x, y, 1, 1).data;
105
- const unitMultiplier = Math.floor(drawSynteny_1.MAX_COLOR_RANGE / model.numFeats);
102
+ const unitMultiplier = Math.floor(drawSynteny_1.MAX_COLOR_RANGE / numFeats);
106
103
  const id = (0, drawSynteny_1.getId)(r1, g1, b1, unitMultiplier);
107
- const feat = model.featPositions[id];
104
+ const feat = featPositions[id];
108
105
  if (feat) {
109
106
  const { f } = feat;
110
107
  model.setClickId(f.id());
111
108
  const session = (0, util_1.getSession)(model);
112
109
  if ((0, util_1.isSessionModelWithWidgets)(session)) {
113
- session.showWidget(session.addWidget('BaseFeatureWidget', 'baseFeature', {
110
+ session.showWidget(session.addWidget('SyntenyFeatureWidget', 'syntenyFeature', {
114
111
  view,
115
112
  track,
116
113
  featureData: f.toJSON(),
114
+ level,
117
115
  }));
118
116
  }
119
117
  }
@@ -144,9 +142,9 @@ function onSynContextClick(event, model, setAnchorEl) {
144
142
  setAnchorEl({ clientX, clientY, feature: f });
145
143
  }
146
144
  }
147
- function getTooltip(f, cigarOp, cigarOpLen) {
145
+ function getTooltip({ feature, cigarOp, cigarOpLen, }) {
148
146
  // @ts-expect-error
149
- const f1 = f.toJSON();
147
+ const f1 = feature.toJSON();
150
148
  const f2 = f1.mate;
151
149
  const l1 = f1.end - f1.start;
152
150
  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): undefined;
4
+ export declare function drawRef(model: LinearSyntenyDisplayModel, ctx1: CanvasRenderingContext2D, ctx3?: CanvasRenderingContext2D): void;
5
5
  export declare function drawMouseoverSynteny(model: LinearSyntenyDisplayModel): void;
@@ -31,25 +31,24 @@ function drawRef(model, ctx1, ctx3) {
31
31
  const view = (0, util_1.getContainingView)(model);
32
32
  const drawCurves = view.drawCurves;
33
33
  const drawCIGAR = view.drawCIGAR;
34
- const height = view.middleComparativeHeight;
34
+ const { level, height, featPositions } = model;
35
35
  const width = view.width;
36
36
  const bpPerPxs = view.views.map(v => v.bpPerPx);
37
37
  if (ctx3) {
38
38
  ctx3.imageSmoothingEnabled = false;
39
39
  }
40
40
  ctx1.beginPath();
41
- const featPos = model.featPositions;
42
41
  const offsets = view.views.map(v => v.offsetPx);
43
- const unitMultiplier = Math.floor(exports.MAX_COLOR_RANGE / featPos.length);
42
+ const unitMultiplier = Math.floor(exports.MAX_COLOR_RANGE / featPositions.length);
44
43
  // this loop is optimized to draw many thin lines with a single ctx.stroke
45
44
  // call, a separate loop below draws larger boxes
46
45
  ctx1.fillStyle = colorMap.M;
47
46
  ctx1.strokeStyle = colorMap.M;
48
- for (const { p11, p12, p21, p22 } of featPos) {
49
- const x11 = p11.offsetPx - offsets[0];
50
- const x12 = p12.offsetPx - offsets[0];
51
- const x21 = p21.offsetPx - offsets[1];
52
- const x22 = p22.offsetPx - offsets[1];
47
+ for (const { p11, p12, p21, p22 } of featPositions) {
48
+ const x11 = p11.offsetPx - offsets[level];
49
+ const x12 = p12.offsetPx - offsets[level];
50
+ const x21 = p21.offsetPx - offsets[level + 1];
51
+ const x22 = p22.offsetPx - offsets[level + 1];
53
52
  const l1 = Math.abs(x12 - x11);
54
53
  const l2 = Math.abs(x22 - x21);
55
54
  const y1 = 0;
@@ -75,11 +74,11 @@ function drawRef(model, ctx1, ctx3) {
75
74
  // ctx.stroke once is much more efficient than calling stroke() many times
76
75
  ctx1.fillStyle = colorMap.M;
77
76
  ctx1.strokeStyle = colorMap.M;
78
- for (const { p11, p12, p21, p22, f, cigar } of featPos) {
79
- const x11 = p11.offsetPx - offsets[0];
80
- const x12 = p12.offsetPx - offsets[0];
81
- const x21 = p21.offsetPx - offsets[1];
82
- const x22 = p22.offsetPx - offsets[1];
77
+ for (const { p11, p12, p21, p22, f, cigar } of featPositions) {
78
+ const x11 = p11.offsetPx - offsets[level];
79
+ const x12 = p12.offsetPx - offsets[level];
80
+ const x21 = p21.offsetPx - offsets[level + 1];
81
+ const x22 = p22.offsetPx - offsets[level + 1];
83
82
  const l1 = Math.abs(x12 - x11);
84
83
  const l2 = Math.abs(x22 - x21);
85
84
  const minX = Math.min(x21, x22);
@@ -114,8 +113,8 @@ function drawRef(model, ctx1, ctx3) {
114
113
  px1 = cx1;
115
114
  px2 = cx2;
116
115
  }
117
- const d1 = len / bpPerPxs[0];
118
- const d2 = len / bpPerPxs[1];
116
+ const d1 = len / bpPerPxs[level];
117
+ const d2 = len / bpPerPxs[level + 1];
119
118
  if (op === 'M' || op === '=' || op === 'X') {
120
119
  cx1 += d1 * rev1;
121
120
  cx2 += d2 * rev2;
@@ -141,16 +140,18 @@ function drawRef(model, ctx1, ctx3) {
141
140
  continuingFlag = true;
142
141
  }
143
142
  else {
144
- // allow rendering the dominant color when using continuing flag
145
- // if the last element of continuing was a large feature, else
146
- // just use match
143
+ // allow rendering the dominant color when using continuing
144
+ // flag if the last element of continuing was a large
145
+ // feature, else just use match
147
146
  ctx1.fillStyle =
148
147
  colorMap[(continuingFlag && d1 > 1) || d2 > 1 ? op : 'M'];
149
148
  continuingFlag = false;
150
149
  (0, util_2.draw)(ctx1, px1, cx1, y1, cx2, px2, y2, mid, drawCurves);
150
+ ctx1.fill();
151
151
  if (ctx3) {
152
152
  ctx3.fillStyle = makeColor(idx);
153
153
  (0, util_2.draw)(ctx3, px1, cx1, y1, cx2, px2, y2, mid, drawCurves);
154
+ ctx3.fill();
154
155
  }
155
156
  }
156
157
  }
@@ -158,6 +159,7 @@ function drawRef(model, ctx1, ctx3) {
158
159
  }
159
160
  else {
160
161
  (0, util_2.draw)(ctx1, x11, x12, y1, x22, x21, y2, mid, drawCurves);
162
+ ctx1.fill();
161
163
  }
162
164
  }
163
165
  }
@@ -168,8 +170,8 @@ function drawRef(model, ctx1, ctx3) {
168
170
  }
169
171
  ctx2.imageSmoothingEnabled = false;
170
172
  ctx2.clearRect(0, 0, width, height);
171
- for (let i = 0; i < featPos.length; i++) {
172
- const feature = featPos[i];
173
+ for (let i = 0; i < featPositions.length; i++) {
174
+ const feature = featPositions[i];
173
175
  const idx = i * unitMultiplier + 1;
174
176
  ctx2.fillStyle = makeColor(idx);
175
177
  // too many click map false positives with colored stroked lines
@@ -180,6 +182,7 @@ function drawRef(model, ctx1, ctx3) {
180
182
  feature,
181
183
  ctx: ctx2,
182
184
  drawCurves,
185
+ level,
183
186
  offsets,
184
187
  oobLimit,
185
188
  viewWidth: view.width,
@@ -187,15 +190,14 @@ function drawRef(model, ctx1, ctx3) {
187
190
  height,
188
191
  });
189
192
  }
190
- return undefined;
191
193
  }
192
194
  function drawMouseoverSynteny(model) {
193
195
  var _a;
194
- const { clickId, mouseoverId } = model;
196
+ const { level, clickId, mouseoverId } = model;
195
197
  const highResolutionScaling = 1;
196
198
  const view = (0, util_1.getContainingView)(model);
197
199
  const drawCurves = view.drawCurves;
198
- const height = view.middleComparativeHeight;
200
+ const height = model.height;
199
201
  const width = view.width;
200
202
  const ctx = (_a = model.mouseoverCanvas) === null || _a === void 0 ? void 0 : _a.getContext('2d');
201
203
  const offsets = view.views.map(v => v.offsetPx);
@@ -205,14 +207,16 @@ function drawMouseoverSynteny(model) {
205
207
  ctx.resetTransform();
206
208
  ctx.scale(highResolutionScaling, highResolutionScaling);
207
209
  ctx.clearRect(0, 0, width, height);
210
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.9)';
211
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
208
212
  const feature1 = model.featMap[mouseoverId || ''];
209
213
  if (feature1) {
210
- ctx.fillStyle = 'rgb(0,0,0,0.1)';
211
214
  (0, util_2.drawMatchSimple)({
212
215
  cb: ctx => {
213
216
  ctx.fill();
214
217
  },
215
218
  feature: feature1,
219
+ level,
216
220
  ctx,
217
221
  oobLimit,
218
222
  viewWidth: view.width,
@@ -223,13 +227,13 @@ function drawMouseoverSynteny(model) {
223
227
  }
224
228
  const feature2 = model.featMap[clickId || ''];
225
229
  if (feature2) {
226
- ctx.strokeStyle = 'rgb(0, 0, 0, 0.9)';
227
230
  (0, util_2.drawMatchSimple)({
228
231
  cb: ctx => {
229
232
  ctx.stroke();
230
233
  },
231
234
  feature: feature2,
232
235
  ctx,
236
+ level,
233
237
  oobLimit,
234
238
  viewWidth: view.width,
235
239
  drawCurves,
@@ -40,7 +40,7 @@ function LinearSyntenyDisplayF(pluginManager) {
40
40
  configSchema,
41
41
  stateModel: (0, model_1.default)(configSchema),
42
42
  trackType: 'SyntenyTrack',
43
- viewType: 'LinearSyntenyView',
43
+ viewType: 'LinearSyntenyViewHelper',
44
44
  ReactComponent: (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/Component')))),
45
45
  });
46
46
  });
@@ -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").IStateTreeNode<AnyConfigurationSchemaType>);
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
  /**
@@ -48,28 +48,51 @@ function stateModelFactory(configSchema) {
48
48
  configuration: (0, configuration_1.ConfigurationReference)(configSchema),
49
49
  }))
50
50
  .volatile(() => ({
51
- // canvas used for drawing visible screen
51
+ /**
52
+ * #volatile
53
+ * canvas used for drawing visible screen
54
+ */
52
55
  mainCanvas: null,
53
- // canvas used for drawing click map with feature ids
54
- // this renders a unique color per alignment, so that it can be re-traced
55
- // after a feature click with getImageData at that pixel
56
+ /**
57
+ * #volatile
58
+ * canvas used for drawing click map with feature ids this renders a
59
+ * unique color per alignment, so that it can be re-traced after a
60
+ * feature click with getImageData at that pixel
61
+ */
56
62
  clickMapCanvas: null,
57
- // canvas used for drawing click map with cigar data
58
- // this can show if you are mousing over a insertion/deletion. it is similar
59
- // in purpose to the clickMapRef but was not feasible to pack this into the
60
- // clickMapRef
63
+ /**
64
+ * #volatile
65
+ * canvas used for drawing click map with cigar data this can show if you
66
+ * are mousing over a insertion/deletion. it is similar in purpose to the
67
+ * clickMapRef but was not feasible to pack this into the clickMapRef
68
+ */
61
69
  cigarClickMapCanvas: null,
62
- // canvas for drawing mouseover shading
63
- // this is separate from the other code for speed: don't have to redraw
64
- // entire canvas to do a feature's mouseover shading
70
+ /**
71
+ * #volatile
72
+ * canvas for drawing mouseover shading this is separate from the other
73
+ * code for speed: don't have to redraw entire canvas to do a feature's
74
+ * mouseover shading
75
+ */
65
76
  mouseoverCanvas: null,
66
- // assigned by reaction
77
+ /**
78
+ * #volatile
79
+ * assigned by reaction
80
+ */
67
81
  featPositions: [],
68
- // currently mouse'd over feature
82
+ /**
83
+ * #volatile
84
+ * currently mouse'd over feature
85
+ */
69
86
  mouseoverId: undefined,
70
- // currently click'd over feature
87
+ /**
88
+ * #volatile
89
+ * currently click'd over feature
90
+ */
71
91
  clickId: undefined,
72
- // currently mouseover'd CIGAR subfeature
92
+ /**
93
+ * #volatile
94
+ * currently mouseover'd CIGAR subfeature
95
+ */
73
96
  cigarMouseoverId: -1,
74
97
  }))
75
98
  .actions(self => ({