@jbrowse/plugin-linear-comparative-view 2.15.4 → 2.16.0

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 (101) hide show
  1. package/dist/LaunchLinearSyntenyView.js +41 -11
  2. package/dist/LinearComparativeDisplay/stateModelFactory.d.ts +14 -9
  3. package/dist/LinearComparativeDisplay/stateModelFactory.js +8 -9
  4. package/dist/LinearComparativeView/components/Header.d.ts +2 -3
  5. package/dist/LinearComparativeView/components/Header.js +72 -62
  6. package/dist/LinearComparativeView/components/HeaderSearchBoxes.d.ts +6 -0
  7. package/dist/LinearComparativeView/components/HeaderSearchBoxes.js +34 -0
  8. package/dist/LinearComparativeView/components/LinearComparativeRenderArea.d.ts +6 -0
  9. package/dist/LinearComparativeView/components/LinearComparativeRenderArea.js +61 -0
  10. package/dist/LinearComparativeView/components/LinearComparativeView.d.ts +2 -4
  11. package/dist/LinearComparativeView/components/LinearComparativeView.js +3 -67
  12. package/dist/LinearComparativeView/components/Rubberband.js +1 -1
  13. package/dist/LinearComparativeView/index.js +3 -0
  14. package/dist/LinearComparativeView/model.d.ts +265 -12
  15. package/dist/LinearComparativeView/model.js +45 -75
  16. package/dist/LinearSyntenyDisplay/afterAttach.js +5 -3
  17. package/dist/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +32 -24
  18. package/dist/LinearSyntenyDisplay/components/SyntenyContextMenu.js +12 -6
  19. package/dist/LinearSyntenyDisplay/components/util.d.ts +2 -1
  20. package/dist/LinearSyntenyDisplay/components/util.js +5 -5
  21. package/dist/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
  22. package/dist/LinearSyntenyDisplay/drawSynteny.js +28 -22
  23. package/dist/LinearSyntenyDisplay/index.js +1 -1
  24. package/dist/LinearSyntenyDisplay/model.d.ts +12 -11
  25. package/dist/LinearSyntenyDisplay/model.js +7 -0
  26. package/dist/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts} +2 -3
  27. package/dist/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js} +3 -3
  28. package/dist/LinearSyntenyView/components/ImportForm/LinearSyntenyImportForm.js +195 -0
  29. package/dist/LinearSyntenyView/components/ImportForm/Spacer.d.ts +2 -0
  30. package/dist/LinearSyntenyView/components/ImportForm/Spacer.js +10 -0
  31. package/dist/LinearSyntenyView/components/ImportForm/TrackSelector.d.ts +10 -0
  32. package/dist/LinearSyntenyView/components/ImportForm/{ImportSyntenyTrackSelector.js → TrackSelector.js} +15 -20
  33. package/dist/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.d.ts +14 -0
  34. package/dist/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.js +52 -0
  35. package/dist/LinearSyntenyView/components/LinearSyntenyView.js +3 -3
  36. package/dist/LinearSyntenyView/index.js +1 -1
  37. package/dist/LinearSyntenyView/model.d.ts +267 -9
  38. package/dist/LinearSyntenyView/model.js +2 -2
  39. package/dist/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.d.ts +12 -0
  40. package/dist/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.js +19 -0
  41. package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.d.ts +1 -3
  42. package/dist/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +36 -27
  43. package/dist/LinearSyntenyViewHelper/index.d.ts +2 -0
  44. package/dist/LinearSyntenyViewHelper/index.js +25 -0
  45. package/dist/LinearSyntenyViewHelper/stateModelFactory.d.ts +30 -0
  46. package/dist/LinearSyntenyViewHelper/stateModelFactory.js +105 -0
  47. package/dist/index.js +2 -0
  48. package/esm/LaunchLinearSyntenyView.js +41 -11
  49. package/esm/LinearComparativeDisplay/stateModelFactory.d.ts +14 -9
  50. package/esm/LinearComparativeDisplay/stateModelFactory.js +9 -10
  51. package/esm/LinearComparativeView/components/Header.d.ts +2 -3
  52. package/esm/LinearComparativeView/components/Header.js +73 -63
  53. package/esm/LinearComparativeView/components/HeaderSearchBoxes.d.ts +6 -0
  54. package/esm/LinearComparativeView/components/HeaderSearchBoxes.js +29 -0
  55. package/esm/LinearComparativeView/components/LinearComparativeRenderArea.d.ts +6 -0
  56. package/esm/LinearComparativeView/components/LinearComparativeRenderArea.js +56 -0
  57. package/esm/LinearComparativeView/components/LinearComparativeView.d.ts +2 -4
  58. package/esm/LinearComparativeView/components/LinearComparativeView.js +3 -67
  59. package/esm/LinearComparativeView/components/Rubberband.js +1 -1
  60. package/esm/LinearComparativeView/index.js +3 -0
  61. package/esm/LinearComparativeView/model.d.ts +265 -12
  62. package/esm/LinearComparativeView/model.js +47 -77
  63. package/esm/LinearSyntenyDisplay/afterAttach.js +6 -4
  64. package/esm/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +33 -25
  65. package/esm/LinearSyntenyDisplay/components/SyntenyContextMenu.js +12 -6
  66. package/esm/LinearSyntenyDisplay/components/util.d.ts +2 -1
  67. package/esm/LinearSyntenyDisplay/components/util.js +5 -5
  68. package/esm/LinearSyntenyDisplay/drawSynteny.d.ts +1 -1
  69. package/esm/LinearSyntenyDisplay/drawSynteny.js +28 -22
  70. package/esm/LinearSyntenyDisplay/index.js +1 -1
  71. package/esm/LinearSyntenyDisplay/model.d.ts +12 -11
  72. package/esm/LinearSyntenyDisplay/model.js +8 -1
  73. package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.d.ts → AddCustomTrack.d.ts} +2 -3
  74. package/esm/LinearSyntenyView/components/ImportForm/{ImportCustomTrack.js → AddCustomTrack.js} +3 -3
  75. package/esm/LinearSyntenyView/components/ImportForm/LinearSyntenyImportForm.js +167 -0
  76. package/esm/LinearSyntenyView/components/ImportForm/Spacer.d.ts +2 -0
  77. package/esm/LinearSyntenyView/components/ImportForm/Spacer.js +4 -0
  78. package/esm/LinearSyntenyView/components/ImportForm/TrackSelector.d.ts +10 -0
  79. package/esm/LinearSyntenyView/components/ImportForm/{ImportSyntenyTrackSelector.js → TrackSelector.js} +15 -20
  80. package/esm/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.d.ts +14 -0
  81. package/esm/LinearSyntenyView/components/ImportForm/TrackSelectorUtil.js +23 -0
  82. package/esm/LinearSyntenyView/components/LinearSyntenyView.js +3 -3
  83. package/esm/LinearSyntenyView/index.js +1 -1
  84. package/esm/LinearSyntenyView/model.d.ts +267 -9
  85. package/esm/LinearSyntenyView/model.js +2 -2
  86. package/esm/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.d.ts +12 -0
  87. package/esm/LinearSyntenyView/svgcomponents/SVGLinearGenomeView.js +13 -0
  88. package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.d.ts +1 -3
  89. package/esm/LinearSyntenyView/svgcomponents/SVGLinearSyntenyView.js +38 -29
  90. package/esm/LinearSyntenyViewHelper/index.d.ts +2 -0
  91. package/esm/LinearSyntenyViewHelper/index.js +19 -0
  92. package/esm/LinearSyntenyViewHelper/stateModelFactory.d.ts +30 -0
  93. package/esm/LinearSyntenyViewHelper/stateModelFactory.js +102 -0
  94. package/esm/index.js +2 -0
  95. package/package.json +2 -2
  96. package/dist/LinearSyntenyView/components/ImportForm/ImportSyntenyTrackSelector.d.ts +0 -9
  97. package/dist/LinearSyntenyView/components/ImportForm/index.js +0 -138
  98. package/esm/LinearSyntenyView/components/ImportForm/ImportSyntenyTrackSelector.d.ts +0 -9
  99. package/esm/LinearSyntenyView/components/ImportForm/index.js +0 -110
  100. /package/dist/LinearSyntenyView/components/ImportForm/{index.d.ts → LinearSyntenyImportForm.d.ts} +0 -0
  101. /package/esm/LinearSyntenyView/components/ImportForm/{index.d.ts → LinearSyntenyImportForm.d.ts} +0 -0
