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 ( + + + + Allows editing the zoom level using the 'base pairs per pixel' + measurement + + + Large numbers e.g. 10 means there are 10 base pairs in each pixel, + small numbers e.g. 0.1 means there are 10 pixels for each base pair + + { + setVal(event.target.value) + }} + /> + + + + + + + ) +}) + +export default RegionWidthEditorDialog diff --git a/plugins/linear-genome-view/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap b/plugins/linear-genome-view/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap index 5c5353c298..a00d902dc9 100644 --- a/plugins/linear-genome-view/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap +++ b/plugins/linear-genome-view/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap @@ -101,7 +101,7 @@ exports[`renders one track, one region 1`] = ` >

100bp

@@ -727,7 +727,7 @@ exports[`renders two tracks, two regions 1`] = ` >

798bp

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' diff --git a/products/jbrowse-react-linear-genome-view/src/JBrowseLinearGenomeView/__snapshots__/JBrowseLinearGenomeView.test.tsx.snap b/products/jbrowse-react-linear-genome-view/src/JBrowseLinearGenomeView/__snapshots__/JBrowseLinearGenomeView.test.tsx.snap index 42b99228ef..312c80f02c 100644 --- a/products/jbrowse-react-linear-genome-view/src/JBrowseLinearGenomeView/__snapshots__/JBrowseLinearGenomeView.test.tsx.snap +++ b/products/jbrowse-react-linear-genome-view/src/JBrowseLinearGenomeView/__snapshots__/JBrowseLinearGenomeView.test.tsx.snap @@ -186,7 +186,7 @@ exports[` renders successfully 1`] = ` >

40bp