@jbrowse/plugin-linear-genome-view 1.7.9 → 1.7.10

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 (32) hide show
  1. package/dist/BaseLinearDisplay/components/BaseLinearDisplay.d.ts +1 -5
  2. package/dist/BaseLinearDisplay/components/BaseLinearDisplay.js +32 -120
  3. package/dist/BaseLinearDisplay/components/Tooltip.d.ts +8 -0
  4. package/dist/BaseLinearDisplay/components/Tooltip.js +125 -0
  5. package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +3 -2
  6. package/dist/LinearGenomeView/components/Header.js +5 -2
  7. package/dist/LinearGenomeView/components/HelpDialog.js +2 -3
  8. package/dist/LinearGenomeView/components/LinearGenomeView.js +6 -2
  9. package/dist/LinearGenomeView/components/LinearGenomeView.test.js +2 -2
  10. package/dist/LinearGenomeView/components/OverviewScaleBar.js +2 -2
  11. package/dist/LinearGenomeView/components/ScaleBar.d.ts +6 -2
  12. package/dist/LinearGenomeView/components/ScaleBar.js +8 -3
  13. package/dist/LinearGenomeView/components/TrackLabel.js +25 -41
  14. package/dist/LinearGenomeView/index.d.ts +3 -8
  15. package/dist/LinearGenomeView/index.js +59 -32
  16. package/dist/LinearGenomeView/index.test.js +22 -5
  17. package/dist/index.js +22 -11
  18. package/package.json +3 -2
  19. package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +4 -89
  20. package/src/BaseLinearDisplay/components/Tooltip.tsx +97 -0
  21. package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +10 -4
  22. package/src/LinearGenomeView/components/Header.tsx +3 -2
  23. package/src/LinearGenomeView/components/HelpDialog.tsx +5 -4
  24. package/src/LinearGenomeView/components/LinearGenomeView.test.js +2 -2
  25. package/src/LinearGenomeView/components/LinearGenomeView.tsx +16 -10
  26. package/src/LinearGenomeView/components/OverviewScaleBar.tsx +3 -4
  27. package/src/LinearGenomeView/components/ScaleBar.tsx +6 -9
  28. package/src/LinearGenomeView/components/TrackLabel.tsx +25 -28
  29. package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +4 -21
  30. package/src/LinearGenomeView/index.test.ts +20 -5
  31. package/src/LinearGenomeView/index.tsx +54 -26
  32. package/src/index.ts +35 -30
