Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds URL query param for highlight on LGV #4234

Merged
merged 11 commits into from
Feb 27, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { observer } from 'mobx-react'
import { makeStyles } from 'tss-react/mui'
import { SessionWithWidgets, getSession, notEmpty } from '@jbrowse/core/util'
import { colord } from '@jbrowse/core/util/colord'
import { Tooltip } from '@mui/material'

// icons
import BookmarkIcon from '@mui/icons-material/Bookmark'

// locals
import { Tooltip } from '@mui/material'
import { GridBookmarkModel } from '../../model'
import { IExtendedLGV } from '../../model'

Expand Down
17 changes: 16 additions & 1 deletion plugins/linear-genome-view/src/LaunchLinearGenomeView/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PluginManager from '@jbrowse/core/PluginManager'
import { AbstractSessionModel, when } from '@jbrowse/core/util'
import { AbstractSessionModel, when, parseLocString } from '@jbrowse/core/util'
// locals
import { LinearGenomeViewModel } from '../LinearGenomeView'
import { handleSelectedRegion } from '../searchUtils'
Expand All @@ -17,16 +17,21 @@ export default (pluginManager: PluginManager) => {
tracks = [],
tracklist,
nav,
highlight,
}: {
session: AbstractSessionModel
assembly?: string
loc: string
tracks?: string[]
tracklist?: boolean
nav?: boolean
highlight?: string
}) => {
try {
const { assemblyManager } = session

const { isValidRefName } = assemblyManager

const view = session.addView('LinearGenomeView', {}) as LGV

await when(() => !!view.volatileWidth)
Expand Down Expand Up @@ -59,6 +64,16 @@ export default (pluginManager: PluginManager) => {
if (nav !== undefined) {
view.setHideHeader(!nav)
}
if (highlight !== undefined) {
const location = parseLocString(highlight, refName =>
isValidRefName(refName, assembly),
)
if (location?.start && location?.end) {
location.assemblyName = assembly

view.setHighlight(location)
}
}
} catch (e) {
session.notify(`${e}`, 'error')
throw e
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react'
import { observer } from 'mobx-react'
import { makeStyles } from 'tss-react/mui'
import { colord } from '@jbrowse/core/util/colord'
import { Tooltip } from '@mui/material'

// icons
import LinkIcon from '@mui/icons-material/Link'

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

type LGV = LinearGenomeViewModel

const useStyles = makeStyles()({
highlight: {
height: '100%',
position: 'absolute',
textAlign: 'center',
overflow: 'hidden',
display: 'flex',
carolinebridge marked this conversation as resolved.
Show resolved Hide resolved
alignItems: 'start',
},
})

interface ParsedLocStringA {
assemblyName: string
refName: string
start: number
end: number
reversed: boolean
}

const Highlight = observer(function Highlight({ model }: { model: LGV }) {
const { classes } = useStyles()

if (!model.highlight) {
return
}

// coords
const mapCoords = (r: ParsedLocStringA) => {
const s = model.bpToPx({
refName: r.refName,
coord: r.start,
})
const e = model.bpToPx({
refName: r.refName,
coord: r.end,
})
return s && e
? {
width: Math.max(Math.abs(e.offsetPx - s.offsetPx), 3),
left: Math.min(s.offsetPx, e.offsetPx) - model.offsetPx,
}
: undefined
}

const h = mapCoords(model.highlight)
const color = 'rgba(252, 186, 3, 0.35)'

return (
<>
{h ? (
<div
key={`${h.left}_${h.width}`}
carolinebridge marked this conversation as resolved.
Show resolved Hide resolved
className={classes.highlight}
style={{ left: h.left, width: h.width, background: color }}
>
<Tooltip title={'Highlighted from URL parameter'} arrow>
<LinkIcon
fontSize="small"
sx={{
color: `${
colord(color).alpha() !== 0
carolinebridge marked this conversation as resolved.
Show resolved Hide resolved
? colord(color).alpha(0.8).toRgbString()
: colord(color).alpha(0).toRgbString()
}`,
}}
/>
</Tooltip>
</div>
) : null}
</>
)
})

export default Highlight
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Gridlines from './Gridlines'
import CenterLine from './CenterLine'
import VerticalGuide from './VerticalGuide'
import RubberbandSpan from './RubberbandSpan'
import Highlight from './Highlight'

const useStyles = makeStyles()({
tracksContainer: {
Expand Down Expand Up @@ -107,6 +108,7 @@ const TracksContainer = observer(function TracksContainer({
/>
}
/>
<Highlight model={model} />
{additional}
{children}
</div>
Expand Down
12 changes: 12 additions & 0 deletions plugins/linear-genome-view/src/LinearGenomeView/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@ export function stateModelFactory(pluginManager: PluginManager) {
* show the "gridlines" in the track area
*/
showGridlines: true,

/**
* #property
* highlights on the LGV from the URL parameters
*/
highlight: types.optional(types.frozen(), ''),
carolinebridge marked this conversation as resolved.
Show resolved Hide resolved
}),
)
.volatile(() => ({
Expand Down Expand Up @@ -581,6 +587,12 @@ export function stateModelFactory(pluginManager: PluginManager) {
setShowGridlines(b: boolean) {
self.showGridlines = b
},
/**
* #action
*/
setHighlight(highlight: ParsedLocString) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with above comment, can make it "|undefined" so that undefined clears it

self.highlight = highlight
},
/**
* #action
*/
Expand Down
3 changes: 3 additions & 0 deletions products/jbrowse-web/src/SessionLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const SessionLoader = types
assembly: types.maybe(types.string),
tracks: types.maybe(types.string),
tracklist: types.maybe(types.boolean),
highlight: types.maybe(types.string),
nav: types.maybe(types.boolean),
initialTimestamp: types.number,
})
Expand Down Expand Up @@ -285,6 +286,7 @@ const SessionLoader = types
assembly,
tracklist,
nav,
highlight,
sessionTracksParsed: sessionTracks,
} = self
if (loc) {
Expand All @@ -299,6 +301,7 @@ const SessionLoader = types
assembly,
tracklist,
nav,
highlight,
},
],
}
Expand Down
4 changes: 4 additions & 0 deletions products/jbrowse-web/src/components/Loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function Loader({
const [sessionTracks, setSessionTracks] = useQueryParam('sessionTracks', Str)
const [assembly, setAssembly] = useQueryParam('assembly', Str)
const [tracks, setTracks] = useQueryParam('tracks', Str)
const [highlight, setHighlight] = useQueryParam('highlight', Str)
const [nav, setNav] = useQueryParam('nav', Str)
const [tracklist, setTrackList] = useQueryParam('tracklist', Str)

Expand All @@ -61,6 +62,7 @@ export function Loader({
tracks: normalize(tracks),
sessionTracks: normalize(sessionTracks),
tracklist: JSON.parse(normalize(tracklist) || 'false'),
highlight: normalize(highlight),
nav: JSON.parse(normalize(nav) || 'true'),
initialTimestamp,
})
Expand All @@ -73,6 +75,7 @@ export function Loader({
setSessionTracks(undefined, 'replaceIn')
setTrackList(undefined, 'replaceIn')
setNav(undefined, 'replaceIn')
setHighlight(undefined, 'replaceIn')
}, [
setAssembly,
setLoc,
Expand All @@ -81,6 +84,7 @@ export function Loader({
setTracks,
setPassword,
setSessionTracks,
setHighlight,
])

return <Renderer loader={loader} />
Expand Down
Loading