@jbrowse/plugin-linear-comparative-view 3.6.4 → 3.7.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 (59) hide show
  1. package/dist/LGVSyntenyDisplay/configSchemaF.js +1 -1
  2. package/dist/LGVSyntenyDisplay/model.d.ts +17 -2
  3. package/dist/LinearComparativeView/components/ColorBySelector.d.ts +5 -0
  4. package/dist/LinearComparativeView/components/ColorBySelector.js +54 -0
  5. package/dist/LinearComparativeView/components/Header.js +7 -2
  6. package/dist/LinearComparativeView/components/MinLengthSlider.d.ts +5 -0
  7. package/dist/LinearComparativeView/components/MinLengthSlider.js +47 -0
  8. package/dist/LinearComparativeView/components/OpacitySlider.d.ts +5 -0
  9. package/dist/LinearComparativeView/components/OpacitySlider.js +46 -0
  10. package/dist/LinearComparativeView/components/RubberbandSpan.js +2 -2
  11. package/dist/LinearComparativeView/components/SliderTooltip.d.ts +2 -0
  12. package/dist/LinearComparativeView/components/SliderTooltip.js +9 -0
  13. package/dist/LinearComparativeView/components/useRangeSelect.js +10 -14
  14. package/dist/LinearComparativeView/model.d.ts +7 -4
  15. package/dist/LinearComparativeView/model.js +4 -0
  16. package/dist/LinearSyntenyDisplay/afterAttach.js +5 -3
  17. package/dist/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +10 -5
  18. package/dist/LinearSyntenyDisplay/components/util.d.ts +2 -1
  19. package/dist/LinearSyntenyDisplay/components/util.js +43 -2
  20. package/dist/LinearSyntenyDisplay/drawSynteny.d.ts +3 -2
  21. package/dist/LinearSyntenyDisplay/drawSynteny.js +284 -45
  22. package/dist/LinearSyntenyDisplay/model.d.ts +6 -0
  23. package/dist/LinearSyntenyDisplay/model.js +12 -0
  24. package/dist/LinearSyntenyView/components/DiagonalizationProgressDialog.d.ts +6 -0
  25. package/dist/LinearSyntenyView/components/DiagonalizationProgressDialog.js +87 -0
  26. package/dist/LinearSyntenyView/model.d.ts +46 -15
  27. package/dist/LinearSyntenyView/model.js +70 -18
  28. package/dist/LinearSyntenyView/util/diagonalize.d.ts +27 -0
  29. package/dist/LinearSyntenyView/util/diagonalize.js +91 -0
  30. package/esm/LGVSyntenyDisplay/configSchemaF.js +1 -1
  31. package/esm/LGVSyntenyDisplay/model.d.ts +17 -2
  32. package/esm/LinearComparativeView/components/ColorBySelector.d.ts +5 -0
  33. package/esm/LinearComparativeView/components/ColorBySelector.js +49 -0
  34. package/esm/LinearComparativeView/components/Header.js +8 -3
  35. package/esm/LinearComparativeView/components/MinLengthSlider.d.ts +5 -0
  36. package/esm/LinearComparativeView/components/MinLengthSlider.js +42 -0
  37. package/esm/LinearComparativeView/components/OpacitySlider.d.ts +5 -0
  38. package/esm/LinearComparativeView/components/OpacitySlider.js +41 -0
  39. package/esm/LinearComparativeView/components/RubberbandSpan.js +2 -2
  40. package/esm/LinearComparativeView/components/SliderTooltip.d.ts +2 -0
  41. package/esm/LinearComparativeView/components/SliderTooltip.js +6 -0
  42. package/esm/LinearComparativeView/components/useRangeSelect.js +11 -15
  43. package/esm/LinearComparativeView/model.d.ts +7 -4
  44. package/esm/LinearComparativeView/model.js +4 -0
  45. package/esm/LinearSyntenyDisplay/afterAttach.js +6 -4
  46. package/esm/LinearSyntenyDisplay/components/LinearSyntenyRendering.js +10 -5
  47. package/esm/LinearSyntenyDisplay/components/util.d.ts +2 -1
  48. package/esm/LinearSyntenyDisplay/components/util.js +43 -3
  49. package/esm/LinearSyntenyDisplay/drawSynteny.d.ts +3 -2
  50. package/esm/LinearSyntenyDisplay/drawSynteny.js +283 -45
  51. package/esm/LinearSyntenyDisplay/model.d.ts +6 -0
  52. package/esm/LinearSyntenyDisplay/model.js +12 -0
  53. package/esm/LinearSyntenyView/components/DiagonalizationProgressDialog.d.ts +6 -0
  54. package/esm/LinearSyntenyView/components/DiagonalizationProgressDialog.js +85 -0
  55. package/esm/LinearSyntenyView/model.d.ts +46 -15
  56. package/esm/LinearSyntenyView/model.js +70 -18
  57. package/esm/LinearSyntenyView/util/diagonalize.d.ts +27 -0
  58. package/esm/LinearSyntenyView/util/diagonalize.js +88 -0
  59. package/package.json +5 -5
