import { bpSpanPx } from '@jbrowse/core/util' ; import SimpleFeature from '@jbrowse/core/util/simpleFeature' ; import { Region } from '@jbrowse/core/util/types' ; import { observer } from 'mobx-react' ; import React from 'react' ; type LayoutRecord = [ number , number , number , number ] ; interface SvgOverlayProps { region : Region ; displayModel : { getFeatureByID : ( arg0 : string , arg1 : string ) => LayoutRecord ; selectedFeatureId ? : string ; featureIdUnderMouse ? : string ; contextMenuFeature ? : SimpleFeature ; } ; bpPerPx : number ; blockKey : string ; movedDuringLastMouseDown : boolean ; onFeatureMouseDown ? ( event , featureId ) : { } ; onFeatureMouseEnter ? ( event , featureId ) : { } ; onFeatureMouseOut ? ( event , featureId ) : { } ; onFeatureMouseOver ? ( event , featureId ) : { } ; onFeatureMouseUp ? ( event , featureId ) : { } ; onFeatureMouseLeave ? ( event , featureId ) : { } ; onFeatureMouseMove ? ( event , featureId ) : { } ; onFeatureClick ? ( event , featureId ) : { } ; onFeatureContextMenu ? ( event , featureId ) : { } ; } interface OverlayRectProps extends React . SVGProps < SVGRectElement > { rect ? : LayoutRecord ; region : Region ; bpPerPx : number ; } function OverlayRect ( { rect , region , bpPerPx , ... rectProps } ) { if ( ! rect ) { return null ; } const [ leftBp , topPx , rightBp , bottomPx ] = rect ; const [ leftPx , rightPx ] = bpSpanPx ( leftBp , rightBp , region , bpPerPx ) ; const rectTop = Math . round ( topPx ) ; const screenWidth = ( region . end - region . start ) / bpPerPx ; const rectHeight = Math . round ( bottomPx - topPx ) ; const width = rightPx - leftPx ; if ( leftPx + width < 0 ) { return null ; } const leftWithinBlock = Math . max ( leftPx , 0 ) ; const diff = leftWithinBlock - leftPx ; const widthWithinBlock = Math . max ( 1 , Math . min ( width - diff , screenWidth ) ) ; return ( < rect x = { leftWithinBlock - 2 } y = { rectTop - 2 } width = { widthWithinBlock + 4 } height = { rectHeight + 4 } { ... rectProps } />); } function SvgOverlay ( { displayModel , blockKey , region , bpPerPx , movedDuringLastMouseDown , ... handlers } ) { const { selectedFeatureId , featureIdUnderMouse , contextMenuFeature } = displayModel ; const mouseoverFeatureId = featureIdUnderMouse || contextMenuFeature ?. id ( ) ; function onFeatureMouseDown ( event ) { const { onFeatureMouseDown : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } return handler ( event , mouseoverFeatureId ) ; } function onFeatureMouseEnter ( event ) { const { onFeatureMouseEnter : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } return handler ( event , mouseoverFeatureId ) ; } function onFeatureMouseOut ( event ) { const { onFeatureMouseOut : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } return handler ( event , mouseoverFeatureId ) ; } function onFeatureMouseOver ( event ) { const { onFeatureMouseOver : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } return handler ( event , mouseoverFeatureId ) ; } function onFeatureMouseUp ( event ) { const { onFeatureMouseUp : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } return handler ( event , mouseoverFeatureId ) ; } function onFeatureMouseLeave ( event ) { const { onFeatureMouseLeave : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } return handler ( event , mouseoverFeatureId ) ; } function onFeatureMouseMove ( event ) { const { onFeatureMouseMove : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } return handler ( event , mouseoverFeatureId ) ; } function onFeatureClick ( event ) { if ( movedDuringLastMouseDown ) { return undefined ; } const { onFeatureClick : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } event . stopPropagation ( ) ; return handler ( event , mouseoverFeatureId ) ; } function onFeatureContextMenu ( event ) { const { onFeatureContextMenu : handler } = handlers ; if ( ! ( handler && mouseoverFeatureId ) ) { return undefined ; } return handler ( event , mouseoverFeatureId ) ; } return ( < > { mouseoverFeatureId ? ( < OverlayRect rect = { displayModel . getFeatureByID ?. ( blockKey , mouseoverFeatureId ) } region = { region } bpPerPx = { bpPerPx } fill = "#000" fillOpacity = "0.2" onMouseDown = { onFeatureMouseDown } onMouseEnter = { onFeatureMouseEnter } onMouseOut = { onFeatureMouseOut } onMouseOver = { onFeatureMouseOver } onMouseUp = { onFeatureMouseUp } onMouseLeave = { onFeatureMouseLeave } onMouseMove = { onFeatureMouseMove } onClick = { onFeatureClick } onContextMenu = { onFeatureContextMenu } onFocus = { onFeatureMouseOver } onBlur = { onFeatureMouseOut } data - testid = { mouseoverFeatureId } / > ) : null } { selectedFeatureId ? ( < OverlayRect rect = { displayModel . getFeatureByID ?. ( blockKey , selectedFeatureId ) } region = { region } bpPerPx = { bpPerPx } stroke = "#00b8ff" fill = "none" / > ) : null } < />); } export default observer ( SvgOverlay ) ;