@@ -8,7 +8,14 @@ import {
88import SerializableFilterChain from '@jbrowse/core/pluggableElementTypes/renderers/util/serializableFilterChain'
99import { SimpleFeature , getSession } from '@jbrowse/core/util'
1010import { getRpcSessionId } from '@jbrowse/core/util/tracks'
11- import { cast , getParent , isAlive , types } from '@jbrowse/mobx-state-tree'
11+ import {
12+ addDisposer ,
13+ cast ,
14+ getParent ,
15+ isAlive ,
16+ types ,
17+ } from '@jbrowse/mobx-state-tree'
18+ import { reaction } from 'mobx'
1219import VisibilityIcon from '@mui/icons-material/Visibility'
1320
1421import { BaseLinearDisplay } from '../BaseLinearDisplay/index.ts'
@@ -83,7 +90,7 @@ function stateModelFactory(configSchema: AnyConfigurationSchemaType) {
8390 /**
8491 * #getter
8592 */
86- get activeFilters ( ) {
93+ get activeFilters ( ) : string [ ] {
8794 // config jexlFilters are deferred evaluated so they are prepended with
8895 // jexl at runtime rather than being stored with jexl in the config
8996 return (
@@ -264,7 +271,9 @@ function stateModelFactory(configSchema: AnyConfigurationSchemaType) {
264271 trackInstanceId : parentTrack . id ,
265272 rendererType : self . rendererTypeName ,
266273 } ,
267- ) ) as { feature : SimpleFeatureSerialized | undefined }
274+ ) ) as {
275+ feature : SimpleFeatureSerialized | undefined
276+ }
268277
269278 if ( isAlive ( self ) && feature ) {
270279 self . selectFeature ( new SimpleFeature ( feature ) )
@@ -293,7 +302,9 @@ function stateModelFactory(configSchema: AnyConfigurationSchemaType) {
293302 trackInstanceId : parentTrack . id ,
294303 rendererType : self . rendererTypeName ,
295304 } ,
296- ) ) as { feature : SimpleFeatureSerialized | undefined }
305+ ) ) as {
306+ feature : SimpleFeatureSerialized | undefined
307+ }
297308
298309 if ( isAlive ( self ) && feature ) {
299310 self . setContextMenuFeature ( new SimpleFeature ( feature ) )
@@ -393,6 +404,55 @@ function stateModelFactory(configSchema: AnyConfigurationSchemaType) {
393404 } ,
394405 }
395406 } )
407+ . actions ( self => ( {
408+ afterAttach ( ) {
409+ // Set up a reaction to fetch feature details when hovering
410+ // This enables custom mouseover jexl expressions that use get(feature, ...)
411+ addDisposer (
412+ self ,
413+ reaction (
414+ ( ) => self . featureIdUnderMouse ,
415+ async featureId => {
416+ if ( ! featureId ) {
417+ self . setFeatureUnderMouse ( undefined )
418+ return
419+ }
420+
421+ const session = getSession ( self )
422+ const { rpcManager } = session
423+ const { parentTrack } = self
424+ try {
425+ const sessionId = getRpcSessionId ( self )
426+ const { feature } = ( await rpcManager . call (
427+ sessionId ,
428+ 'CoreGetFeatureDetails' ,
429+ {
430+ featureId,
431+ sessionId,
432+ trackInstanceId : parentTrack . id ,
433+ rendererType : self . rendererTypeName ,
434+ } ,
435+ ) ) as {
436+ feature : SimpleFeatureSerialized | undefined
437+ }
438+
439+ // Only set if still alive and feature ID hasn't changed
440+ if (
441+ isAlive ( self ) &&
442+ feature &&
443+ self . featureIdUnderMouse === featureId
444+ ) {
445+ self . setFeatureUnderMouse ( new SimpleFeature ( feature ) )
446+ }
447+ } catch ( e ) {
448+ // Silently ignore errors for mouseover - don't spam console
449+ }
450+ } ,
451+ { delay : 50 , name : 'LinearFeatureDisplayMouseoverReaction' } ,
452+ ) ,
453+ )
454+ } ,
455+ } ) )
396456 . postProcessSnapshot ( snap => {
397457 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
398458 if ( ! snap ) {
0 commit comments