@@ -10,7 +10,7 @@ function configSchemaF(pluginManager) {
10
10
  const l2name = (mate === null || mate === void 0 ? void 0 : mate.name) || (mate === null || mate === void 0 ? void 0 : mate.id);
11
11
  return [
12
12
  l1name ? `Name1: ${l1name}` : '',
13
- l2name ? `Name1: ${l2name}` : '',
13
+ l2name ? `Name2: ${l2name}` : '',
14
14
  `Loc1: ${(0, util_1.assembleLocString)({
15
15
  refName: f.get('refName'),
16
16
  start: f.get('start'),
@@ -182,6 +182,7 @@ declare function stateModelFactory(schema: AnyConfigurationSchemaType): import("
182
182
  regionCannotBeRenderedText(_region: import("@jbrowse/core/util").Region): "" | "Force load to see features";
183
183
  regionCannotBeRendered(_region: import("@jbrowse/core/util").Region): import("react/jsx-runtime").JSX.Element | null;
184
184
  } & {
185
+ mouseoverExtraInformation: string | undefined;
185
186
  featureIdUnderMouse: undefined | string;
186
187
  contextMenuFeature: undefined | Feature;
187
188
  } & {
@@ -196,9 +197,22 @@ declare function stateModelFactory(schema: AnyConfigurationSchemaType): import("
196
197
  } & {
197
198
  readonly features: import("@jbrowse/core/util/compositeMap").default<string, Feature>;
198
199
  readonly featureUnderMouse: Feature | undefined;
200
+ readonly layoutFeatures: import("@jbrowse/core/util/compositeMap").default<string, [number, number, number, number] | [number, number, number, number, {
201
+ label?: string;
202
+ description?: string;
203
+ refName: string;
204
+ }]>;
199
205
  getFeatureOverlapping(blockKey: string, x: number, y: number): string | undefined;
200
- getFeatureByID(blockKey: string, id: string): [number, number, number, number] | undefined;
201
- searchFeatureByID(id: string): [number, number, number, number] | undefined;
206
+ getFeatureByID(blockKey: string, id: string): ([number, number, number, number] | [number, number, number, number, {
207
+ label?: string;
208
+ description?: string;
209
+ refName: string;
210
+ }]) | undefined;
211
+ searchFeatureByID(id: string): ([number, number, number, number] | [number, number, number, number, {
212
+ label?: string;
213
+ description?: string;
214
+ refName: string;
215
+ }]) | undefined;
202
216
  } & {
203
217
  addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
204
218
  deleteBlock(key: string): void;
@@ -207,6 +221,7 @@ declare function stateModelFactory(schema: AnyConfigurationSchemaType): import("
207
221
  clearFeatureSelection(): void;
208
222
  setFeatureIdUnderMouse(feature?: string): void;
209
223
  setContextMenuFeature(feature?: Feature): void;
224
+ setMouseoverExtraInformation(extra?: string): void;
210
225
  } & {
211
226
  reload(): Promise<void>;
212
227
  } & {
@@ -0,0 +1,5 @@
1
+ import type { LinearComparativeViewModel } from '../model';
2
+ declare const ColorBySelector: ({ model, }: {
3
+ model: LinearComparativeViewModel;
4
+ }) => import("react/jsx-runtime").JSX.Element;
5
+ export default ColorBySelector;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const CascadingMenuButton_1 = __importDefault(require("@jbrowse/core/ui/CascadingMenuButton"));
8
+ const Palette_1 = __importDefault(require("@mui/icons-material/Palette"));
9
+ const mobx_react_1 = require("mobx-react");
10
+ const ColorBySelector = (0, mobx_react_1.observer)(function ({ model, }) {
11
+ var _a, _b, _c;
12
+ const firstDisplay = (_b = (_a = model.levels[0]) === null || _a === void 0 ? void 0 : _a.tracks[0]) === null || _b === void 0 ? void 0 : _b.displays[0];
13
+ const colorBy = (_c = firstDisplay === null || firstDisplay === void 0 ? void 0 : firstDisplay.colorBy) !== null && _c !== void 0 ? _c : 'default';
14
+ const setColorBy = (value) => {
15
+ for (const level of model.levels) {
16
+ for (const track of level.tracks) {
17
+ for (const display of track.displays) {
18
+ ;
19
+ display.setColorBy(value);
20
+ }
21
+ }
22
+ }
23
+ };
24
+ return ((0, jsx_runtime_1.jsx)(CascadingMenuButton_1.default, { menuItems: [
25
+ {
26
+ label: 'Default',
27
+ type: 'radio',
28
+ checked: colorBy === 'default',
29
+ onClick: () => {
30
+ setColorBy('default');
31
+ },
32
+ helpText: 'Use the default color scheme with CIGAR operation coloring. Insertions, deletions, matches, and mismatches are shown in different colors with transparency.',
33
+ },
34
+ {
35
+ label: 'Strand',
36
+ type: 'radio',
37
+ checked: colorBy === 'strand',
38
+ onClick: () => {
39
+ setColorBy('strand');
40
+ },
41
+ helpText: 'Color alignments by strand orientation. Forward strand alignments and reverse strand alignments are shown in different colors, making it easy to identify inversions and strand-specific patterns.',
42
+ },
43
+ {
44
+ label: 'Query',
45
+ type: 'radio',
46
+ checked: colorBy === 'query',
47
+ onClick: () => {
48
+ setColorBy('query');
49
+ },
50
+ helpText: 'Color alignments by query sequence name. Each unique query sequence is assigned a consistent color based on its name, making it easy to visually distinguish between different sequences.',
51
+ },
52
+ ], children: (0, jsx_runtime_1.jsx)(Palette_1.default, {}) }));
53
+ });
54
+ exports.default = ColorBySelector;
@@ -12,17 +12,22 @@ const Search_1 = __importDefault(require("@mui/icons-material/Search"));
12
12
  const material_1 = require("@mui/material");
13
13
  const mobx_react_1 = require("mobx-react");
14
14
  const mui_1 = require("tss-react/mui");
15
+ const ColorBySelector_1 = __importDefault(require("./ColorBySelector"));
15
16
  const HeaderSearchBoxes_1 = __importDefault(require("./HeaderSearchBoxes"));
17
+ const MinLengthSlider_1 = __importDefault(require("./MinLengthSlider"));
18
+ const OpacitySlider_1 = __importDefault(require("./OpacitySlider"));
16
19
  const useStyles = (0, mui_1.makeStyles)()({
17
20
  inline: {
18
21
  display: 'inline-flex',
19
22
  },
20
23
  });
21
24
  const Header = (0, mobx_react_1.observer)(function ({ model, }) {
25
+ var _a, _b;
22
26
  const { classes } = useStyles();
23
- const { views } = model;
27
+ const { views, levels, showDynamicControls } = model;
24
28
  const [showSearchBoxes, setShowSearchBoxes] = (0, react_1.useState)(views.length <= 3);
25
29
  const [sideBySide, setSideBySide] = (0, react_1.useState)(views.length <= 3);
30
+ const hasDisplays = (_b = (_a = levels[0]) === null || _a === void 0 ? void 0 : _a.tracks[0]) === null || _b === void 0 ? void 0 : _b.displays[0];
26
31
  return ((0, jsx_runtime_1.jsxs)(material_1.FormGroup, { row: true, children: [(0, jsx_runtime_1.jsx)(CascadingMenuButton_1.default, { menuItems: [
27
32
  {
28
33
  label: 'Synteny track selectors',
@@ -77,6 +82,6 @@ const Header = (0, mobx_react_1.observer)(function ({ model, }) {
77
82
  setSideBySide(!sideBySide);
78
83
  },
79
84
  },
80
- ], children: (0, jsx_runtime_1.jsx)(Search_1.default, {}) }), showSearchBoxes ? ((0, jsx_runtime_1.jsx)("span", { className: sideBySide ? classes.inline : undefined, children: views.map(view => ((0, jsx_runtime_1.jsx)(HeaderSearchBoxes_1.default, { view: view }, view.id))) })) : null] }));
85
+ ], children: (0, jsx_runtime_1.jsx)(Search_1.default, {}) }), hasDisplays && showDynamicControls ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ColorBySelector_1.default, { model: model }), (0, jsx_runtime_1.jsx)(OpacitySlider_1.default, { model: model }), (0, jsx_runtime_1.jsx)(MinLengthSlider_1.default, { model: model })] })) : null, showSearchBoxes ? ((0, jsx_runtime_1.jsx)("span", { className: sideBySide ? classes.inline : undefined, children: views.map(view => ((0, jsx_runtime_1.jsx)(HeaderSearchBoxes_1.default, { view: view }, view.id))) })) : null] }));
81
86
  });
82
87
  exports.default = Header;
@@ -0,0 +1,5 @@
1
+ import type { LinearComparativeViewModel } from '../model';
2
+ declare const MinLengthSlider: ({ model, }: {
3
+ model: LinearComparativeViewModel;
4
+ }) => import("react/jsx-runtime").JSX.Element;
5
+ export default MinLengthSlider;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const material_1 = require("@mui/material");
9
+ const mobx_react_1 = require("mobx-react");
10
+ const mui_1 = require("tss-react/mui");
11
+ const SliderTooltip_1 = __importDefault(require("./SliderTooltip"));
12
+ const useStyles = (0, mui_1.makeStyles)()({
13
+ container: {
14
+ display: 'flex',
15
+ alignItems: 'center',
16
+ marginLeft: 16,
17
+ marginRight: 16,
18
+ minWidth: 150,
19
+ },
20
+ });
21
+ const MinLengthSlider = (0, mobx_react_1.observer)(function ({ model, }) {
22
+ var _a, _b, _c;
23
+ const { classes } = useStyles();
24
+ const { levels } = model;
25
+ const firstDisplay = (_b = (_a = levels[0]) === null || _a === void 0 ? void 0 : _a.tracks[0]) === null || _b === void 0 ? void 0 : _b.displays[0];
26
+ const minAlignmentLength = (_c = firstDisplay === null || firstDisplay === void 0 ? void 0 : firstDisplay.minAlignmentLength) !== null && _c !== void 0 ? _c : 0;
27
+ const [minLengthValue, setMinLengthValue] = (0, react_1.useState)(Math.log2(Math.max(1, minAlignmentLength)) * 100);
28
+ (0, react_1.useEffect)(() => {
29
+ setMinLengthValue(Math.log2(Math.max(1, minAlignmentLength)) * 100);
30
+ }, [minAlignmentLength]);
31
+ return ((0, jsx_runtime_1.jsxs)(material_1.Box, { className: classes.container, children: [(0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", style: { marginRight: 8 }, children: "Min length:" }), (0, jsx_runtime_1.jsx)(material_1.Slider, { value: minLengthValue, onChange: (_, val) => {
32
+ setMinLengthValue(val);
33
+ }, onChangeCommitted: () => {
34
+ const newMinLength = Math.round(2 ** (minLengthValue / 100));
35
+ for (const level of levels) {
36
+ for (const track of level.tracks) {
37
+ for (const display of track.displays) {
38
+ ;
39
+ display.setMinAlignmentLength(newMinLength);
40
+ }
41
+ }
42
+ }
43
+ }, min: 0, max: Math.log2(1000000) * 100, valueLabelDisplay: "auto", valueLabelFormat: newValue => Math.round(2 ** (newValue / 100)).toLocaleString(), size: "small", style: { minWidth: 100 }, slots: {
44
+ valueLabel: SliderTooltip_1.default,
45
+ } })] }));
46
+ });
47
+ exports.default = MinLengthSlider;
@@ -0,0 +1,5 @@
1
+ import type { LinearComparativeViewModel } from '../model';
2
+ declare const OpacitySlider: ({ model, }: {
3
+ model: LinearComparativeViewModel;
4
+ }) => import("react/jsx-runtime").JSX.Element;
5
+ export default OpacitySlider;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const material_1 = require("@mui/material");
8
+ const mobx_react_1 = require("mobx-react");
9
+ const mui_1 = require("tss-react/mui");
10
+ const SliderTooltip_1 = __importDefault(require("./SliderTooltip"));
11
+ const useStyles = (0, mui_1.makeStyles)()({
12
+ container: {
13
+ display: 'flex',
14
+ alignItems: 'center',
15
+ marginLeft: 16,
16
+ marginRight: 16,
17
+ minWidth: 150,
18
+ },
19
+ });
20
+ const OpacitySlider = (0, mobx_react_1.observer)(function ({ model, }) {
21
+ var _a, _b, _c;
22
+ const { classes } = useStyles();
23
+ const { levels } = model;
24
+ const firstDisplay = (_b = (_a = levels[0]) === null || _a === void 0 ? void 0 : _a.tracks[0]) === null || _b === void 0 ? void 0 : _b.displays[0];
25
+ const alpha = (_c = firstDisplay === null || firstDisplay === void 0 ? void 0 : firstDisplay.alpha) !== null && _c !== void 0 ? _c : 1;
26
+ const exponent = 3;
27
+ const alphaToSlider = (a) => Math.pow(a, 1 / exponent);
28
+ const sliderToAlpha = (s) => Math.pow(s, exponent);
29
+ const sliderValue = alphaToSlider(alpha);
30
+ const handleAlphaChange = (_event, value) => {
31
+ const sliderVal = typeof value === 'number' ? value : value[0];
32
+ const newAlpha = sliderToAlpha(sliderVal);
33
+ for (const level of levels) {
34
+ for (const track of level.tracks) {
35
+ for (const display of track.displays) {
36
+ ;
37
+ display.setAlpha(newAlpha);
38
+ }
39
+ }
40
+ }
41
+ };
42
+ return ((0, jsx_runtime_1.jsxs)(material_1.Box, { className: classes.container, children: [(0, jsx_runtime_1.jsx)(material_1.Typography, { variant: "body2", style: { marginRight: 8 }, children: "Opacity:" }), (0, jsx_runtime_1.jsx)(material_1.Slider, { value: sliderValue, onChange: handleAlphaChange, min: 0, max: 1, step: 0.01, valueLabelDisplay: "auto", size: "small", style: { minWidth: 100 }, slots: {
43
+ valueLabel: SliderTooltip_1.default,
44
+ }, valueLabelFormat: (value) => sliderToAlpha(value).toFixed(3) })] }));
45
+ });
46
+ exports.default = OpacitySlider;
@@ -29,10 +29,10 @@ const useStyles = (0, mui_1.makeStyles)()(theme => {
29
29
  function RubberbandSpan({ leftBpOffset, rightBpOffset, numOfBpSelected, left, width, top = 0, sticky = false, }) {
30
30
  const { classes } = useStyles();
31
31
  const [anchorEl, setAnchorEl] = (0, react_1.useState)(null);
32
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [anchorEl ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(RubberbandTooltip_1.default, { side: "left", anchorEl: anchorEl, text: leftBpOffset.map((l, idx) => ((0, jsx_runtime_1.jsx)("div", { children: (0, util_1.stringify)(l, true) }, `JSON.stringify(l)-${idx}`))) }), (0, jsx_runtime_1.jsx)(RubberbandTooltip_1.default, { side: "right", anchorEl: anchorEl, text: rightBpOffset.map((l, idx) => ((0, jsx_runtime_1.jsx)("div", { children: (0, util_1.stringify)(l, true) }, `JSON.stringify(l)-${idx}`))) })] })) : null, (0, jsx_runtime_1.jsx)("div", { className: classes.rubberband, style: { left, width }, children: numOfBpSelected ? ((0, jsx_runtime_1.jsx)(material_1.Typography, { ref: el => {
32
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [anchorEl ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(RubberbandTooltip_1.default, { side: "left", anchorEl: anchorEl, text: leftBpOffset.map((l, idx) => ((0, jsx_runtime_1.jsx)("div", { children: (0, util_1.stringify)(l, true) }, `${JSON.stringify(l)}-left-${idx}`))) }), (0, jsx_runtime_1.jsx)(RubberbandTooltip_1.default, { side: "right", anchorEl: anchorEl, text: rightBpOffset.map((l, idx) => ((0, jsx_runtime_1.jsx)("div", { children: (0, util_1.stringify)(l, true) }, `${JSON.stringify(l)}-right-${idx}`))) })] })) : null, (0, jsx_runtime_1.jsx)("div", { className: classes.rubberband, style: { left, width }, children: numOfBpSelected ? ((0, jsx_runtime_1.jsx)(material_1.Typography, { ref: el => {
33
33
  setAnchorEl(el);
34
34
  }, variant: "h6", className: classes.rubberbandText, style: {
35
35
  top,
36
36
  position: sticky ? 'sticky' : undefined,
37
- }, children: numOfBpSelected.map((n, i) => ((0, jsx_runtime_1.jsx)("div", { children: (0, util_1.getBpDisplayStr)(n) }, i))) })) : null })] }));
37
+ }, children: numOfBpSelected.map((n, i) => ((0, jsx_runtime_1.jsx)("div", { children: (0, util_1.getBpDisplayStr)(n) }, `bpSelectedRow-${i}`))) })) : null })] }));
38
38
  }
@@ -0,0 +1,2 @@
1
+ import type { SliderValueLabelProps } from '@mui/material';
2
+ export default function SliderTooltip(props: SliderValueLabelProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = SliderTooltip;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const material_1 = require("@mui/material");
6
+ function SliderTooltip(props) {
7
+ const { children, open, value } = props;
8
+ return ((0, jsx_runtime_1.jsx)(material_1.Tooltip, { open: open, enterTouchDelay: 0, placement: "top", title: value, arrow: true, children: children }));
9
+ }
@@ -10,6 +10,11 @@ function useRangeSelect(ref, model) {
10
10
  const [anchorPosition, setAnchorPosition] = (0, react_1.useState)();
11
11
  const [guideX, setGuideX] = (0, react_1.useState)();
12
12
  const mouseDragging = startX !== undefined && anchorPosition === undefined;
13
+ const handleClose = (0, react_1.useCallback)(() => {
14
+ setAnchorPosition(undefined);
15
+ setStartX(undefined);
16
+ setCurrentX(undefined);
17
+ }, []);
13
18
  (0, react_1.useEffect)(() => {
14
19
  function computeOffsets(offsetX) {
15
20
  if (startX === undefined) {
@@ -32,6 +37,10 @@ function useRangeSelect(ref, model) {
32
37
  if (startX !== undefined && ref.current) {
33
38
  const { clientX, clientY } = event;
34
39
  const offsetX = (0, util_1.getRelativeX)(event, ref.current);
40
+ if (Math.abs(offsetX - startX) <= 3) {
41
+ handleClose();
42
+ return;
43
+ }
35
44
  setAnchorPosition({
36
45
  offsetX,
37
46
  clientX,
@@ -57,15 +66,7 @@ function useRangeSelect(ref, model) {
57
66
  };
58
67
  }
59
68
  return () => { };
60
- }, [startX, mouseDragging, model, ref]);
61
- (0, react_1.useEffect)(() => {
62
- if (!mouseDragging &&
63
- currentX !== undefined &&
64
- startX !== undefined &&
65
- Math.abs(currentX - startX) <= 3) {
66
- handleClose();
67
- }
68
- }, [mouseDragging, currentX, startX]);
69
+ }, [startX, mouseDragging, model, ref, handleClose]);
69
70
  function mouseDown(event) {
70
71
  event.preventDefault();
71
72
  event.stopPropagation();
@@ -84,11 +85,6 @@ function useRangeSelect(ref, model) {
84
85
  }
85
86
  });
86
87
  }
87
- function handleClose() {
88
- setAnchorPosition(undefined);
89
- setStartX(undefined);
90
- setCurrentX(undefined);
91
- }
92
88
  function handleMenuItemClick(_, callback) {
93
89
  callback();
94
90
  handleClose();
@@ -13,6 +13,7 @@ declare function stateModelFactory(pluginManager: PluginManager): import("mobx-s
13
13
  showIntraviewLinks: import("mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
14
14
  linkViews: import("mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
15
15
  interactiveOverlay: import("mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
16
+ showDynamicControls: import("mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
16
17
  levels: import("mobx-state-tree").IArrayType<import("mobx-state-tree").IModelType<{
17
18
  id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
18
19
  type: import("mobx-state-tree").IType<string | undefined, string, string>;
@@ -78,8 +79,8 @@ declare function stateModelFactory(pluginManager: PluginManager): import("mobx-s
78
79
  readonly interRegionPaddingWidth: number;
79
80
  readonly assemblyNames: string[];
80
81
  readonly assemblyDisplayNames: string[];
81
- readonly isTopLevelView: import("@jbrowse/core/util").AbstractViewModel | undefined;
82
- readonly stickyViewHeaders: boolean | undefined;
82
+ readonly isTopLevelView: boolean;
83
+ readonly stickyViewHeaders: boolean;
83
84
  readonly rubberbandTop: number;
84
85
  readonly pinnedTracksTop: number;
85
86
  } & {
@@ -303,6 +304,7 @@ declare function stateModelFactory(pluginManager: PluginManager): import("mobx-s
303
304
  removeView(view: LinearGenomeViewModel): void;
304
305
  setLevelHeight(newHeight: number, level?: number): number;
305
306
  setLinkViews(arg: boolean): void;
307
+ setShowDynamicControls(arg: boolean): void;
306
308
  activateTrackSelector(level: number): import("@jbrowse/core/util").Widget;
307
309
  toggleTrack(trackId: string, level?: number): void;
308
310
  showTrack(trackId: string, level?: number, initialSnapshot?: {}): void;
@@ -330,6 +332,7 @@ declare function stateModelFactory(pluginManager: PluginManager): import("mobx-s
330
332
  showIntraviewLinks: import("mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
331
333
  linkViews: import("mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
332
334
  interactiveOverlay: import("mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
335
+ showDynamicControls: import("mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
333
336
  levels: import("mobx-state-tree").IArrayType<import("mobx-state-tree").IModelType<{
334
337
  id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
335
338
  type: import("mobx-state-tree").IType<string | undefined, string, string>;
@@ -395,8 +398,8 @@ declare function stateModelFactory(pluginManager: PluginManager): import("mobx-s
395
398
  readonly interRegionPaddingWidth: number;
396
399
  readonly assemblyNames: string[];
397
400
  readonly assemblyDisplayNames: string[];
398
- readonly isTopLevelView: import("@jbrowse/core/util").AbstractViewModel | undefined;
399
- readonly stickyViewHeaders: boolean | undefined;
401
+ readonly isTopLevelView: boolean;
402
+ readonly stickyViewHeaders: boolean;
400
403
  readonly rubberbandTop: number;
401
404
  readonly pinnedTracksTop: number;
402
405
  } & {
@@ -55,6 +55,7 @@ function stateModelFactory(pluginManager) {
55
55
  showIntraviewLinks: true,
56
56
  linkViews: false,
57
57
  interactiveOverlay: false,
58
+ showDynamicControls: true,
58
59
  levels: mobx_state_tree_1.types.array(LinearSyntenyViewHelper),
59
60
  views: mobx_state_tree_1.types.array(pluginManager.getViewType('LinearGenomeView')
60
61
  .stateModel),
@@ -131,6 +132,9 @@ function stateModelFactory(pluginManager) {
131
132
  setLinkViews(arg) {
132
133
  self.linkViews = arg;
133
134
  },
135
+ setShowDynamicControls(arg) {
136
+ self.showDynamicControls = arg;
137
+ },
134
138
  activateTrackSelector(level) {
135
139
  if (self.trackSelectorType === 'hierarchical') {
136
140
  const session = (0, util_1.getSession)(self);
@@ -20,11 +20,12 @@ function doAfterAttach(self) {
20
20
  if (!ctx1 || !ctx3) {
21
21
  return;
22
22
  }
23
+ const { alpha } = self;
23
24
  const height = self.height;
24
25
  const width = view.width;
25
26
  ctx1.clearRect(0, 0, width, height);
26
- ctx3.clearRect(0, 0, width, height);
27
- (0, drawSynteny_1.drawRef)(self, ctx1, ctx3);
27
+ (0, drawSynteny_1.drawRef)(self, ctx1);
28
+ (0, drawSynteny_1.drawCigarClickMap)(self, ctx3);
28
29
  }));
29
30
  (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
30
31
  const view = (0, util_1.getContainingView)(self);
@@ -32,7 +33,8 @@ function doAfterAttach(self) {
32
33
  !view.views.every(a => a.displayedRegions.length > 0 && a.initialized)) {
33
34
  return;
34
35
  }
35
- (0, drawSynteny_1.drawMouseoverSynteny)(self);
36
+ const { clickId, mouseoverId } = self;
37
+ (0, drawSynteny_1.drawMouseoverClickMap)(self);
36
38
  }));
37
39
  (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.reaction)(() => {
38
40
  const view = (0, util_1.getContainingView)(self);
@@ -189,11 +189,16 @@ const LinearSyntenyRendering = (0, mobx_react_1.observer)(function ({ model, })
189
189
  const { f, cigar } = model.featPositions[id];
190
190
  const unitMultiplier2 = Math.floor(drawSynteny_1.MAX_COLOR_RANGE / cigar.length);
191
191
  const cigarIdx = (0, drawSynteny_1.getId)(r2, g2, b2, unitMultiplier2);
192
- setTooltip((0, util_2.getTooltip)({
193
- feature: f,
194
- cigarOp: cigar[cigarIdx],
195
- cigarOpLen: cigar[cigarIdx + 1],
196
- }));
192
+ if (cigarIdx % 2 === 0 && (r2 !== 0 || g2 !== 0 || b2 !== 0)) {
193
+ setTooltip((0, util_2.getTooltip)({
194
+ feature: f,
195
+ cigarOp: cigar[cigarIdx + 1],
196
+ cigarOpLen: cigar[cigarIdx],
197
+ }));
198
+ }
199
+ else {
200
+ setTooltip('');
201
+ }
197
202
  }
198
203
  }
199
204
  }, onMouseLeave: () => {
@@ -32,13 +32,14 @@ export declare function drawMatchSimple({ feature, ctx, offsets, level, cb, heig
32
32
  hideTiny?: boolean;
33
33
  }): void;
34
34
  export declare function draw(ctx: CanvasRenderingContext2D, x1: number, x2: number, y1: number, x3: number, x4: number, y2: number, mid: number, drawCurves?: boolean): void;
35
+ export declare function drawLocationMarkers(ctx: CanvasRenderingContext2D, x1: number, x2: number, y1: number, x3: number, x4: number, y2: number, mid: number, bpPerPx1: number, bpPerPx2: number, drawCurves?: boolean): void;
35
36
  export declare function drawBox(ctx: CanvasRenderingContext2D, x1: number, x2: number, y1: number, x3: number, x4: number, y2: number): void;
36
37
  export declare function drawBezierBox(ctx: CanvasRenderingContext2D, x1: number, x2: number, y1: number, x3: number, x4: number, y2: number, mid: number): void;
37
38
  export declare function onSynClick(event: React.MouseEvent, model: LinearSyntenyDisplayModel): import("../model").FeatPos | undefined;
38
39
  export declare function onSynContextClick(event: React.MouseEvent, model: LinearSyntenyDisplayModel, setAnchorEl: (arg: ClickCoord) => void): void;
39
40
  export declare function getTooltip({ feature, cigarOp, cigarOpLen, }: {
40
41
  feature: Feature;
41
- cigarOp?: string;
42
42
  cigarOpLen?: string;
43
+ cigarOp?: string;
43
44
  }): string;
44
45
  export {};
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.drawMatchSimple = drawMatchSimple;
4
4
  exports.draw = draw;
5
+ exports.drawLocationMarkers = drawLocationMarkers;
5
6
  exports.drawBox = drawBox;
6
7
  exports.drawBezierBox = drawBezierBox;
7
8
  exports.onSynClick = onSynClick;
@@ -51,6 +52,42 @@ function draw(ctx, x1, x2, y1, x3, x4, y2, mid, drawCurves) {
51
52
  drawBox(ctx, x1, x2, y1, x3, x4, y2);
52
53
  }
53
54
  }
55
+ function drawLocationMarkers(ctx, x1, x2, y1, x3, x4, y2, mid, bpPerPx1, bpPerPx2, drawCurves) {
56
+ const width1 = Math.abs(x2 - x1);
57
+ const width2 = Math.abs(x4 - x3);
58
+ const averageWidth = (width1 + width2) / 2;
59
+ if (averageWidth < 30) {
60
+ return;
61
+ }
62
+ const targetPixelSpacing = 20;
63
+ const numMarkers = Math.max(2, Math.floor(averageWidth / targetPixelSpacing) + 1);
64
+ const prevStrokeStyle = ctx.strokeStyle;
65
+ const prevLineWidth = ctx.lineWidth;
66
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.25)';
67
+ ctx.lineWidth = 0.5;
68
+ ctx.beginPath();
69
+ if (drawCurves) {
70
+ for (let step = 0; step < numMarkers; step++) {
71
+ const t = step / numMarkers;
72
+ const topX = x1 + (x2 - x1) * t;
73
+ const bottomX = x4 + (x3 - x4) * t;
74
+ ctx.moveTo(topX, y1);
75
+ ctx.bezierCurveTo(topX, mid, bottomX, mid, bottomX, y2);
76
+ }
77
+ }
78
+ else {
79
+ for (let step = 0; step < numMarkers; step++) {
80
+ const t = step / numMarkers;
81
+ const topX = x1 + (x2 - x1) * t;
82
+ const bottomX = x4 + (x3 - x4) * t;
83
+ ctx.moveTo(topX, y1);
84
+ ctx.lineTo(bottomX, y2);
85
+ }
86
+ }
87
+ ctx.stroke();
88
+ ctx.strokeStyle = prevStrokeStyle;
89
+ ctx.lineWidth = prevLineWidth;
90
+ }
54
91
  function drawBox(ctx, x1, x2, y1, x3, x4, y2) {
55
92
  ctx.beginPath();
56
93
  ctx.moveTo(x1, y1);
@@ -131,7 +168,11 @@ function onSynContextClick(event, model, setAnchorEl) {
131
168
  const f = model.featPositions[id];
132
169
  if (f) {
133
170
  model.setClickId(f.f.id());
134
- setAnchorEl({ clientX, clientY, feature: f });
171
+ setAnchorEl({
172
+ clientX,
173
+ clientY,
174
+ feature: f,
175
+ });
135
176
  }
136
177
  }
137
178
  function getTooltip({ feature, cigarOp, cigarOpLen, }) {
@@ -149,7 +190,7 @@ function getTooltip({ feature, cigarOp, cigarOpLen, }) {
149
190
  `Query len: ${l1.toLocaleString('en-US')}`,
150
191
  `Target len: ${l2.toLocaleString('en-US')}`,
151
192
  identity ? `Identity: ${identity.toPrecision(2)}` : '',
152
- cigarOp ? `CIGAR operator: ${cigarOp}${cigarOpLen}` : '',
193
+ cigarOp ? `CIGAR operator: ${(0, util_1.toLocale)(+cigarOpLen)}${cigarOp}` : '',
153
194
  n1 ? `Name 1: ${n1}` : '',
154
195
  n2 ? `Name 2: ${n2}` : '',
155
196
  ]
@@ -1,5 +1,6 @@
1
1
  import type { 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): void;
5
- export declare function drawMouseoverSynteny(model: LinearSyntenyDisplayModel): void;
4
+ export declare function drawCigarClickMap(model: LinearSyntenyDisplayModel, cigarClickMapCanvas: CanvasRenderingContext2D): void;
5
+ export declare function drawRef(model: LinearSyntenyDisplayModel, mainCanvas: CanvasRenderingContext2D): void;
6
+ export declare function drawMouseoverClickMap(model: LinearSyntenyDisplayModel): void;