@@ -0,0 +1,97 @@
1
+ import React, { useState, useMemo } from 'react'
2
+ import { getConf } from '@jbrowse/core/configuration'
3
+ import { observer } from 'mobx-react'
4
+ import { Portal, alpha, makeStyles } from '@material-ui/core'
5
+ import { usePopper } from 'react-popper'
6
+
7
+ // locals
8
+ import { BaseLinearDisplayModel } from '../models/BaseLinearDisplayModel'
9
+
10
+ function round(value: number) {
11
+ return Math.round(value * 1e5) / 1e5
12
+ }
13
+ const useStyles = makeStyles(theme => ({
14
+ // these styles come from
15
+ // https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js
16
+ tooltip: {
17
+ pointerEvents: 'none',
18
+ backgroundColor: alpha(theme.palette.grey[700], 0.9),
19
+ borderRadius: theme.shape.borderRadius,
20
+ color: theme.palette.common.white,
21
+ fontFamily: theme.typography.fontFamily,
22
+ padding: '4px 8px',
23
+ fontSize: theme.typography.pxToRem(12),
24
+ lineHeight: `${round(14 / 10)}em`,
25
+ maxWidth: 300,
26
+ wordWrap: 'break-word',
27
+ },
28
+ }))
29
+
30
+ const TooltipContents = React.forwardRef<
31
+ HTMLDivElement,
32
+ { message: React.ReactNode | string }
33
+ >(({ message }: { message: React.ReactNode | string }, ref) => {
34
+ return <div ref={ref}>{message}</div>
35
+ })
36
+
37
+ type Coord = [number, number]
38
+ const Tooltip = observer(
39
+ ({
40
+ model,
41
+ clientMouseCoord,
42
+ }: {
43
+ model: BaseLinearDisplayModel
44
+ clientMouseCoord: Coord
45
+ }) => {
46
+ const classes = useStyles()
47
+ const { featureUnderMouse } = model
48
+ const [width, setWidth] = useState(0)
49
+ const [popperElt, setPopperElt] = useState<HTMLDivElement | null>(null)
50
+
51
+ // must be memoized a la https://github.com/popperjs/react-popper/issues/391
52
+ const virtElement = useMemo(
53
+ () => ({
54
+ getBoundingClientRect: () => {
55
+ const x = clientMouseCoord[0] + width / 2 + 20
56
+ const y = clientMouseCoord[1]
57
+ return {
58
+ top: y,
59
+ left: x,
60
+ bottom: y,
61
+ right: x,
62
+ width: 0,
63
+ height: 0,
64
+ x,
65
+ y,
66
+ toJSON() {},
67
+ }
68
+ },
69
+ }),
70
+ [clientMouseCoord, width],
71
+ )
72
+ const { styles, attributes } = usePopper(virtElement, popperElt)
73
+
74
+ const contents = featureUnderMouse
75
+ ? getConf(model, 'mouseover', { feature: featureUnderMouse })
76
+ : undefined
77
+
78
+ return featureUnderMouse && contents ? (
79
+ <Portal>
80
+ <div
81
+ ref={setPopperElt}
82
+ className={classes.tooltip}
83
+ // zIndex needed to go over widget drawer
84
+ style={{ ...styles.popper, zIndex: 100000 }}
85
+ {...attributes.popper}
86
+ >
87
+ <TooltipContents
88
+ ref={elt => setWidth(elt?.getBoundingClientRect().width || 0)}
89
+ message={contents}
90
+ />
91
+ </div>
92
+ </Portal>
93
+ ) : null
94
+ },
95
+ )
96
+
97
+ export default Tooltip
@@ -7,6 +7,7 @@ import { MenuItem } from '@jbrowse/core/ui'
7
7
  import {
8
8
  isAbortException,
9
9
  getContainingView,
10
+ getContainingTrack,
10
11
  getSession,
11
12
  getViewParams,
12
13
  isSelectionContainer,
@@ -333,8 +334,13 @@ export const BaseLinearDisplay = types
333
334
  const featureWidget = session.addWidget(
334
335
  'BaseFeatureWidget',
335
336
  'baseFeature',
336
- { featureData: feature.toJSON(), view: getContainingView(self) },
337
+ {
338
+ view: getContainingView(self),
339
+ track: getContainingTrack(self),
340
+ featureData: feature.toJSON(),
341
+ },
337
342
  )
343
+
338
344
  session.showWidget(featureWidget)
339
345
  }