@@ -1,4 +1,4 @@
1
- import React, { useState, useCallback, useRef, lazy } from 'react';
1
+ import React, { useState, useCallback, useRef, lazy, useEffect } from 'react';
2
2
  import { observer } from 'mobx-react';
3
3
  import { getContainingView } from '@jbrowse/core/util';
4
4
  import { transaction } from 'mobx';
@@ -17,21 +17,21 @@ const useStyles = makeStyles()({
17
17
  rel: {
18
18
  position: 'relative',
19
19
  },
20
- abs: {
20
+ mouseoverCanvas: {
21
21
  position: 'absolute',
22
- },
23
- none: {
24
22
  pointEvents: 'none',
25
23
  },
24
+ mainCanvas: {
25
+ position: 'absolute',
26
+ },
26
27
  });
27
28
  const LinearSyntenyRendering = observer(function ({ model, }) {
28
- const { classes, cx } = useStyles();
29
+ const { classes } = useStyles();
29
30
  const xOffset = useRef(0);
30
- const currScrollFrame = useRef();
31
31
  const view = getContainingView(model);
32
- const height = view.middleComparativeHeight;
33
32
  const width = view.width;
34
33
  const delta = useRef(0);
34
+ const scheduled = useRef(false);
35
35
  const timeout = useRef();
36
36
  const [anchorEl, setAnchorEl] = useState();
37
37
  const [tooltip, setTooltip] = useState('');
@@ -39,7 +39,8 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
39
39
  const [mouseCurrDownX, setMouseCurrDownX] = useState();
40
40
  const [mouseInitialDownX, setMouseInitialDownX] = useState();
41
41
  const [currY, setCurrY] = useState();
42
- const { mouseoverId } = model;
42
+ const { mouseoverId, height } = model;
43
+ const k2p = useRef();
43
44
  // these useCallbacks avoid new refs from being created on any mouseover,
44
45
  // etc.
45
46
  // biome-ignore lint/correctness/useExhaustiveDependencies:
@@ -51,6 +52,13 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
51
52
  // biome-ignore lint/correctness/useExhaustiveDependencies:
52
53
  const k2 = useCallback((ref) => {
53
54
  model.setMainCanvasRef(ref);
55
+ k2p.current = ref; // this ref is additionally used in useEffect below
56
+ },
57
+ // eslint-disable-next-line react-hooks/exhaustive-deps
58
+ [model, height, width]);
59
+ // biome-ignore lint/correctness/useExhaustiveDependencies:
60
+ useEffect(() => {
61
+ var _a;
54
62
  function onWheel(event) {
55
63
  event.preventDefault();
56
64
  if (event.ctrlKey) {
@@ -62,11 +70,12 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
62
70
  clearTimeout(timeout.current);
63
71
  }
64
72
  timeout.current = setTimeout(() => {
73
+ var _a;
65
74
  for (const v of view.views) {
66
75
  v.setScaleFactor(1);
67
76
  v.zoomTo(delta.current > 0
68
77
  ? v.bpPerPx * (1 + delta.current)
69
- : v.bpPerPx / (1 - delta.current), event.clientX - ((ref === null || ref === void 0 ? void 0 : ref.getBoundingClientRect().left) || 0));
78
+ : v.bpPerPx / (1 - delta.current), event.clientX - (((_a = k2p.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().left) || 0));
70
79
  }
71
80
  delta.current = 0;
72
81
  }, 300);
@@ -75,29 +84,27 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
75
84
  if (Math.abs(event.deltaY) < Math.abs(event.deltaX)) {
76
85
  xOffset.current += event.deltaX / 2;
77
86
  }
78
- if (currScrollFrame.current === undefined) {
79
- currScrollFrame.current = requestAnimationFrame(() => {
87
+ if (!scheduled.current) {
88
+ scheduled.current = true;
89
+ window.requestAnimationFrame(() => {
80
90
  transaction(() => {
81
91
  for (const v of view.views) {
82
92
  v.horizontalScroll(xOffset.current);
83
93
  }
84
94
  xOffset.current = 0;
85
- currScrollFrame.current = undefined;
95
+ scheduled.current = false;
86
96
  });
87
97
  });
88
98
  }
89
99
  }
90
100
  }
91
- ref === null || ref === void 0 ? void 0 : ref.addEventListener('wheel', onWheel);
92
- // this is a react 19-ism to have a cleanup in the ref callback
93
- // https://react.dev/blog/2024/04/25/react-19#cleanup-functions-for-refs
94
- // note: it warns in earlier versions of react
101
+ (_a = k2p.current) === null || _a === void 0 ? void 0 : _a.addEventListener('wheel', onWheel);
95
102
  return () => {
96
- ref === null || ref === void 0 ? void 0 : ref.removeEventListener('wheel', onWheel);
103
+ var _a;
104
+ (_a = k2p.current) === null || _a === void 0 ? void 0 : _a.removeEventListener('wheel', onWheel);
97
105
  };
98
- },
99
- // eslint-disable-next-line react-hooks/exhaustive-deps
100
- [model, height, width]);
106
+ // eslint-disable-next-line react-hooks/exhaustive-deps
107
+ }, [model, height, width]);
101
108
  // biome-ignore lint/correctness/useExhaustiveDependencies:
102
109
  const k3 = useCallback((ref) => {
103
110
  model.setClickMapCanvasRef(ref);
@@ -111,20 +118,21 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
111
118
  // eslint-disable-next-line react-hooks/exhaustive-deps
112
119
  [model, height, width]);
113
120
  return (React.createElement("div", { className: classes.rel },
114
- React.createElement("canvas", { ref: k1, width: width, height: height, className: cx(classes.abs, classes.none) }),
121
+ React.createElement("canvas", { ref: k1, width: width, height: height, className: classes.mouseoverCanvas }),
115
122
  React.createElement("canvas", { ref: k2, onMouseMove: event => {
116
123
  var _a;
117
124
  if (mouseCurrDownX !== undefined) {
118
125
  xOffset.current += mouseCurrDownX - event.clientX;
119
126
  setMouseCurrDownX(event.clientX);
120
- if (currScrollFrame.current === undefined) {
121
- currScrollFrame.current = requestAnimationFrame(() => {
127
+ if (!scheduled.current) {
128
+ scheduled.current = true;
129
+ window.requestAnimationFrame(() => {
122
130
  transaction(() => {
123
131
  for (const v of view.views) {
124
132
  v.horizontalScroll(xOffset.current);
125
133
  }
126
134
  xOffset.current = 0;
127
- currScrollFrame.current = undefined;
135
+ scheduled.current = false;
128
136
  });
129
137
  });
130
138
  }
@@ -176,7 +184,7 @@ const LinearSyntenyRendering = observer(function ({ model, }) {
176
184
  }
177
185
  }, onContextMenu: evt => {
178
186
  onSynContextClick(evt, model, setAnchorEl);
179
- }, "data-testid": "synteny_canvas", className: classes.abs, width: width, height: height }),
187
+ }, "data-testid": "synteny_canvas", className: classes.mainCanvas, width: width, height: height }),
180
188
  React.createElement("canvas", { ref: k3, className: classes.pix, width: width, height: height }),
181
189
  React.createElement("canvas", { ref: k4, className: classes.pix, width: width, height: height }),
182
190
  mouseoverId && tooltip && currX && currY ? (React.createElement(SyntenyTooltip, { title: tooltip })) : null,
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { getContainingView, getSession } from '@jbrowse/core/util';
3
3
  import { Menu } from '@jbrowse/core/ui';
4
+ import { getParent } from 'mobx-state-tree';
4
5
  export default function SyntenyContextMenu({ model, onClose, anchorEl, }) {
5
6
  const view = getContainingView(model);
6
7
  const { clientX, clientY, feature } = anchorEl;
@@ -29,17 +30,22 @@ export default function SyntenyContextMenu({ model, onClose, anchorEl, }) {
29
30
  label: 'Center on feature',
30
31
  onClick: () => {
31
32
  const { f } = feature;
33
+ const track = getParent(model, 4);
32
34
  const start = f.get('start');
33
35
  const end = f.get('end');
34
36
  const refName = f.get('refName');
35
37
  const mate = f.get('mate');
36
- view.views[0].navToLocString(`${refName}:${start}-${end}`).catch((e) => {
37
- console.error(e);
38
- getSession(model).notifyError(`${e}`, e);
38
+ const l1 = view.views[track.level];
39
+ const l2 = view.views[track.level + 1];
40
+ l1.navToLocString(`${refName}:${start}-${end}`).catch((e) => {
41
+ const err = `${l1.assemblyNames[0]}:${e}`;
42
+ console.error(err);
43
+ getSession(model).notifyError(err, e);
39
44
  });
40
- view.views[1].navToLocString(`${mate.refName}:${mate.start}-${mate.end}`).catch((e) => {
41
- console.error(e);
42
- getSession(model).notifyError(`${e}`, e);
45
+ l2.navToLocString(`${mate.refName}:${mate.start}-${mate.end}`).catch((e) => {
46
+ const err = `${l2.assemblyNames[0]}:${e}`;
47
+ console.error(err);
48
+ getSession(model).notifyError(err, e);
43
49
  });
44
50
  },
45
51
  },
@@ -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;
@@ -1,12 +1,12 @@
1
1
  import { assembleLocString, doesIntersect2, getSession, isSessionModelWithWidgets, getContainingTrack, getContainingView, } from '@jbrowse/core/util';
2
2
  // locals
3
3
  import { getId, MAX_COLOR_RANGE } from '../drawSynteny';
4
- export function drawMatchSimple({ feature, ctx, offsets, cb, height, drawCurves, oobLimit, viewWidth, hideTiny, }) {
4
+ export function drawMatchSimple({ feature, ctx, offsets, level, cb, height, drawCurves, oobLimit, viewWidth, hideTiny, }) {
5
5
  const { p11, p12, p21, p22 } = feature;
6
- const x11 = p11.offsetPx - offsets[0];
7
- const x12 = p12.offsetPx - offsets[0];
8
- const x21 = p21.offsetPx - offsets[1];
9
- const x22 = p22.offsetPx - offsets[1];
6
+ const x11 = p11.offsetPx - offsets[level];
7
+ const x12 = p12.offsetPx - offsets[level];
8
+ const x21 = p21.offsetPx - offsets[level + 1];
9
+ const x22 = p22.offsetPx - offsets[level + 1];
10
10
  const l1 = Math.abs(x12 - x11);
11
11
  const l2 = Math.abs(x22 - x21);
12
12
  const y1 = 0;
@@ -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;
@@ -1,5 +1,6 @@
1
1
  import { doesIntersect2, getContainingView } from '@jbrowse/core/util';
2
2
  import { draw, drawMatchSimple } from './components/util';
3
+ import { getParent } from 'mobx-state-tree';
3
4
  export const MAX_COLOR_RANGE = 255 * 255 * 255; // max color range
4
5
  function makeColor(idx) {
5
6
  const r = Math.floor(idx / (255 * 255)) % 255;
@@ -23,27 +24,28 @@ export function getId(r, g, b, unitMultiplier) {
23
24
  export function drawRef(model, ctx1, ctx3) {
24
25
  var _a;
25
26
  const view = getContainingView(model);
27
+ // @ts-expect-error
28
+ const level = getParent(model, 4).level;
26
29
  const drawCurves = view.drawCurves;
27
30
  const drawCIGAR = view.drawCIGAR;
28
- const height = view.middleComparativeHeight;
31
+ const { height, featPositions } = model;
29
32
  const width = view.width;
30
33
  const bpPerPxs = view.views.map(v => v.bpPerPx);
31
34
  if (ctx3) {
32
35
  ctx3.imageSmoothingEnabled = false;
33
36
  }
34
37
  ctx1.beginPath();
35
- const featPos = model.featPositions;
36
38
  const offsets = view.views.map(v => v.offsetPx);
37
- const unitMultiplier = Math.floor(MAX_COLOR_RANGE / featPos.length);
39
+ const unitMultiplier = Math.floor(MAX_COLOR_RANGE / featPositions.length);
38
40
  // this loop is optimized to draw many thin lines with a single ctx.stroke
39
41
  // call, a separate loop below draws larger boxes
40
42
  ctx1.fillStyle = colorMap.M;
41
43
  ctx1.strokeStyle = colorMap.M;
42
- for (const { p11, p12, p21, p22 } of featPos) {
43
- const x11 = p11.offsetPx - offsets[0];
44
- const x12 = p12.offsetPx - offsets[0];
45
- const x21 = p21.offsetPx - offsets[1];
46
- const x22 = p22.offsetPx - offsets[1];
44
+ for (const { p11, p12, p21, p22 } of featPositions) {
45
+ const x11 = p11.offsetPx - offsets[level];
46
+ const x12 = p12.offsetPx - offsets[level];
47
+ const x21 = p21.offsetPx - offsets[level + 1];
48
+ const x22 = p22.offsetPx - offsets[level + 1];
47
49
  const l1 = Math.abs(x12 - x11);
48
50
  const l2 = Math.abs(x22 - x21);
49
51
  const y1 = 0;
@@ -69,11 +71,11 @@ export function drawRef(model, ctx1, ctx3) {
69
71
  // ctx.stroke once is much more efficient than calling stroke() many times
70
72
  ctx1.fillStyle = colorMap.M;
71
73
  ctx1.strokeStyle = colorMap.M;
72
- for (const { p11, p12, p21, p22, f, cigar } of featPos) {
73
- const x11 = p11.offsetPx - offsets[0];
74
- const x12 = p12.offsetPx - offsets[0];
75
- const x21 = p21.offsetPx - offsets[1];
76
- const x22 = p22.offsetPx - offsets[1];
74
+ for (const { p11, p12, p21, p22, f, cigar } of featPositions) {
75
+ const x11 = p11.offsetPx - offsets[level];
76
+ const x12 = p12.offsetPx - offsets[level];
77
+ const x21 = p21.offsetPx - offsets[level + 1];
78
+ const x22 = p22.offsetPx - offsets[level + 1];
77
79
  const l1 = Math.abs(x12 - x11);
78
80
  const l2 = Math.abs(x22 - x21);
79
81
  const minX = Math.min(x21, x22);
@@ -108,8 +110,8 @@ export function drawRef(model, ctx1, ctx3) {
108
110
  px1 = cx1;
109
111
  px2 = cx2;
110
112
  }
111
- const d1 = len / bpPerPxs[0];
112
- const d2 = len / bpPerPxs[1];
113
+ const d1 = len / bpPerPxs[level];
114
+ const d2 = len / bpPerPxs[level + 1];
113
115
  if (op === 'M' || op === '=' || op === 'X') {
114
116
  cx1 += d1 * rev1;
115
117
  cx2 += d2 * rev2;
@@ -135,9 +137,9 @@ export function drawRef(model, ctx1, ctx3) {
135
137
  continuingFlag = true;
136
138
  }
137
139
  else {
138
- // allow rendering the dominant color when using continuing flag
139
- // if the last element of continuing was a large feature, else
140
- // just use match
140
+ // allow rendering the dominant color when using continuing
141
+ // flag if the last element of continuing was a large
142
+ // feature, else just use match
141
143
  ctx1.fillStyle =
142
144
  colorMap[(continuingFlag && d1 > 1) || d2 > 1 ? op : 'M'];
143
145
  continuingFlag = false;
@@ -162,8 +164,8 @@ export function drawRef(model, ctx1, ctx3) {
162
164
  }
163
165
  ctx2.imageSmoothingEnabled = false;
164
166
  ctx2.clearRect(0, 0, width, height);
165
- for (let i = 0; i < featPos.length; i++) {
166
- const feature = featPos[i];
167
+ for (let i = 0; i < featPositions.length; i++) {
168
+ const feature = featPositions[i];
167
169
  const idx = i * unitMultiplier + 1;
168
170
  ctx2.fillStyle = makeColor(idx);
169
171
  // too many click map false positives with colored stroked lines
@@ -174,6 +176,7 @@ export function drawRef(model, ctx1, ctx3) {
174
176
  feature,
175
177
  ctx: ctx2,
176
178
  drawCurves,
179
+ level,
177
180
  offsets,
178
181
  oobLimit,
179
182
  viewWidth: view.width,
@@ -181,7 +184,6 @@ export function drawRef(model, ctx1, ctx3) {
181
184
  height,
182
185
  });
183
186
  }
184
- return undefined;
185
187
  }
186
188
  export function drawMouseoverSynteny(model) {
187
189
  var _a;
@@ -189,10 +191,12 @@ export function drawMouseoverSynteny(model) {
189
191
  const highResolutionScaling = 1;
190
192
  const view = getContainingView(model);
191
193
  const drawCurves = view.drawCurves;
192
- const height = view.middleComparativeHeight;
194
+ const height = model.height;
193
195
  const width = view.width;
194
196
  const ctx = (_a = model.mouseoverCanvas) === null || _a === void 0 ? void 0 : _a.getContext('2d');
195
197
  const offsets = view.views.map(v => v.offsetPx);
198
+ // @ts-expect-error
199
+ const level = getParent(model, 4).level;
196
200
  if (!ctx) {
197
201
  return;
198
202
  }
@@ -207,6 +211,7 @@ export function drawMouseoverSynteny(model) {
207
211
  ctx.fill();
208
212
  },
209
213
  feature: feature1,
214
+ level,
210
215
  ctx,
211
216
  oobLimit,
212
217
  viewWidth: view.width,
@@ -224,6 +229,7 @@ export function drawMouseoverSynteny(model) {
224
229
  },
225
230
  feature: feature2,
226
231
  ctx,
232
+ level,
227
233
  oobLimit,
228
234
  viewWidth: view.width,
229
235
  drawCurves,
@@ -11,7 +11,7 @@ export default function LinearSyntenyDisplayF(pluginManager) {
11
11
  configSchema,
12
12
  stateModel: stateModelFactory(configSchema),
13
13
  trackType: 'SyntenyTrack',
14
- viewType: 'LinearSyntenyView',
14
+ viewType: 'LinearSyntenyViewHelper',
15
15
  ReactComponent: lazy(() => import('./components/Component')),
16
16
  });
17
17
  });
@@ -24,7 +24,6 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
24
24
  } & {
25
25
  type: import("mobx-state-tree").ISimpleType<"LinearComparativeDisplay">;
26
26
  configuration: AnyConfigurationSchemaType;
27
- height: import("mobx-state-tree").IType<number | undefined, number, number>;
28
27
  } & {
29
28
  /**
30
29
  * #property
@@ -69,7 +68,9 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
69
68
  rendererTypeName: string;
70
69
  error: unknown;
71
70
  message: string | undefined;
72
- } & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IModelType<{
71
+ } & import("mobx-state-tree" /**
72
+ * #action
73
+ */).IStateTreeNode<import("mobx-state-tree").IModelType<{
73
74
  id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
74
75
  type: import("mobx-state-tree").ISimpleType<string>;
75
76
  rpcDriverName: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<string>>;
@@ -77,9 +78,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
77
78
  rendererTypeName: string;
78
79
  error: unknown;
79
80
  message: string | undefined;
80
- }, import("mobx-state-tree" /**
81
- * #action
82
- */)._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
81
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
83
82
  }> | null;
84
83
  readonly adapterConfig: any;
85
84
  readonly parentTrack: any;
@@ -116,7 +115,6 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
116
115
  } & import("mobx-state-tree/dist/internal").NonEmptyObject & any & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>);
117
116
  } & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>);
118
117
  } & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>;
119
- height: number;
120
118
  } & import("mobx-state-tree/dist/internal").NonEmptyObject & {
121
119
  rendererTypeName: string;
122
120
  error: unknown;
@@ -152,7 +150,9 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
152
150
  rendererTypeName: string;
153
151
  error: unknown;
154
152
  message: string | undefined;
155
- } & import("mobx-state-tree").IStateTreeNode<import("mobx-state-tree").IModelType<{
153
+ } & import("mobx-state-tree" /**
154
+ * #action
155
+ */).IStateTreeNode<import("mobx-state-tree").IModelType<{
156
156
  id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
157
157
  type: import("mobx-state-tree").ISimpleType<string>;
158
158
  rpcDriverName: import("mobx-state-tree").IMaybe<import("mobx-state-tree").ISimpleType<string>>;
@@ -160,9 +160,7 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
160
160
  rendererTypeName: string;
161
161
  error: unknown;
162
162
  message: string | undefined;
163
- }, import("mobx-state-tree" /**
164
- * #action
165
- */)._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
163
+ }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
166
164
  }> | null;
167
165
  readonly adapterConfig: any;
168
166
  readonly parentTrack: any;
@@ -188,7 +186,6 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
188
186
  } & {
189
187
  type: import("mobx-state-tree").ISimpleType<"LinearComparativeDisplay">;
190
188
  configuration: AnyConfigurationSchemaType;
191
- height: import("mobx-state-tree").IType<number | undefined, number, number>;
192
189
  }, {
193
190
  rendererTypeName: string;
194
191
  error: unknown;
@@ -314,6 +311,10 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
314
311
  * #getter
315
312
  */
316
313
  readonly trackIds: string[];
314
+ /**
315
+ * #getter
316
+ */
317
+ readonly height: number;
317
318
  /**
318
319
  * #getter
319
320
  */
@@ -1,4 +1,4 @@
1
- import { types } from 'mobx-state-tree';
1
+ import { types, getParent } from 'mobx-state-tree';
2
2
  import { getConf, ConfigurationReference, } from '@jbrowse/core/configuration';
3
3
  // locals
4
4
  import baseModelFactory from '../LinearComparativeDisplay/stateModelFactory';
@@ -111,6 +111,13 @@ function stateModelFactory(configSchema) {
111
111
  get trackIds() {
112
112
  return getConf(self, 'trackIds');
113
113
  },
114
+ /**
115
+ * #getter
116
+ */
117
+ get height() {
118
+ // @ts-expect-error
119
+ return getParent(self, 4).height;
120
+ },
114
121
  /**
115
122
  * #getter
116
123
  */
@@ -2,10 +2,9 @@ import React from 'react';
2
2
  import { SnapshotIn } from 'mobx-state-tree';
3
3
  import { AnyConfigurationModel } from '@jbrowse/core/configuration';
4
4
  type Conf = SnapshotIn<AnyConfigurationModel>;
5
- declare const ImportCustomTrack: ({ assembly1, assembly2, setSessionTrackData, }: {
6
- sessionTrackData: Conf;
5
+ declare const ImportCustomTrack: ({ assembly1, assembly2, setUserOpenedSyntenyTrack, }: {
7
6
  assembly1: string;
8
7
  assembly2: string;
9
- setSessionTrackData: (arg: Conf) => void;
8
+ setUserOpenedSyntenyTrack: (arg: Conf) => void;
10
9
  }) => React.JSX.Element;
11
10
  export default ImportCustomTrack;
@@ -66,7 +66,7 @@ function getAdapter({ radioOption, assembly1, assembly2, fileLocation, indexFile
66
66
  throw new Error(`Unknown to detect type ${radioOption} from filename (select radio button to clarify)`);
67
67
  }
68
68
  }
69
- const ImportCustomTrack = observer(function ({ assembly1, assembly2, setSessionTrackData, }) {
69
+ const ImportCustomTrack = observer(function ({ assembly1, assembly2, setUserOpenedSyntenyTrack, }) {
70
70
  const [bed2Location, setBed2Location] = useState();
71
71
  const [bed1Location, setBed1Location] = useState();
72
72
  const [fileLocation, setFileLocation] = useState();
@@ -81,7 +81,7 @@ const ImportCustomTrack = observer(function ({ assembly1, assembly2, setSessionT
81
81
  const fn = fileName ? basename(fileName) : 'MyTrack';
82
82
  const trackId = `${fn}-${Date.now()}`;
83
83
  setError(undefined);
84
- setSessionTrackData({
84
+ setUserOpenedSyntenyTrack({
85
85
  trackId,
86
86
  name: fn,
87
87
  assemblyNames: [assembly2, assembly1],
@@ -111,7 +111,7 @@ const ImportCustomTrack = observer(function ({ assembly1, assembly2, setSessionT
111
111
  fileLocation,
112
112
  indexFileLocation,
113
113
  radioOption,
114
- setSessionTrackData,
114
+ setUserOpenedSyntenyTrack,
115
115
  ]);
116
116
  return (React.createElement(Paper, { style: { padding: 12 } },
117
117
  error ? React.createElement(ErrorMessage, { error: error }) : null,