diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/Header.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/Header.tsx
index ee2da4c6ef..add32a4c74 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/components/Header.tsx
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/Header.tsx
@@ -1,20 +1,17 @@
-import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons'
-import { getBpDisplayStr } from '@jbrowse/core/util'
-import ArrowBackIcon from '@mui/icons-material/ArrowBack'
-import ArrowForwardIcon from '@mui/icons-material/ArrowForward'
-import { Button, FormGroup, IconButton, Typography, alpha } from '@mui/material'
+import { FormGroup } from '@mui/material'
import { observer } from 'mobx-react'
import { makeStyles } from 'tss-react/mui'
+import HeaderPanControls from './HeaderPanControls'
+import HeaderRegionWidth from './HeaderRegionWidth'
+import HeaderTrackSelectorButton from './HeaderTrackSelectorButton'
+import HeaderZoomControls from './HeaderZoomControls'
import OverviewScalebar from './OverviewScalebar'
import SearchBox from './SearchBox'
-import ZoomControls from './ZoomControls'
-import { SPACING } from '../consts'
import type { LinearGenomeViewModel } from '..'
-type LGV = LinearGenomeViewModel
-const useStyles = makeStyles()(theme => ({
+const useStyles = makeStyles()({
headerBar: {
display: 'flex',
},
@@ -25,95 +22,30 @@ const useStyles = makeStyles()(theme => ({
spacer: {
flexGrow: 1,
},
-
- panButton: {
- background: alpha(theme.palette.background.paper, 0.8),
- color: theme.palette.text.primary,
- margin: SPACING,
- },
- bp: {
- display: 'flex',
- alignItems: 'center',
- marginLeft: 5,
- },
- toggleButton: {
- height: 44,
- border: 'none',
- marginLeft: theme.spacing(4),
- },
- buttonSpacer: {
- marginRight: theme.spacing(2),
- },
-}))
-
-const HeaderButtons = observer(({ model }: { model: LGV }) => {
- const { classes } = useStyles()
- return (
-
-
-
- )
-})
-
-function PanControls({ model }: { model: LGV }) {
- const { classes } = useStyles()
- return (
- <>
-
-
- >
- )
-}
-
-const RegionWidth = observer(function ({ model }: { model: LGV }) {
- const { classes } = useStyles()
- const { coarseTotalBp } = model
- return (
-
- {getBpDisplayStr(coarseTotalBp)}
-
- )
})
-const Controls = ({ model }: { model: LGV }) => {
+const Controls = function ({ model }: { model: LinearGenomeViewModel }) {
const { classes } = useStyles()
return (
)
}
-const LinearGenomeViewHeader = observer(function ({ model }: { model: LGV }) {
+const LinearGenomeViewHeader = observer(function ({
+ model,
+}: {
+ model: LinearGenomeViewModel
+}) {
const { hideHeader, hideHeaderOverview } = model
return !hideHeader ? (
hideHeaderOverview ? (
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderPanControls.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderPanControls.tsx
new file mode 100644
index 0000000000..df4b32c772
--- /dev/null
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderPanControls.tsx
@@ -0,0 +1,47 @@
+import ArrowBackIcon from '@mui/icons-material/ArrowBack'
+import ArrowForwardIcon from '@mui/icons-material/ArrowForward'
+import { Button, alpha } from '@mui/material'
+import { makeStyles } from 'tss-react/mui'
+
+import { SPACING } from '../consts'
+
+import type { LinearGenomeViewModel } from '..'
+
+type LGV = LinearGenomeViewModel
+const useStyles = makeStyles()(theme => ({
+ panButton: {
+ background: alpha(theme.palette.background.paper, 0.8),
+ color: theme.palette.text.primary,
+ margin: SPACING,
+ },
+
+ buttonSpacer: {
+ marginRight: theme.spacing(2),
+ },
+}))
+
+export default function HeaderPanControls({ model }: { model: LGV }) {
+ const { classes } = useStyles()
+ return (
+ <>
+
+
+ >
+ )
+}
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderRegionWidth.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderRegionWidth.tsx
new file mode 100644
index 0000000000..07d081e6a3
--- /dev/null
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderRegionWidth.tsx
@@ -0,0 +1,52 @@
+import { lazy } from 'react'
+
+import { getBpDisplayStr, getSession } from '@jbrowse/core/util'
+import { Typography } from '@mui/material'
+import { observer } from 'mobx-react'
+import { makeStyles } from 'tss-react/mui'
+
+import type { LinearGenomeViewModel } from '..'
+
+const RegionWidthEditorDialog = lazy(() => import('./RegionWidthEditorDialog'))
+
+const useStyles = makeStyles()({
+ bp: {
+ display: 'flex',
+ alignItems: 'center',
+ marginLeft: 5,
+ cursor: 'pointer',
+ minWidth: 50,
+ '&:hover': {
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
+ },
+ },
+})
+
+const HeaderRegionWidth = observer(function ({
+ model,
+}: {
+ model: LinearGenomeViewModel
+}) {
+ const { classes } = useStyles()
+ const { coarseTotalBp } = model
+ return (
+ {
+ getSession(model).queueDialog(handleClose => [
+ RegionWidthEditorDialog,
+ {
+ model,
+ handleClose,
+ },
+ ])
+ }}
+ >
+ {getBpDisplayStr(coarseTotalBp)}
+
+ )
+})
+
+export default HeaderRegionWidth
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderTrackSelectorButton.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderTrackSelectorButton.tsx
new file mode 100644
index 0000000000..117fc62194
--- /dev/null
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderTrackSelectorButton.tsx
@@ -0,0 +1,34 @@
+import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons'
+import { IconButton } from '@mui/material'
+import { observer } from 'mobx-react'
+import { makeStyles } from 'tss-react/mui'
+
+import type { LinearGenomeViewModel } from '..'
+
+const useStyles = makeStyles()(theme => ({
+ toggleButton: {
+ height: 44,
+ border: 'none',
+ marginLeft: theme.spacing(4),
+ },
+}))
+
+const HeaderTrackSelectorButton = observer(function ({
+ model,
+}: {
+ model: LinearGenomeViewModel
+}) {
+ const { classes } = useStyles()
+ return (
+
+
+
+ )
+})
+
+export default HeaderTrackSelectorButton
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderZoomControls.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderZoomControls.tsx
new file mode 100644
index 0000000000..6162afbcb2
--- /dev/null
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/HeaderZoomControls.tsx
@@ -0,0 +1,106 @@
+import { useEffect, useState } from 'react'
+
+import ZoomIn from '@mui/icons-material/ZoomIn'
+import ZoomOut from '@mui/icons-material/ZoomOut'
+import { IconButton, Slider, Tooltip } from '@mui/material'
+import { observer } from 'mobx-react'
+import { makeStyles } from 'tss-react/mui'
+
+import type { LinearGenomeViewModel } from '..'
+
+const useStyles = makeStyles()(theme => ({
+ container: {
+ display: 'flex',
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ slider: {
+ width: 100,
+ color: theme.palette.text.secondary,
+ },
+}))
+
+const HeaderZoomControls = observer(function ({
+ model,
+}: {
+ model: LinearGenomeViewModel
+}) {
+ const { classes } = useStyles()
+ const { maxBpPerPx, minBpPerPx, bpPerPx } = model
+ const [value, setValue] = useState(-Math.log2(bpPerPx) * 100)
+ useEffect(() => {
+ setValue(-Math.log2(bpPerPx) * 100)
+ }, [bpPerPx])
+ const zoomInDisabled = bpPerPx <= minBpPerPx + 0.0001
+ const zoomOutDisabled = bpPerPx >= maxBpPerPx - 0.0001
+ return (
+
+
+
+ {
+ model.zoom(bpPerPx * 15)
+ }}
+ >
+
+
+
+
+
+
+ {
+ model.zoom(bpPerPx * 2)
+ }}
+ >
+
+
+
+
+
+ model.zoomTo(2 ** (-value / 100))}
+ onChange={(_, val) => {
+ setValue(val as number)
+ }}
+ />
+
+
+ {
+ model.zoom(model.bpPerPx / 2)
+ }}
+ >
+
+
+
+
+
+
+ {
+ model.zoom(model.bpPerPx / 15)
+ }}
+ >
+
+
+
+
+
+ )
+})
+
+export default HeaderZoomControls
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/RegionWidthEditorDialog.tsx b/plugins/linear-genome-view/src/LinearGenomeView/components/RegionWidthEditorDialog.tsx
new file mode 100644
index 0000000000..8e61e31313
--- /dev/null
+++ b/plugins/linear-genome-view/src/LinearGenomeView/components/RegionWidthEditorDialog.tsx
@@ -0,0 +1,71 @@
+import { useState } from 'react'
+
+import { Dialog } from '@jbrowse/core/ui'
+import {
+ Button,
+ DialogActions,
+ DialogContent,
+ TextField,
+ Typography,
+} from '@mui/material'
+import { observer } from 'mobx-react'
+
+import type { LinearGenomeViewModel } from '../model'
+
+const toP = (s = 0) => +(+s).toFixed(1)
+
+const RegionWidthEditorDialog = observer(function ({
+ model,
+ handleClose,
+}: {
+ model: LinearGenomeViewModel
+ handleClose: () => void
+}) {
+ const [val, setVal] = useState(`${toP(model.bpPerPx)}`)
+ return (
+
+ )
+})
+
+export default RegionWidthEditorDialog
diff --git a/plugins/linear-genome-view/src/LinearGenomeView/model.ts b/plugins/linear-genome-view/src/LinearGenomeView/model.ts
index 32712888b8..becf98703c 100644
--- a/plugins/linear-genome-view/src/LinearGenomeView/model.ts
+++ b/plugins/linear-genome-view/src/LinearGenomeView/model.ts
@@ -1747,6 +1747,5 @@ export {
export { default as RefNameAutocomplete } from './components/RefNameAutocomplete'
export { default as SearchBox } from './components/SearchBox'
-export { default as ZoomControls } from './components/ZoomControls'
export { renderToSvg } from './svgcomponents/SVGLinearGenomeView'
diff --git a/plugins/linear-genome-view/src/index.ts b/plugins/linear-genome-view/src/index.ts
index 42c34075fc..ad90ab36ed 100644
--- a/plugins/linear-genome-view/src/index.ts
+++ b/plugins/linear-genome-view/src/index.ts
@@ -17,8 +17,8 @@ import LinearBasicDisplayF from './LinearBasicDisplay'
import LinearGenomeViewF, {
LinearGenomeView,
SearchBox,
- ZoomControls,
} from './LinearGenomeView'
+import ZoomControls from './LinearGenomeView/components/HeaderZoomControls'
import type PluginManager from '@jbrowse/core/PluginManager'
import type { AbstractSessionModel } from '@jbrowse/core/util'