340
346
  if (isSelectionContainer(session)) {
@@ -551,7 +557,7 @@ export const BaseLinearDisplay = types
551
557
  self.currBpPerPx !== view.bpPerPx || !self.estimatedRegionStats,
552
558
  rpcDriverName: self.rpcDriverName,
553
559
  displayModel: self,
554
- onFeatureClick(_: unknown, featureId: string | undefined) {
560
+ onFeatureClick(_: unknown, featureId?: string) {
555
561
  const f = featureId || self.featureIdUnderMouse
556
562
  if (!f) {
557
563
  self.clearFeatureSelection()
@@ -566,7 +572,7 @@ export const BaseLinearDisplay = types
566
572
  self.clearFeatureSelection()
567
573
  },
568
574
  // similar to click but opens a menu with further options
569
- onFeatureContextMenu(_: unknown, featureId: string | undefined) {
575
+ onFeatureContextMenu(_: unknown, featureId?: string) {
570
576
  const f = featureId || self.featureIdUnderMouse
571
577
  if (!f) {
572
578
  self.clearFeatureSelection()
@@ -576,7 +582,7 @@ export const BaseLinearDisplay = types
576
582
  }
577
583
  },
578
584
 
579
- onMouseMove(_: unknown, featureId: string | undefined) {
585
+ onMouseMove(_: unknown, featureId?: string) {
580
586
  self.setFeatureIdUnderMouse(featureId)
581
587
  },
582
588
 
@@ -7,6 +7,7 @@ import {
7
7
  makeStyles,
8
8
  alpha,
9
9
  } from '@material-ui/core'
10
+ import { getTickDisplayStr2 } from '@jbrowse/core/util'
10
11
  import SearchBox from './SearchBox'
11
12
 
12
13
  // icons
@@ -97,10 +98,10 @@ function PanControls({ model }: { model: LGV }) {
97
98
 
98
99
  const RegionWidth = observer(({ model }: { model: LGV }) => {
99
100
  const classes = useStyles()
100
- const { coarseTotalBp } = model
101
+ const { coarseTotalBp, bpPerPx } = model
101
102
  return (
102
103
  <Typography variant="body2" color="textSecondary" className={classes.bp}>
103
- {Math.round(coarseTotalBp).toLocaleString('en-US')} bp
104
+ {getTickDisplayStr2(coarseTotalBp, bpPerPx)}
104
105
  </Typography>
105
106
  )
106
107
  })
@@ -32,11 +32,8 @@ export default function HelpDialog({
32
32
  Using the search box
33
33
  {handleClose ? (
34
34
  <IconButton
35
- data-testid="close-resultsDialog"
36
35
  className={classes.closeButton}
37
- onClick={() => {
38
- handleClose()
39
- }}
36
+ onClick={() => handleClose()}
40
37
  >
41
38
  <CloseIcon />
42
39
  </IconButton>
@@ -81,6 +78,10 @@ export default function HelpDialog({
81
78
  <code>chr1:1-100[rev] chr2:1-100</code> - open up the first region
82
79
  in the horizontally flipped orientation
83
80
  </li>
81
+ <li>
82
+ <code>chr1 100 200</code> - use whitespace separated refname, start,
83
+ end
84
+ </li>
84
85
  </ul>
85
86
  </DialogContent>
86
87
  <Divider />
@@ -79,7 +79,7 @@ describe('<LinearGenomeView />', () => {
79
79
  await findByText('Foo Track')
80
80
  // test needs to wait until it's updated to display 100 bp in the header to
81
81
  // make snapshot pass
82
- await findByText('100 bp')
82
+ await findByText('100bp')
83
83
  expect(container.firstChild).toMatchSnapshot()
84
84
  })
85
85
  it('renders two tracks, two regions', async () => {
@@ -145,7 +145,7 @@ describe('<LinearGenomeView />', () => {
145
145
  <LinearGenomeView model={model} />,
146
146
  )
147
147
  await findByText('Foo Track')
148
- await findByText('798 bp')
148
+ await findByText('798bp')
149
149
  await findAllByTestId('svgfeatures')
150
150
 
151
151
  expect(container.firstChild).toMatchSnapshot()
@@ -92,16 +92,22 @@ const LinearGenomeView = observer(({ model }: { model: LGV }) => {
92
92
  <TracksContainer model={model}>
93
93
  {!tracks.length ? (
94
94
  <Paper variant="outlined" className={classes.note}>
95
- <Typography>No tracks active.</Typography>
96
- <Button
97
- variant="contained"
98
- color="primary"
99
- onClick={model.activateTrackSelector}
100
- style={{ zIndex: 1000 }}
101
- startIcon={<TrackSelectorIcon />}
102
- >
103
- Open track selector
104
- </Button>
95
+ {!model.hideNoTracksActive ? (
96
+ <>
97
+ <Typography>No tracks active.</Typography>
98
+ <Button
99
+ variant="contained"
100
+ color="primary"
101
+ onClick={model.activateTrackSelector}
102
+ style={{ zIndex: 1000 }}
103
+ startIcon={<TrackSelectorIcon />}
104
+ >
105
+ Open track selector
106
+ </Button>
107
+ </>
108
+ ) : (
109
+ <div style={{ height: '48px' }}></div>
110
+ )}
105
111
  </Paper>
106
112
  ) : (
107
113
  tracks.map(track => (
@@ -5,7 +5,7 @@ import { Instance } from 'mobx-state-tree'
5
5
  import clsx from 'clsx'
6
6
 
7
7
  import Base1DView, { Base1DViewModel } from '@jbrowse/core/util/Base1DViewModel'
8
- import { getSession } from '@jbrowse/core/util'
8
+ import { getSession, getTickDisplayStr } from '@jbrowse/core/util'
9
9
  import { ContentBlock } from '@jbrowse/core/util/blockTypes'
10
10
  import { Assembly } from '@jbrowse/core/assemblyManager/assembly'
11
11
 
@@ -51,7 +51,6 @@ const useStyles = makeStyles(theme => {
51
51
  },
52
52
  scaleBarLabel: {
53
53
  height: HEADER_OVERVIEW_HEIGHT,
54
- width: 1,
55
54
  position: 'absolute',
56
55
  display: 'flex',
57
56
  justifyContent: 'center',
@@ -301,7 +300,7 @@ const OverviewBox = observer(
301
300
  overview: Base1DViewModel
302
301
  }) => {
303
302
  const classes = useStyles()
304
- const { cytobandOffset, showCytobands } = model
303
+ const { cytobandOffset, bpPerPx, showCytobands } = model
305
304
  const { start, end, reversed, refName, assemblyName } = block
306
305
  const { majorPitch } = chooseGridPitch(scale, 120, 15)
307
306
  const { assemblyManager } = getSession(model)
@@ -354,7 +353,7 @@ const OverviewBox = observer(
354
353
  color: refNameColor,
355
354
  }}
356
355
  >
357
- {tickLabel.toLocaleString('en-US')}
356
+ {getTickDisplayStr(tickLabel, bpPerPx)}
358
357
  </Typography>
359
358
  ))
360
359
  : null}
@@ -14,6 +14,7 @@ import {
14
14
  InterRegionPaddingBlock as InterRegionPaddingBlockComponent,
15
15
  } from '../../BaseLinearDisplay/components/Block'
16
16
  import { makeTicks } from '../util'
17
+ import { getTickDisplayStr } from '@jbrowse/core/util'
17
18
 
18
19
  type LGV = LinearGenomeViewModel
19
20
 
@@ -95,18 +96,14 @@ const RenderedRefNameLabels = observer(({ model }: { model: LGV }) => {
95
96
 
96
97
  const RenderedScaleBarLabels = observer(({ model }: { model: LGV }) => {
97
98
  const classes = useStyles()
99
+ const { bpPerPx } = model
98
100
 
99
101
  return (
100
102
  <>
101
103
  {model.staticBlocks.map((block, index) => {
102
104
  if (block instanceof ContentBlock) {
103
- const ticks = makeTicks(
104
- block.start,
105
- block.end,
106
- model.bpPerPx,
107
- true,
108
- false,
109
- )
105
+ const { start, end } = block
106
+ const ticks = makeTicks(start, end, bpPerPx, true, false)
110
107
 
111
108
  return (
112
109
  <ContentBlockComponent key={`${block.key}-${index}`} block={block}>
@@ -116,7 +113,7 @@ const RenderedScaleBarLabels = observer(({ model }: { model: LGV }) => {
116
113
  (block.reversed
117
114
  ? block.end - tick.base
118
115
  : tick.base - block.start) / model.bpPerPx
119
- const baseNumber = (tick.base + 1).toLocaleString('en-US')
116
+ const baseNumber = tick.base + 1
120
117
  return (
121
118
  <div
122
119
  key={tick.base}
@@ -125,7 +122,7 @@ const RenderedScaleBarLabels = observer(({ model }: { model: LGV }) => {
125
122
  >
126
123
  {baseNumber ? (
127
124
  <Typography className={classes.majorTickLabel}>
128
- {baseNumber}
125
+ {getTickDisplayStr(baseNumber, bpPerPx)}
129
126
  </Typography>
130
127
  ) : null}
131
128
  </div>
@@ -1,6 +1,6 @@
1
1
  import React from 'react'
2
2
  import { getConf, readConfObject } from '@jbrowse/core/configuration'
3
- import { Menu } from '@jbrowse/core/ui'
3
+ import CascadingMenu from '@jbrowse/core/ui/CascadingMenu'
4
4
  import { getSession, getContainingView } from '@jbrowse/core/util'
5
5
  import { BaseTrackModel } from '@jbrowse/core/pluggableElementTypes/models'
6
6
  import {
@@ -11,14 +11,21 @@ import {
11
11
  makeStyles,
12
12
  } from '@material-ui/core'
13
13
 
14
+ import {
15
+ bindTrigger,
16
+ bindPopover,
17
+ usePopupState,
18
+ } from 'material-ui-popup-state/hooks'
19
+
20
+ import clsx from 'clsx'
21
+ import { observer } from 'mobx-react'
22
+ import { Instance } from 'mobx-state-tree'
23
+
14
24
  // icons
15
25
  import MoreVertIcon from '@material-ui/icons/MoreVert'
16
26
  import DragIcon from '@material-ui/icons/DragIndicator'
17
27
  import CloseIcon from '@material-ui/icons/Close'
18
28
 
19
- import clsx from 'clsx'
20
- import { observer } from 'mobx-react'
21
- import { Instance } from 'mobx-state-tree'
22
29
  import { LinearGenomeViewStateModel } from '..'
23
30
 
24
31
  const useStyles = makeStyles(theme => ({
@@ -54,22 +61,20 @@ const useStyles = makeStyles(theme => ({
54
61
  type LGV = Instance<LinearGenomeViewStateModel>
55
62
 
56
63
  const TrackLabel = React.forwardRef(
57
- (props: { track: BaseTrackModel; className?: string }, ref) => {
64
+ (
65
+ { track, className }: { track: BaseTrackModel; className?: string },
66
+ ref,
67
+ ) => {
58
68
  const classes = useStyles()
59
- const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
60
- const { track, className } = props
61
69
  const view = getContainingView(track) as LGV
62
70
  const session = getSession(track)
63
71
  const trackConf = track.configuration
64
72
  const trackId = getConf(track, 'trackId')
65
73
 
66
- const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
67
- setAnchorEl(event.currentTarget)
68
- }
69
-
70
- const handleClose = () => {
71
- setAnchorEl(null)
72
- }
74
+ const popupState = usePopupState({
75
+ popupId: 'trackLabelMenu',
76
+ variant: 'popover',
77
+ })
73
78
 
74
79
  const onDragStart = (event: React.DragEvent<HTMLSpanElement>) => {
75
80
  const target = event.target as HTMLElement
@@ -91,17 +96,12 @@ const TrackLabel = React.forwardRef(
91
96
  if (getConf(track, 'type') === 'ReferenceSequenceTrack') {
92
97
  const r = session.assemblies.find(a => a.sequence === trackConf)
93
98
  trackName =
94
- readConfObject(trackConf, 'name') ||
99
+ trackName ||
95
100
  (r
96
101
  ? `Reference Sequence (${readConfObject(r, 'name')})`
97
102
  : 'Reference Sequence')
98
103
  }
99
104
 
100
- function handleMenuItemClick(_: unknown, callback: Function) {
101
- callback()
102
- handleClose()
103
- }
104
-
105
105
  const items = [
106
106
  ...(session.getTrackActionMenuItems?.(trackConf) || []),
107
107
  ...track.trackMenuItems(),
@@ -135,9 +135,7 @@ const TrackLabel = React.forwardRef(
135
135
  {trackName}
136
136
  </Typography>
137
137
  <IconButton
138
- aria-controls="simple-menu"
139
- aria-haspopup="true"
140
- onClick={handleClick}
138
+ {...bindTrigger(popupState)}
141
139
  className={classes.iconButton}
142
140
  color="secondary"
143
141
  data-testid="track_menu_icon"
@@ -146,12 +144,11 @@ const TrackLabel = React.forwardRef(
146
144
  <MoreVertIcon />
147
145
  </IconButton>
148
146
  </Paper>
149
- <Menu
150
- anchorEl={anchorEl}
151
- onMenuItemClick={handleMenuItemClick}
152
- open={Boolean(anchorEl)}
153
- onClose={handleClose}
147
+ <CascadingMenu
148
+ {...bindPopover(popupState)}
149
+ onMenuItemClick={(_: unknown, callback: Function) => callback()}
154
150
  menuItems={items}
151
+ popupState={popupState}
155
152
  />
156
153
  </>
157
154
  )
@@ -255,8 +255,7 @@ exports[`<LinearGenomeView /> renders one track, one region 1`] = `
255
255
  <p
256
256
  class="MuiTypography-root makeStyles-bp MuiTypography-body2 MuiTypography-colorTextSecondary"
257
257
  >
258
- 100
259
- bp
258
+ 100bp
260
259
  </p>
261
260
  <div
262
261
  class="makeStyles-container"
@@ -425,13 +424,7 @@ exports[`<LinearGenomeView /> renders one track, one region 1`] = `
425
424
  <div
426
425
  class="makeStyles-tick"
427
426
  style="left: -1px;"
428
- >
429
- <p
430
- class="MuiTypography-root makeStyles-majorTickLabel MuiTypography-body1"
431
- >
432
- 0
433
- </p>
434
- </div>
427
+ />
435
428
  </div>
436
429
  <div
437
430
  class="makeStyles-boundaryPaddingBlock"
@@ -500,7 +493,6 @@ exports[`<LinearGenomeView /> renders one track, one region 1`] = `
500
493
  Foo Track
501
494
  </span>
502
495
  <button
503
- aria-controls="simple-menu"
504
496
  aria-haspopup="true"
505
497
  class="MuiButtonBase-root MuiIconButton-root makeStyles-iconButton MuiIconButton-colorSecondary"
506
498
  data-testid="track_menu_icon"
@@ -850,8 +842,7 @@ exports[`<LinearGenomeView /> renders two tracks, two regions 1`] = `
850
842
  <p
851
843
  class="MuiTypography-root makeStyles-bp MuiTypography-body2 MuiTypography-colorTextSecondary"
852
844
  >
853
- 798
854
- bp
845
+ 798bp
855
846
  </p>
856
847
  <div
857
848
  class="makeStyles-container"
@@ -1239,13 +1230,7 @@ exports[`<LinearGenomeView /> renders two tracks, two regions 1`] = `
1239
1230
  <div
1240
1231
  class="makeStyles-tick"
1241
1232
  style="left: -1px;"
1242
- >
1243
- <p
1244
- class="MuiTypography-root makeStyles-majorTickLabel MuiTypography-body1"
1245
- >
1246
- 0
1247
- </p>
1248
- </div>
1233
+ />
1249
1234
  </div>
1250
1235
  <div
1251
1236
  class="makeStyles-interRegionPaddingBlock"
@@ -1390,7 +1375,6 @@ exports[`<LinearGenomeView /> renders two tracks, two regions 1`] = `
1390
1375
  Foo Track
1391
1376
  </span>
1392
1377
  <button
1393
- aria-controls="simple-menu"
1394
1378
  aria-haspopup="true"
1395
1379
  class="MuiButtonBase-root MuiIconButton-root makeStyles-iconButton MuiIconButton-colorSecondary"
1396
1380
  data-testid="track_menu_icon"
@@ -1533,7 +1517,6 @@ exports[`<LinearGenomeView /> renders two tracks, two regions 1`] = `
1533
1517
  Bar Track
1534
1518
  </span>
1535
1519
  <button
1536
- aria-controls="simple-menu"
1537
1520
  aria-haspopup="true"
1538
1521
  class="MuiButtonBase-root MuiIconButton-root makeStyles-iconButton MuiIconButton-colorSecondary"
1539
1522
  data-testid="track_menu_icon"
@@ -72,7 +72,7 @@ function initialize() {
72
72
  })
73
73
  .actions(self => ({
74
74
  isValidRefName(str: string) {
75
- return !str.includes(':')
75
+ return str === 'ctgA' || str === 'ctgB'
76
76
  },
77
77
  get(str: string) {
78
78
  return self.assemblies.get(str)
@@ -989,8 +989,23 @@ test('multi region', () => {
989
989
  model.navToLocString('ctgA ctgB')
990
990
  expect(model.displayedRegions[0].refName).toBe('ctgA')
991
991
  expect(model.displayedRegions[1].refName).toBe('ctgB')
992
- // [
993
- // { refName: 'ctgA', start: 0, end: 50001 },
994
- // { refName: 'ctgB', start: 0, end: 6079 },
995
- // ])
992
+ })
993
+
994
+ test('space separated locstring', () => {
995
+ const { Session, LinearGenomeModel } = initialize()
996
+ const model = Session.create({
997
+ configuration: {},
998
+ }).setView(
999
+ LinearGenomeModel.create({
1000
+ type: 'LinearGenomeView',
1001
+ tracks: [{ name: 'foo track', type: 'BasicTrack' }],
1002
+ }),
1003
+ )
1004
+ model.setWidth(800)
1005
+ model.setDisplayedRegions(volvoxDisplayedRegions.slice(0, 1))
1006
+
1007
+ model.navToLocString('ctgA 0 100')
1008
+
1009
+ expect(model.offsetPx).toBe(0)
1010
+ expect(model.bpPerPx).toBe(0.125)
996
1011
  })