Skip to content

Commit

Permalink
Add zoom in/out proportional to mouse position
Browse files Browse the repository at this point in the history
Remove some type `any` and avoid contents flying off the screen during
re-renders
  • Loading branch information
cmdcolin committed Mar 4, 2023
1 parent ffe454c commit 7328c19
Show file tree
Hide file tree
Showing 8 changed files with 586 additions and 546 deletions.
8 changes: 4 additions & 4 deletions packages/core/ui/LoadingEllipses.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ const useStyles = makeStyles()({
textAlign: 'left',
animation: `${keyframes`
0% {
content: '...';
content: '';
}
25% {
content: '';
content: '.';
}
50% {
content: '.';
content: '..';
}
75% {
content: '..';
content: '...';
}
`} 1.2s infinite ease-in-out`,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from 'react'
import { observer } from 'mobx-react'
import { getContainingView } from '@jbrowse/core/util'

// locals
import { DotplotDisplayModel } from '../stateModelFactory'
import { DotplotViewModel } from '../../DotplotView/model'

Expand All @@ -9,20 +11,24 @@ function DotplotDisplay(props: {
children?: React.ReactNode
}) {
const { model, children } = props
const { offsetX = 0, offsetY = 0 } = model.data || {}
const { offsetX = 0, offsetY = 0, bpPerPxX, bpPerPxY } = model.data || {}
const view = getContainingView(model) as DotplotViewModel
const same =
view.vview.bpPerPx === bpPerPxY && view.hview.bpPerPx === bpPerPxX
const top = view.vview.offsetPx - offsetY
const left = -(view.hview.offsetPx - offsetX)
return (
<div style={{ position: 'relative' }}>
<model.ReactComponent2
{...props}
style={{
position: 'absolute',
top,
left,
}}
/>
{same ? (
<model.ReactComponent2
{...props}
style={{
position: 'absolute',
top,
left,
}}
/>
) : null}
{children}
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export async function renderBlockEffect(
props?: ReturnType<typeof renderBlockData>,
) {
if (!props) {
throw new Error('cannot render with no props')
return
}

const { rendererType, rpcManager, renderProps } = props
Expand Down
9 changes: 4 additions & 5 deletions plugins/dotplot-view/src/DotplotDisplay/stateModelFactory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,12 @@ export function stateModelFactory(configSchema: AnyConfigurationSchemaType) {
return {
afterAttach() {
makeAbortableReaction(
self as any,
() => renderBlockData(self as any),
(blockData): any =>
blockData ? renderBlockEffect(blockData) : undefined,
self,
() => renderBlockData(self),
blockData => renderBlockEffect(blockData),
{
name: `${self.type} ${self.id} rendering`,
delay: 1000,
delay: 500,
fireImmediately: true,
},
this.setLoading,
Expand Down
2 changes: 2 additions & 0 deletions plugins/dotplot-view/src/DotplotRenderer/DotplotRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,8 @@ export default class DotplotRenderer extends ComparativeRenderer {
width,
offsetX: views[0].dynamicBlocks.blocks[0].offsetPx,
offsetY: views[1].dynamicBlocks.blocks[0].offsetPx,
bpPerPxX: views[0].bpPerPx,
bpPerPxY: views[1].bpPerPx,
}
}
}
34 changes: 22 additions & 12 deletions plugins/dotplot-view/src/DotplotView/components/DotplotView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ const useStyles = makeStyles()(theme => ({
gridColumn: '2/2',
gridRow: '1/2',
},

resizeHandle: {
height: 4,
background: '#ccc',
boxSizing: 'border-box',
borderTop: '1px solid #fafafa',
},
}))

type Coord = [number, number] | undefined
Expand Down Expand Up @@ -84,7 +91,6 @@ const DotplotViewInternal = observer(function ({
}: {
model: DotplotViewModel
}) {
const { cursorMode } = model
const { classes } = useStyles()
const [mousecurrClient, setMouseCurrClient] = useState<Coord>()
const [mousedownClient, setMouseDownClient] = useState<Coord>()
Expand All @@ -97,13 +103,14 @@ const DotplotViewInternal = observer(function ({
const scheduled = useRef(false)
const [ctrlKeyWasUsed, setCtrlKeyWasUsed] = useState(false)
const svg = ref.current?.getBoundingClientRect() || blank
const rootRect = ref.current?.getBoundingClientRect() || blank
const mousedown = getOffset(mousedownClient, svg)
const mousecurr = getOffset(mousecurrClient, svg)
const mouseup = getOffset(mouseupClient, svg)
const mouserect = mouseup || mousecurr
const xdistance = mousedown && mouserect ? mouserect[0] - mousedown[0] : 0
const ydistance = mousedown && mouserect ? mouserect[1] - mousedown[1] : 0
const { hview, vview, wheelMode } = model
const { hview, vview, wheelMode, cursorMode } = model

const validPan =
(cursorMode === 'move' && !ctrlKeyWasUsed) ||
Expand All @@ -130,9 +137,17 @@ const DotplotViewInternal = observer(function ({
hview.scroll(distanceX.current / 3)
vview.scroll(distanceY.current / 10)
} else if (wheelMode === 'zoom') {
const val = distanceY.current < 0 ? 1.1 : 0.9
hview.zoomTo(hview.bpPerPx * val)
vview.zoomTo(vview.bpPerPx * val)
if (
Math.abs(distanceY.current) > Math.abs(distanceX.current) * 2 &&
mousecurr
) {
const val = distanceY.current < 0 ? 1.1 : 0.9
hview.zoomTo(hview.bpPerPx * val, mousecurr[0])
vview.zoomTo(
vview.bpPerPx * val,
rootRect.height - mousecurr[1],
)
}
}
})
scheduled.current = false
Expand All @@ -147,7 +162,7 @@ const DotplotViewInternal = observer(function ({
return () => curr.removeEventListener('wheel', onWheel)
}
return () => {}
}, [hview, vview, wheelMode])
}, [hview, vview, wheelMode, mousecurr, rootRect.height])

useEffect(() => {
function globalMouseMove(event: MouseEvent) {
Expand Down Expand Up @@ -308,12 +323,7 @@ const DotplotViewInternal = observer(function ({
</div>
<ResizeHandle
onDrag={n => model.setHeight(model.height + n)}
style={{
height: 4,
background: '#ccc',
boxSizing: 'border-box',
borderTop: '1px solid #fafafa',
}}
className={classes.resizeHandle}
/>
</div>
</div>
Expand Down
33 changes: 28 additions & 5 deletions plugins/dotplot-view/src/DotplotView/components/PanButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import React from 'react'
import { IconButton, Paper } from '@mui/material'
import { makeStyles } from 'tss-react/mui'
import { observer } from 'mobx-react'

// icons
import ArrowDropDown from '@mui/icons-material/ArrowDropDown'
import ArrowDropUp from '@mui/icons-material/ArrowDropUp'
import ArrowLeft from '@mui/icons-material/ArrowLeft'
import ArrowRight from '@mui/icons-material/ArrowRight'
import ZoomIn from '@mui/icons-material/ZoomIn'
import ZoomOut from '@mui/icons-material/ZoomOut'

// locals
import { DotplotViewModel } from '../model'
import { observer } from 'mobx-react'

const useStyles = makeStyles()(theme => ({
const useStyles = makeStyles()({
dpad: {
display: 'grid',
gridTemplateColumns: 'repeat(3, 1fr)',
Expand All @@ -24,7 +28,7 @@ const useStyles = makeStyles()(theme => ({
padding: 0,
margin: 0,
},
}))
})

export default observer(function PanButtons({
model,
Expand All @@ -45,14 +49,14 @@ export default observer(function PanButtons({

<IconButton
className={classes.icon}
onClick={() => model.hview.scroll(100)}
onClick={() => model.hview.scroll(-100)}
>
<ArrowLeft />
</IconButton>
<div />
<IconButton
className={classes.icon}
onClick={() => model.hview.scroll(-100)}
onClick={() => model.hview.scroll(100)}
>
<ArrowRight />
</IconButton>
Expand All @@ -65,6 +69,25 @@ export default observer(function PanButtons({
<ArrowDropDown />
</IconButton>
<div />
<IconButton
className={classes.icon}
onClick={() => {
model.hview.zoomIn()
model.vview.zoomIn()
}}
>
<ZoomIn />
</IconButton>
<div />
<IconButton
className={classes.icon}
onClick={() => {
model.hview.zoomOut()
model.vview.zoomOut()
}}
>
<ZoomOut />
</IconButton>
</Paper>
)
})
Loading

0 comments on commit 7328c19

Please sign in to comment.