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

Keep tabs mounted #544

Merged
merged 6 commits into from
Jan 13, 2025
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
2 changes: 1 addition & 1 deletion screen2.0/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@
"typescript-eslint": "^8.18.0"
},
"packageManager": "[email protected]"
}
}
31 changes: 24 additions & 7 deletions screen2.0/src/app/_barPlot/BarPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ const VerticalBarPlot = <T,>({
onBarClicked,
TooltipContents
}: BarPlotProps<T>) => {
const [spaceForLabel, setSpaceForLabel] = useState(200) //this needs to be initialized with zero. Will break useEffect if changed
const [spaceForLabel, setSpaceForLabel] = useState(200)
const [labelSpaceDecided, setLabelSpaceDecided] = useState(false)
// Unique ID needed to not mix up getElementByID calls if multiple charts are in DOM
const [uniqueID] = useState(topAxisLabel + String(Math.random()))
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = useTooltip<BarData<T>>({});
const requestRef = useRef<number | null>(null);
const tooltipDataRef = useRef<{ top: number; left: number; data: BarData<T> } | null>(null);
Expand All @@ -48,6 +50,8 @@ const VerticalBarPlot = <T,>({
const Portal = VisxPortal as unknown as React.FC<PortalProps>;
const TooltipWithBounds = VisxTooltipWithBounds as unknown as React.FC<TooltipWithBoundsProps>;

const outerSvgRef = useRef<SVGSVGElement>(null)

const handleMouseMove = useCallback((event: React.MouseEvent, barData: BarData<T>) => {
tooltipDataRef.current = {
top: event.pageY,
Expand Down Expand Up @@ -91,19 +95,21 @@ const VerticalBarPlot = <T,>({
range: [0, Math.max(width - spaceForCategory - spaceForLabel, 0)],
}), [data, spaceForLabel, width])


//use prop ref or fallback if ref not passed
const containerWidth = SVGref ? SVGref.current?.clientWidth : outerSvgRef.current?.clientWidth

//This feels really dumb but I couldn't figure out a better way to have the labels not overflow sometimes - JF 11/8/24
//Whenever xScale is adjusted, it checks to see if any of the labels overflow the container, and if so
//it sets the spaceForLabel to be the amount overflowed.
useEffect(() => {
const containerWidth = document.getElementById('outerSVG')?.clientWidth
if (!containerWidth) { return }

let maxOverflow = 0
let minUnderflow: number = null
// let maxOverflowingPoint: [BarData<T>, { textWidth: number, barWidth: number, totalWidth: number, overflow: number }]

data.forEach((d, i) => {
const textElement = document.getElementById(`label-${i}`) as unknown as SVGSVGElement;
const textElement = document.getElementById(`label-${i}-${uniqueID}`) as unknown as SVGSVGElement;

if (textElement) {
const textWidth = textElement.getBBox().width;
Expand Down Expand Up @@ -137,14 +143,25 @@ const VerticalBarPlot = <T,>({
setLabelSpaceDecided(true)
}

}, [data, xScale]);
}, [data, xScale, spaceForLabel, labelSpaceDecided, SVGref, containerWidth, topAxisLabel, uniqueID]);

return (
<div ref={parentRef} style={{position: "relative"}}>
{data.length === 0 ?
<p>No Data To Display</p>
:
<svg ref={SVGref} width={width} height={totalHeight} opacity={(labelSpaceDecided && ParentWidth > 0) ? 1 : 0.3} id={'outerSVG'}>
<svg
//define fallback ref if not passed through props
ref={(node) => {
if (SVGref) {
SVGref.current = node;
}
outerSvgRef.current = node;
}}
width={width}
height={totalHeight}
opacity={(labelSpaceDecided && ParentWidth > 0) ? 1 : 0.3}
>
<Group left={spaceForCategory} top={spaceForTopAxis} >
{/* Top Axis with Label */}
<AxisTop scale={xScale} top={0} label={topAxisLabel} labelProps={{ dy: -5, fontSize: 16, fontFamily: fontFamily }} numTicks={width < 600 ? 4 : undefined} />
Expand Down Expand Up @@ -185,7 +202,7 @@ const VerticalBarPlot = <T,>({
/>
{/* Value label next to the bar */}
<Text
id={`label-${i}`}
id={`label-${i}-${uniqueID}`}
x={barX + barWidth + gapBetweenTextAndBar} // Position label slightly after the end of the bar
y={(barY ?? 0) + barHeight / 2}
dy=".35em" // Vertically align to the middle of the bar
Expand Down
16 changes: 7 additions & 9 deletions screen2.0/src/app/applets/gene-expression/geneexpression.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -601,15 +601,13 @@ export function GeneExpression(props: {
</Grid>
:
dataExperiments ?
// <Grid size={12}>
<VerticalBarPlot
data={plotData}
topAxisLabel={(gene + " Gene Expression in " + assembly + ' - ') + (scale === "linearTPM" ? "Linear TPM" : "Log10(TPM + 1)")}
SVGref={plotRef}
onBarClicked={(x) => window.open("https://www.encodeproject.org/experiments/" + x.metadata.accession, "_blank", "noopener,noreferrer")}
TooltipContents={(bar) => <PlotTooltip {...bar} />}
/>
// </Grid>
<VerticalBarPlot
data={plotData}
topAxisLabel={(gene + " Gene Expression in " + assembly + ' - ') + (scale === "linearTPM" ? "Linear TPM" : "Log10(TPM + 1)")}
SVGref={plotRef}
onBarClicked={(x) => window.open("https://www.encodeproject.org/experiments/" + x.metadata.accession, "_blank", "noopener,noreferrer")}
TooltipContents={(bar) => <PlotTooltip {...bar} />}
/>
:
<Typography variant="h5">
Please Select a Gene
Expand Down
49 changes: 23 additions & 26 deletions screen2.0/src/app/search/_newgbview/browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,39 +75,36 @@ export const Browser = ({ cCREClick, state, dispatch, coordinates, gene, biosamp
const bedMouseOut = () => {
dispatch({ type: BrowserActionType.REMOVE_LAST_HIGHLIGHT })
}
const bedClick = (item: Rect) => {
const bedClick = useMemo(() => (item: Rect) => {
dispatch({ type: BrowserActionType.REMOVE_LAST_HIGHLIGHT })
const { left, right } = linearScale(state.domain, item.start, item.end)
const ccre = { start: left, end: right, color: item.color, name: item.name, score: item.score, chromosome: state.domain.chromosome }
cCREClick(ccre)
}
const initialLoad = useRef(true)
}, [state.domain, state.highlights, cCREClick])

useEffect(() => {
if (initialLoad.current) {
const bigbeds = state.tracks.filter(track => track.trackType === TrackType.BIGBED)
bigbeds.forEach(track => {
dispatch({
type: BrowserActionType.UPDATE_TRACK, id: track.id, track: {
...track,
onMouseOut: bedMouseOut,
onMouseOver: bedMouseOver,
onClick: bedClick,
tooltipContent: (item: Rect) => CCRETooltip({ biosample, assembly: coordinates.assembly, name: item.name })
}
})
const bigbeds = state.tracks.filter(track => track.trackType === TrackType.BIGBED)
bigbeds.forEach(track => {
dispatch({
type: BrowserActionType.UPDATE_TRACK, id: track.id, track: {
...track,
onMouseOut: bedMouseOut,
onMouseOver: bedMouseOver,
onClick: bedClick,
tooltipContent: (item: Rect) => CCRETooltip({ biosample, assembly: coordinates.assembly, name: item.name })
}
})
const transcripts = state.tracks.filter(track => track.trackType === TrackType.TRANSCRIPT)
transcripts.forEach(track => {
dispatch({
type: BrowserActionType.UPDATE_PROPS, id: track.id,
props: {
geneName: gene
}
})
})
const transcripts = state.tracks.filter(track => track.trackType === TrackType.TRANSCRIPT)
transcripts.forEach(track => {
dispatch({
type: BrowserActionType.UPDATE_PROPS, id: track.id,
props: {
geneName: gene
}
})
initialLoad.current = false
}
}, [])
})
}, [cCREClick])

const [loadBiosample, { loading: bloading, data: bdata }] = useLazyQuery(BIOSAMPLE_QUERY, {
fetchPolicy: "cache-and-network",
Expand Down
Loading
Loading