Skip to content

Commit

Permalink
Clear selection
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Mar 14, 2024
1 parent 3fd05a5 commit ad83306
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 228 deletions.
5 changes: 5 additions & 0 deletions src/ProteinView/clearSelection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PluginContext } from 'molstar/lib/mol-plugin/context'

export default function clearSelection({ plugin }: { plugin: PluginContext }) {
plugin?.managers.interactivity.lociSelects.deselectAll()
}
63 changes: 63 additions & 0 deletions src/ProteinView/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { useState } from 'react'
import { observer } from 'mobx-react'
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'

// icons
import MenuIcon from '@mui/icons-material/Menu'

// locals
import { JBrowsePluginProteinViewModel } from '../model'
import ProteinAlignment from './ProteinAlignment'
import { Visibility } from '@mui/icons-material'

const ProteinViewHeader = observer(function ({
model,
}: {
model: JBrowsePluginProteinViewModel
}) {
const { clickString, hoverString, showHighlight, zoomToBaseLevel } = model
const [show, setShow] = useState(true)
return (
<div>
<div style={{ display: 'flex' }}>
<span>
{[
clickString ? `Click: ${clickString}` : '',
hoverString ? `Hover: ${hoverString}` : '',
].join(' ')}
</span>
<span style={{ flexGrow: 1 }} />
<CascadingMenuButton
menuItems={[
{
label: 'Show alignment',
type: 'checkbox',
checked: show,
icon: Visibility,
onClick: () => setShow(!show),
},
{
label: 'Show highlight',
type: 'checkbox',
checked: showHighlight,
icon: Visibility,
onClick: () => model.setShowHighlight(!showHighlight),
},
{
label: 'Zoom to base level on click',
type: 'checkbox',
checked: zoomToBaseLevel,
icon: Visibility,
onClick: () => model.setZoomToBaseLevel(!zoomToBaseLevel),
},
]}
>
<MenuIcon />
</CascadingMenuButton>
</div>
<div>{show ? <ProteinAlignment model={model} /> : null}</div>
</div>
)
})

export default ProteinViewHeader
34 changes: 21 additions & 13 deletions src/ProteinView/components/HelpButton.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
import React, { Suspense, lazy, useState } from 'react'
import React, { lazy } from 'react'
import { IconButton } from '@mui/material'
import { getSession } from '@jbrowse/core/util'

// locals
import { JBrowsePluginProteinViewModel } from '../model'

// icons
import Help from '@mui/icons-material/Help'

const HelpDialog = lazy(() => import('./HelpDialog'))

