From f9a420a32e6b8f72693cf3bec461b1b8b32efe08 Mon Sep 17 00:00:00 2001 From: Shashank Budhanuru Ramaraju Date: Mon, 7 Oct 2024 11:27:41 +0100 Subject: [PATCH 1/4] Hightlight mRNA on intron hover and tooltip fix --- .../LinearApolloDisplay/glyphs/GeneGlyph.ts | 101 +++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts index 32ed3777f..e2210c261 100644 --- a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +++ b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts @@ -5,6 +5,7 @@ import { alpha } from '@mui/material' import { LinearApolloDisplay } from '../stateModel' import { isMousePositionWithFeatureAndGlyph, + LinearApolloDisplayMouseEvents, MousePosition, MousePositionWithFeatureAndGlyph, } from '../stateModel/mouseEvents' @@ -291,9 +292,41 @@ function getFeatureFromLayout( ): AnnotationFeature | undefined { const featureInThisRow: AnnotationFeature[] = featuresForRow(feature)[row] for (const f of featureInThisRow) { + let featureObj if (bp >= f.min && bp <= f.max && f.parent) { - return f + featureObj = f } + if (!featureObj) { + continue + } + if ( + featureObj.type === 'CDS' && + featureObj.parent && + featureObj.parent.type === 'mRNA' + ) { + const { max, min } = featureObj + const { cdsLocations } = featureObj.parent + for (const cdsLoc of cdsLocations) { + const firstLoc = cdsLoc.at(0) + const lastLoc = cdsLoc.at(-1) + + if ( + firstLoc && + firstLoc.min === min && + lastLoc && + lastLoc.max === max + ) { + for (const loc of cdsLoc) { + if (bp >= loc.min && bp <= loc.max) { + return featureObj + } + } + break + } + } + return featureObj.parent + } + return featureObj } return feature } @@ -499,9 +532,73 @@ function getDraggableFeatureInfo( return } +function drawTooltip( + display: LinearApolloDisplayMouseEvents, + context: CanvasRenderingContext2D, +): void { + const { apolloHover, apolloRowHeight, lgv, theme } = display + if (!apolloHover) { + return + } + const { feature, topLevelFeature } = apolloHover + const position = display.getFeatureLayoutPosition(feature) + if (!position) { + return + } + const { layoutIndex, layoutRow } = position + const rowIdx = getRowForFeature(topLevelFeature, feature) + const { bpPerPx, displayedRegions, offsetPx } = lgv + const displayedRegion = displayedRegions[layoutIndex] + const { refName, reversed } = displayedRegion + + let location = 'Loc: ' + + const { length, max, min } = feature + location += `${min + 1}–${max}` + + let startPx = + (lgv.bpToPx({ + refName, + coord: reversed ? max : min, + regionNumber: layoutIndex, + })?.offsetPx ?? 0) - offsetPx + const top = (layoutRow + (rowIdx ?? 0)) * apolloRowHeight + const widthPx = length / bpPerPx + + const featureType = `Type: ${feature.type}` + const { attributes } = feature + const featureName = attributes.get('gff_name')?.find((name) => name !== '') + const textWidth = [ + context.measureText(featureType).width, + context.measureText(location).width, + ] + if (featureName) { + textWidth.push(context.measureText(`Name: ${featureName}`).width) + } + const maxWidth = Math.max(...textWidth) + + startPx = startPx + widthPx + 5 + context.fillStyle = alpha(theme?.palette.text.primary ?? 'rgb(1, 1, 1)', 0.7) + context.fillRect(startPx, top, maxWidth + 4, textWidth.length === 3 ? 45 : 35) + context.beginPath() + context.moveTo(startPx, top) + context.lineTo(startPx - 5, top + 5) + context.lineTo(startPx, top + 10) + context.fill() + context.fillStyle = theme?.palette.background.default ?? 'rgba(255, 255, 255)' + let textTop = top + 12 + context.fillText(featureType, startPx + 2, textTop) + if (featureName) { + textTop = textTop + 12 + context.fillText(`Name: ${featureName}`, startPx + 2, textTop) + } + textTop = textTop + 12 + context.fillText(location, startPx + 2, textTop) +} + // False positive here, none of these functions use "this" /* eslint-disable @typescript-eslint/unbound-method */ -const { drawTooltip, getContextMenuItems, onMouseLeave } = boxGlyph +const { getContextMenuItems, onMouseLeave } = boxGlyph /* eslint-enable @typescript-eslint/unbound-method */ export const geneGlyph: Glyph = { From 76dec0b64ce974d385b84b06254d4fc3da7b5fec Mon Sep 17 00:00:00 2001 From: Shashank Budhanuru Ramaraju Date: Tue, 8 Oct 2024 15:27:36 +0100 Subject: [PATCH 2/4] refactor --- .../LinearApolloDisplay/glyphs/GeneGlyph.ts | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts index e2210c261..7f5634865 100644 --- a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +++ b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts @@ -304,28 +304,19 @@ function getFeatureFromLayout( featureObj.parent && featureObj.parent.type === 'mRNA' ) { - const { max, min } = featureObj const { cdsLocations } = featureObj.parent for (const cdsLoc of cdsLocations) { - const firstLoc = cdsLoc.at(0) - const lastLoc = cdsLoc.at(-1) - - if ( - firstLoc && - firstLoc.min === min && - lastLoc && - lastLoc.max === max - ) { - for (const loc of cdsLoc) { - if (bp >= loc.min && bp <= loc.max) { - return featureObj - } + for (const loc of cdsLoc) { + if (bp >= loc.min && bp <= loc.max) { + return featureObj } - break } } + + // If mouse position is in the intron region, return the mRNA return featureObj.parent } + // If mouse position is in a feature that is not a CDS, return the feature return featureObj } return feature From 1ec2b0aca453184c8440a439274ccff5d2356af4 Mon Sep 17 00:00:00 2001 From: Garrett Stevens Date: Mon, 4 Nov 2024 20:56:19 +0000 Subject: [PATCH 3/4] Fix BoxGlyph drawTooltip to work with GeneGlyph --- .../LinearApolloDisplay/glyphs/BoxGlyph.ts | 4 +- .../LinearApolloDisplay/glyphs/GeneGlyph.ts | 66 +------------------ 2 files changed, 3 insertions(+), 67 deletions(-) diff --git a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/BoxGlyph.ts b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/BoxGlyph.ts index 5ddd8bafc..df190ad8b 100644 --- a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +++ b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/BoxGlyph.ts @@ -175,7 +175,7 @@ function drawTooltip( if (!position) { return } - const { layoutIndex, layoutRow } = position + const { featureRow, layoutIndex, layoutRow } = position const { bpPerPx, displayedRegions, offsetPx } = lgv const displayedRegion = displayedRegions[layoutIndex] const { refName, reversed } = displayedRegion @@ -191,7 +191,7 @@ function drawTooltip( coord: reversed ? max : min, regionNumber: layoutIndex, })?.offsetPx ?? 0) - offsetPx - const top = layoutRow * apolloRowHeight + const top = (layoutRow + featureRow) * apolloRowHeight const widthPx = length / bpPerPx const featureType = `Type: ${feature.type}` diff --git a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts index 7f5634865..6077aa0e4 100644 --- a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +++ b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts @@ -523,73 +523,9 @@ function getDraggableFeatureInfo( return } -function drawTooltip( - display: LinearApolloDisplayMouseEvents, - context: CanvasRenderingContext2D, -): void { - const { apolloHover, apolloRowHeight, lgv, theme } = display - if (!apolloHover) { - return - } - const { feature, topLevelFeature } = apolloHover - const position = display.getFeatureLayoutPosition(feature) - if (!position) { - return - } - const { layoutIndex, layoutRow } = position - const rowIdx = getRowForFeature(topLevelFeature, feature) - const { bpPerPx, displayedRegions, offsetPx } = lgv - const displayedRegion = displayedRegions[layoutIndex] - const { refName, reversed } = displayedRegion - - let location = 'Loc: ' - - const { length, max, min } = feature - location += `${min + 1}–${max}` - - let startPx = - (lgv.bpToPx({ - refName, - coord: reversed ? max : min, - regionNumber: layoutIndex, - })?.offsetPx ?? 0) - offsetPx - const top = (layoutRow + (rowIdx ?? 0)) * apolloRowHeight - const widthPx = length / bpPerPx - - const featureType = `Type: ${feature.type}` - const { attributes } = feature - const featureName = attributes.get('gff_name')?.find((name) => name !== '') - const textWidth = [ - context.measureText(featureType).width, - context.measureText(location).width, - ] - if (featureName) { - textWidth.push(context.measureText(`Name: ${featureName}`).width) - } - const maxWidth = Math.max(...textWidth) - - startPx = startPx + widthPx + 5 - context.fillStyle = alpha(theme?.palette.text.primary ?? 'rgb(1, 1, 1)', 0.7) - context.fillRect(startPx, top, maxWidth + 4, textWidth.length === 3 ? 45 : 35) - context.beginPath() - context.moveTo(startPx, top) - context.lineTo(startPx - 5, top + 5) - context.lineTo(startPx, top + 10) - context.fill() - context.fillStyle = theme?.palette.background.default ?? 'rgba(255, 255, 255)' - let textTop = top + 12 - context.fillText(featureType, startPx + 2, textTop) - if (featureName) { - textTop = textTop + 12 - context.fillText(`Name: ${featureName}`, startPx + 2, textTop) - } - textTop = textTop + 12 - context.fillText(location, startPx + 2, textTop) -} - // False positive here, none of these functions use "this" /* eslint-disable @typescript-eslint/unbound-method */ -const { getContextMenuItems, onMouseLeave } = boxGlyph +const { drawTooltip, getContextMenuItems, onMouseLeave } = boxGlyph /* eslint-enable @typescript-eslint/unbound-method */ export const geneGlyph: Glyph = { From 47db598f8ee06a6ac9391a159c00e1991c910290 Mon Sep 17 00:00:00 2001 From: Garrett Stevens Date: Mon, 4 Nov 2024 21:00:24 +0000 Subject: [PATCH 4/4] Fix lint --- .../src/LinearApolloDisplay/glyphs/GeneGlyph.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts index 6077aa0e4..25b34b32a 100644 --- a/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +++ b/packages/jbrowse-plugin-apollo/src/LinearApolloDisplay/glyphs/GeneGlyph.ts @@ -5,7 +5,6 @@ import { alpha } from '@mui/material' import { LinearApolloDisplay } from '../stateModel' import { isMousePositionWithFeatureAndGlyph, - LinearApolloDisplayMouseEvents, MousePosition, MousePositionWithFeatureAndGlyph, } from '../stateModel/mouseEvents'