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

Use extendPluggableElement for context menu items #2229

Merged
merged 2 commits into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions plugins/alignments/src/LinearPileupDisplay/model.ts
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ const stateModelFactory = (
return rendererType return rendererType
}, },


get contextMenuItems() { contextMenuItems() {
const feat = self.contextMenuFeature const feat = self.contextMenuFeature
const contextMenuItems = feat const contextMenuItems = feat
? [ ? [
Expand All @@ -378,12 +378,6 @@ const stateModelFactory = (
}, },
] ]
: [] : []
self.additionalContextMenuItemCallbacks.forEach(
(callback: Function) => {
const menuItems = callback(feat, self, pluginManager)
contextMenuItems.push(...menuItems)
},
)
return contextMenuItems return contextMenuItems
}, },


Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ const stateModelFactory = (
return true return true
}, },


get contextMenuItems() { contextMenuItems() {
return [] return []
}, },


Expand Down
2 changes: 2 additions & 0 deletions plugins/alignments/src/index.ts
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
configSchemaFactory as linearPileupDisplayConfigSchemaFactory, configSchemaFactory as linearPileupDisplayConfigSchemaFactory,
modelFactory as linearPileupDisplayModelFactory, modelFactory as linearPileupDisplayModelFactory,
} from './LinearPileupDisplay' } from './LinearPileupDisplay'
import { LinearPileupDisplayModel } from './LinearPileupDisplay/model'
import { import {
configSchemaFactory as linearSNPCoverageDisplayConfigSchemaFactory, configSchemaFactory as linearSNPCoverageDisplayConfigSchemaFactory,
modelFactory as linearSNPCoverageDisplayModelFactory, modelFactory as linearSNPCoverageDisplayModelFactory,
Expand All @@ -48,6 +49,7 @@ import {
} from './PileupRPC/rpcMethods' } from './PileupRPC/rpcMethods'


export { MismatchParser } export { MismatchParser }
export type { LinearPileupDisplayModel }


export default class AlignmentsPlugin extends Plugin { export default class AlignmentsPlugin extends Plugin {
name = 'AlignmentsPlugin' name = 'AlignmentsPlugin'
Expand Down
225 changes: 103 additions & 122 deletions plugins/dotplot-view/src/index.ts
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'


import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType' import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType'
import AddIcon from '@material-ui/icons/Add' import AddIcon from '@material-ui/icons/Add'
import { autorun } from 'mobx'
import PluginManager from '@jbrowse/core/PluginManager' import PluginManager from '@jbrowse/core/PluginManager'
import { import {
AbstractSessionModel, AbstractSessionModel,
Expand All @@ -15,10 +14,8 @@ import {


import { getConf } from '@jbrowse/core/configuration' import { getConf } from '@jbrowse/core/configuration'
import { Feature } from '@jbrowse/core/util/simpleFeature' import { Feature } from '@jbrowse/core/util/simpleFeature'
import { AbstractDisplayModel } from '@jbrowse/core/util/types'
import TimelineIcon from '@material-ui/icons/Timeline' import TimelineIcon from '@material-ui/icons/Timeline'
import { MismatchParser } from '@jbrowse/plugin-alignments' import { MismatchParser } from '@jbrowse/plugin-alignments'
import { IAnyStateTreeNode } from 'mobx-state-tree'
import { import {
configSchemaFactory as dotplotDisplayConfigSchemaFactory, configSchemaFactory as dotplotDisplayConfigSchemaFactory,
stateModelFactory as dotplotDisplayStateModelFactory, stateModelFactory as dotplotDisplayStateModelFactory,
Expand All @@ -35,15 +32,15 @@ import {
AdapterClass as PAFAdapter, AdapterClass as PAFAdapter,
} from './PAFAdapter' } from './PAFAdapter'
import ComparativeRender from './DotplotRenderer/ComparativeRenderRpc' import ComparativeRender from './DotplotRenderer/ComparativeRenderRpc'
import { PluggableElementType } from '@jbrowse/core/pluggableElementTypes'
import { LinearPileupDisplayModel } from '@jbrowse/plugin-alignments'


const { parseCigar } = MismatchParser const { parseCigar } = MismatchParser


interface Track { interface Track {
id: string id: string
type: string type: string
displays: { displays: {
addAdditionalContextMenuItemCallback: Function
additionalContextMenuItemCallbacks: Function[]
id: string id: string
type: string type: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down Expand Up @@ -176,85 +173,17 @@ interface ReducedFeature {
seqLength: number seqLength: number
} }


export default class DotplotPlugin extends Plugin { function onClick(feature: Feature, self: LinearPileupDisplayModel) {
name = 'DotplotPlugin' const session = getSession(self)

try {
install(pluginManager: PluginManager) {
pluginManager.addViewType(() => {
return new ViewType({
name: 'DotplotView',
stateModel: stateModelFactory(pluginManager),
ReactComponent: lazy(
() => import('./DotplotView/components/DotplotView'),
),
})
})

pluginManager.addDisplayType(() => {
const configSchema = dotplotDisplayConfigSchemaFactory(pluginManager)
return new DisplayType({
name: 'DotplotDisplay',
configSchema,
stateModel: dotplotDisplayStateModelFactory(configSchema),
trackType: 'SyntenyTrack',
viewType: 'DotplotView',
ReactComponent: DotplotDisplayReactComponent,
})
})

pluginManager.addRendererType(
() =>
new DotplotRenderer({
name: 'DotplotRenderer',
configSchema: dotplotRendererConfigSchema,
ReactComponent: DotplotRendererReactComponent,
pluginManager,
}),
)

pluginManager.addAdapterType(
() =>
new AdapterType({
name: 'PAFAdapter',
configSchema: PAFAdapterConfigSchema,
AdapterClass: PAFAdapter,
}),
)

// install our comparative rendering rpc callback
pluginManager.addRpcMethod(() => new ComparativeRender(pluginManager))
}

configure(pluginManager: PluginManager) {
if (isAbstractMenuManager(pluginManager.rootModel)) {
pluginManager.rootModel.appendToSubMenu(['File', 'Add'], {
label: 'Dotplot view',
icon: TimelineIcon,
onClick: (session: AbstractSessionModel) => {
session.addView('DotplotView', {})
},
})
}

const cb = (
feature: Feature,
display: AbstractDisplayModel & IAnyStateTreeNode,
) => {
const { parentTrack } = display
return feature
? [
{
label: 'Dotplot of read vs ref',
icon: AddIcon,
onClick: () => {
const session = getSession(display)
const cigar = feature.get('CIGAR') const cigar = feature.get('CIGAR')
const clipPos = getClip(cigar, 1) const clipPos = getClip(cigar, 1)
const flags = feature.get('flags') const flags = feature.get('flags')
const origStrand = feature.get('strand') const origStrand = feature.get('strand')
const SA: string = getTag(feature, 'SA') || '' const SA: string = getTag(feature, 'SA') || ''
const readName = feature.get('name') const readName = feature.get('name')
const readAssembly = `${readName}_assembly` const readAssembly = `${readName}_assembly`
const { parentTrack } = self
const [trackAssembly] = getConf(parentTrack, 'assemblyNames') const [trackAssembly] = getConf(parentTrack, 'assemblyNames')
const assemblyNames = [trackAssembly, readAssembly] const assemblyNames = [trackAssembly, readAssembly]
const trackId = `track-${Date.now()}` const trackId = `track-${Date.now()}`
Expand All @@ -267,10 +196,7 @@ export default class DotplotPlugin extends Plugin {
const saLength = getLength(saCigar) const saLength = getLength(saCigar)
const saLengthSansClipping = getLengthSansClipping(saCigar) const saLengthSansClipping = getLengthSansClipping(saCigar)
const saStrandNormalized = saStrand === '-' ? -1 : 1 const saStrandNormalized = saStrand === '-' ? -1 : 1
const saClipPos = getClip( const saClipPos = getClip(saCigar, saStrandNormalized * origStrand)
saCigar,
saStrandNormalized * origStrand,
)
const saRealStart = +saStart - 1 const saRealStart = +saStart - 1
return { return {
refName: saRef, refName: saRef,
Expand Down Expand Up @@ -306,17 +232,11 @@ export default class DotplotPlugin extends Plugin {
flags & 2048 ? supplementaryAlignments[0].CIGAR : cigar, flags & 2048 ? supplementaryAlignments[0].CIGAR : cigar,
) )


const features = [ const features = [feat, ...supplementaryAlignments] as ReducedFeature[]
feat,
...supplementaryAlignments,
] as ReducedFeature[]


features.sort((a, b) => a.clipPos - b.clipPos) features.sort((a, b) => a.clipPos - b.clipPos)


const refLength = features.reduce( const refLength = features.reduce((a, f) => a + f.end - f.start, 0)
(a, f) => a + f.end - f.start,
0,
)


session.addView('DotplotView', { session.addView('DotplotView', {
type: 'DotplotView', type: 'DotplotView',
Expand Down Expand Up @@ -390,46 +310,107 @@ export default class DotplotPlugin extends Plugin {
], ],
displayName: `${readName} vs ${trackAssembly}`, displayName: `${readName} vs ${trackAssembly}`,
}) })
}, } catch (e) {
}, console.error(e)
] session.notify(`${e}`, 'error')
: []
}
function addContextMenu(view: View) {
if (view.type === 'LinearGenomeView') {
view.tracks.forEach(track => {
if (track.type === 'AlignmentsTrack') {
track.displays.forEach(display => {
if (
display.type === 'LinearPileupDisplay' &&
!display.additionalContextMenuItemCallbacks.includes(cb)
) {
display.addAdditionalContextMenuItemCallback(cb)
} else if (
display.type === 'LinearAlignmentsDisplay' &&
display.PileupDisplay &&
!display.PileupDisplay.additionalContextMenuItemCallbacks.includes(
cb,
)
) {
display.PileupDisplay.addAdditionalContextMenuItemCallback(cb)
} }
})
} }

export default class DotplotPlugin extends Plugin {
name = 'DotplotPlugin'

install(pluginManager: PluginManager) {
pluginManager.addViewType(() => {
return new ViewType({
name: 'DotplotView',
stateModel: stateModelFactory(pluginManager),
ReactComponent: lazy(
() => import('./DotplotView/components/DotplotView'),
),
})
})

pluginManager.addDisplayType(() => {
const configSchema = dotplotDisplayConfigSchemaFactory(pluginManager)
return new DisplayType({
name: 'DotplotDisplay',
configSchema,
stateModel: dotplotDisplayStateModelFactory(configSchema),
trackType: 'SyntenyTrack',
viewType: 'DotplotView',
ReactComponent: DotplotDisplayReactComponent,
})
}) })

pluginManager.addRendererType(
() =>
new DotplotRenderer({
name: 'DotplotRenderer',
configSchema: dotplotRendererConfigSchema,
ReactComponent: DotplotRendererReactComponent,
pluginManager,
}),
)

pluginManager.addAdapterType(
() =>
new AdapterType({
name: 'PAFAdapter',
configSchema: PAFAdapterConfigSchema,
AdapterClass: PAFAdapter,
}),
)

// install our comparative rendering rpc callback
pluginManager.addRpcMethod(() => new ComparativeRender(pluginManager))

pluginManager.addToExtensionPoint(
'Core-extendPluggableElement',
(pluggableElement: PluggableElementType) => {
if (pluggableElement.name === 'LinearPileupDisplay') {
const { stateModel } = pluggableElement as ViewType
const newStateModel = stateModel.extend(
(self: LinearPileupDisplayModel) => {
const superContextMenuItems = self.contextMenuItems
return {
views: {
contextMenuItems() {
const feature = self.contextMenuFeature
if (!feature) {
return superContextMenuItems()
}
const newMenuItems = [
...superContextMenuItems(),
{
label: 'Dotplot of read vs ref',
icon: AddIcon,
onClick: () => onClick(feature, self),
},
]

return newMenuItems
},
},
} }
},
)

;(pluggableElement as DisplayType).stateModel = newStateModel
} }
autorun(() => { return pluggableElement
const session = pluginManager.rootModel?.session as Session | undefined },
if (session) { )
session.views.forEach(view => {
if (view.views) {
view.views.forEach(v => addContextMenu(v))
} else {
addContextMenu(view)
} }

configure(pluginManager: PluginManager) {
if (isAbstractMenuManager(pluginManager.rootModel)) {
pluginManager.rootModel.appendToSubMenu(['File', 'Add'], {
label: 'Dotplot view',
icon: TimelineIcon,
onClick: (session: AbstractSessionModel) => {
session.addView('DotplotView', {})
},
}) })
} }
})
} }
} }
Loading