export default function HelpButton() {
const [open, setOpen] = useState(false)
export default function HelpButton({
model,
}: {
model: JBrowsePluginProteinViewModel
}) {
return (
<>
<IconButton style={{ float: 'right' }} onClick={() => setOpen(true)}>
<Help />
</IconButton>
{open ? (
<Suspense fallback={null}>
<HelpDialog handleClose={() => setOpen(false)} />
</Suspense>
) : null}
</>
<IconButton
style={{ float: 'right' }}
onClick={() =>
getSession(model).queueDialog(handleClose => [
HelpDialog,
{ handleClose },
])
}
>
<Help />
</IconButton>
)
}
7 changes: 6 additions & 1 deletion src/ProteinView/components/ProteinAlignment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const ProteinAlignment = observer(function ({
alignment,
structurePositionToAlignmentMap,
alignmentToStructurePosition,
showHighlight,
} = model
const a0 = alignment!.alns[0].seq as string
const a1 = alignment!.alns[1].seq as string
Expand Down Expand Up @@ -52,7 +53,8 @@ const ProteinAlignment = observer(function ({
}
return (
<div>
<HelpButton />
<HelpButton model={model} />

<Typography>
Alignment of the protein structure file&apos;s sequence with the
selected transcript&apos;s sequence. Green is the aligned portion
Expand All @@ -78,6 +80,7 @@ const ProteinAlignment = observer(function ({
</Tooltip>
<SplitString
str={a0}
showHighlight={showHighlight}
col={alignmentHoverPos}
set={set}
onMouseOver={onMouseOver}
Expand All @@ -87,6 +90,7 @@ const ProteinAlignment = observer(function ({
<div>
<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
<SplitString
showHighlight={showHighlight}
str={con}
col={alignmentHoverPos}
set={set}
Expand All @@ -101,6 +105,7 @@ const ProteinAlignment = observer(function ({
<SplitString
str={a1}
col={alignmentHoverPos}
showHighlight={showHighlight}
set={set}
onMouseOver={onMouseOver}
onClick={onClick}
Expand Down
41 changes: 26 additions & 15 deletions src/ProteinView/components/ProteinView.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import React, { useEffect } from 'react'
import { observer } from 'mobx-react'
import { ErrorMessage } from '@jbrowse/core/ui'
import { ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui'
import { PluginContext } from 'molstar/lib/mol-plugin/context'

// locals

import { JBrowsePluginProteinViewModel } from '../model'
import ProteinViewHeader from './ProteinViewHeader'
import Header from './Header'

// hooks
import useProteinView from '../useProteinView'
import useProteinViewClickBehavior from '../useProteinViewClickBehavior'
import useProteinViewHoverBehavior from '../useProteinViewHoverBehavior'

// utils
import selectResidue from '../selectResidue'
import css from '../css/molstar'
import highlightResidue from '../highlightResidue'
import { PluginContext } from 'molstar/lib/mol-plugin/context'
import clearSelection from '../clearSelection'

// css
import css from '../css/molstar'

if (document?.head) {
const style = document.createElement('style')
Expand All @@ -27,21 +31,23 @@ const ProteinView = observer(function ({
}: {
model: JBrowsePluginProteinViewModel
}) {
const { url, data, showControls } = model
const { url, data, showControls, alignment } = model
const { plugin, seq, parentRef, error } = useProteinView({
url,
data,
showControls,
})
return error ? (
<ErrorMessage error={error} />
) : (
) : alignment ? (
<ProteinViewContainer
model={model}
plugin={plugin}
seq={seq}
parentRef={parentRef}
/>
) : (
<LoadingEllipses title="Loading pairwise alignment" />
)
})

Expand All @@ -62,6 +68,7 @@ const ProteinViewContainer = observer(function ({
structureSeqToTranscriptSeqPosition,
seq2,
structureSeqHoverPos,
showHighlight,
} = model

const { error } = useProteinViewClickBehavior({ plugin, model })
Expand All @@ -78,14 +85,18 @@ const ProteinViewContainer = observer(function ({
if (!plugin || !structureSeqToTranscriptSeqPosition || !structure) {
return
}
for (const coord of Object.keys(structureSeqToTranscriptSeqPosition)) {
selectResidue({
structure,
plugin,
selectedResidue: +coord + 1,
})
if (showHighlight) {
for (const coord of Object.keys(structureSeqToTranscriptSeqPosition)) {
selectResidue({
structure,
plugin,
selectedResidue: +coord + 1,
})
}
} else {
clearSelection({ plugin })
}
}, [plugin, structure, structureSeqToTranscriptSeqPosition])
}, [plugin, structure, showHighlight, structureSeqToTranscriptSeqPosition])

useEffect(() => {
if (!plugin || !structure || structureSeqHoverPos === undefined) {
Expand All @@ -105,7 +116,7 @@ const ProteinViewContainer = observer(function ({
return (
<div>
{error ? <ErrorMessage error={error} /> : null}
<ProteinViewHeader model={model} />
<Header model={model} />
<div
ref={parentRef}
style={{
Expand Down
48 changes: 0 additions & 48 deletions src/ProteinView/components/ProteinViewHeader.tsx

This file was deleted.

5 changes: 4 additions & 1 deletion src/ProteinView/components/SplitString.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import React from 'react'

export default function SplitString({
str,
col,
set,
onMouseOver,
onClick,
showHighlight,
}: {
str: string
col?: number
set?: Set<number>
onMouseOver?: (arg: number) => void
onClick?: (arg: number) => void
showHighlight: boolean
}) {
return str.split('').map((d, i) => (
<span
Expand All @@ -21,7 +24,7 @@ export default function SplitString({
background:
col !== undefined && i === col
? '#f69'
: set?.has(i)
: set?.has(i) && showHighlight
? '#33ff19'
: undefined,
}}
Expand Down
20 changes: 20 additions & 0 deletions src/ProteinView/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ function stateModelFactory() {
* #property
*/
connectedViewId: types.maybe(types.string),
/**
* #property
*/
showHighlight: true,
/**
* #property
*/
zoomToBaseLevel: false,
}),
)
.volatile(() => ({
Expand Down Expand Up @@ -206,6 +214,18 @@ function stateModelFactory() {
setAlignment(r?: ReturnType<typeof parsePairwise>) {
self.alignment = r
},
/**
* #action
*/
setShowHighlight(arg: boolean) {
self.showHighlight = arg
},
/**
* #action
*/
setZoomToBaseLevel(arg: boolean) {
self.zoomToBaseLevel = arg
},
}))
.views(self => ({
/**
Expand Down
17 changes: 13 additions & 4 deletions src/ProteinView/proteinToGenomeMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ export async function clickProteinToGenome({
}) {
const session = getSession(model)
const result = proteinToGenomeMapping({ structureSeqPos, model })
const { genomeToTranscriptSeqMapping } = model
const { genomeToTranscriptSeqMapping, zoomToBaseLevel } = model
const { assemblyManager } = session
if (!genomeToTranscriptSeqMapping || result === undefined) {
return undefined
}
Expand All @@ -57,9 +58,17 @@ export async function clickProteinToGenome({
end: s2,
},
])
await lgv.navToLocString(
`${refName}:${s1}-${s2}${strand === -1 ? '[rev]' : ''}`,
)

if (!zoomToBaseLevel) {
const assembly = assemblyManager.get(lgv.assemblyNames[0])
const r = assembly?.getCanonicalRefName(refName) ?? refName
// @ts-expect-error
lgv.centerAt(s1, r)
} else {
await lgv.navToLocString(
`${refName}:${s1}-${s2}${strand === -1 ? '[rev]' : ''}`,
)
}
}

export function hoverProteinToGenome({
Expand Down
Loading

0 comments on commit ad83306

Please sign in to comment.