From 94aff21e62074c8a03c89b8c8c2e618aa328e44a Mon Sep 17 00:00:00 2001 From: lismana Date: Tue, 13 Oct 2020 14:54:16 -0400 Subject: [PATCH] Allow custom chart renderer to render portal on a target --- .../src/CustomTrack.tsx | 13 +- .../src/CustomTrackHeader.tsx | 12 +- src/pages/patientView/timeline2/VAFChart.tsx | 160 ++++++++++-------- .../patientView/timeline2/VAFChartWrapper.tsx | 35 ++-- 4 files changed, 131 insertions(+), 89 deletions(-) diff --git a/packages/cbioportal-clinical-timeline/src/CustomTrack.tsx b/packages/cbioportal-clinical-timeline/src/CustomTrack.tsx index b0f00eb1b29..6bcd4fe068b 100644 --- a/packages/cbioportal-clinical-timeline/src/CustomTrack.tsx +++ b/packages/cbioportal-clinical-timeline/src/CustomTrack.tsx @@ -5,10 +5,14 @@ import classNames from 'classnames'; export type CustomTrackSpecification = { renderHeader: (store: TimelineStore) => any; // any = react renderable, string or element or null or etc. - renderTrack: (store: TimelineStore) => React.ReactElement; + renderTrack: ( + store: TimelineStore, + headerTargetEl: any + ) => React.ReactElement; height: (store: TimelineStore) => number; labelForExport: string; disableHover?: boolean; + uid: string; }; export interface ICustomTrackProps { @@ -44,7 +48,12 @@ const CustomTrack: React.FunctionComponent = function({ height={specification.height(store)} width={width} /> - {specification.renderTrack(store)} + {specification.renderTrack( + store, + document.getElementsByClassName( + `tl-track-uid-${specification.uid}` + )[0] + )} = func }: ICustomTrackHeaderProps) { return (
- {specification.renderHeader(store)} + {specification.renderHeader && specification.renderHeader(store)}
); }; diff --git a/src/pages/patientView/timeline2/VAFChart.tsx b/src/pages/patientView/timeline2/VAFChart.tsx index 8bc9505a696..dc6776facc2 100644 --- a/src/pages/patientView/timeline2/VAFChart.tsx +++ b/src/pages/patientView/timeline2/VAFChart.tsx @@ -49,6 +49,7 @@ interface IVAFChartProps { mutationProfileId: string; coverageInformation: CoverageInformation; sampleManager: SampleManager; + headerEl?: HTMLDivElement; } const HIGHLIGHT_LINE_STROKE_WIDTH = 6; @@ -632,34 +633,36 @@ export default class VAFChart extends React.Component { renderTrack: () => this.sampeIconsGroupByTrack(sampleIds), height: () => this.groupIndexToTrackHeight[index], labelForExport: this.clinicalValuesForGrouping[index], + uid: `groupbytracks-${index}`, }); }); this.props.wrapperStore.groupByTracks = tracks; } - yAxisHeaderReaction = autorun(() => { - this.renderHeader(this.ticks); - }); + // yAxisHeaderReaction = autorun(() => { + // this.renderHeader(this.ticks); + // }); groupByTracksReaction = autorun(() => { this.setGroupByTracks(this.sampleGroups); }); destroy() { - this.yAxisHeaderReaction(); + // this.yAxisHeaderReaction(); this.groupByTracksReaction(); } @action renderHeader(ticks: { label: string; value: number; offset: number }[]) { - this.props.wrapperStore.vafPlotHeader = (store: TimelineStore) => ( -
- -
- ); + return null; + // this.props.wrapperStore.vafPlotHeader = (store: TimelineStore) => ( + //
+ // + //
+ // ); } @computed get groupColor() { @@ -672,44 +675,72 @@ export default class VAFChart extends React.Component { render() { return ( - - {this.renderData.lineData.map( - (data: IPoint[], index: number) => { - return data.map((d: IPoint, i: number) => { - let x1 = this.xPosition[d.sampleId], - x2; - let y1 = this.yPosition[d.y], - y2; - - const nextPoint: IPoint = data[i + 1]; - if (nextPoint) { - x2 = this.xPosition[nextPoint.sampleId]; - y2 = this.yPosition[nextPoint.y]; - } - - let tooltipDatum: { - mutationStatus: MutationStatus; - sampleId: string; - vaf: number; - } = { - mutationStatus: d.mutationStatus, - sampleId: d.sampleId, - vaf: d.y, - }; - - const color = this.groupColor(d.sampleId); - - return ( - - {x2 && y2 && ( - + {this.props.headerEl && ( + +
+ +
+ + )} + + {this.renderData.lineData.map( + (data: IPoint[], index: number) => { + return data.map((d: IPoint, i: number) => { + let x1 = this.xPosition[d.sampleId], + x2; + let y1 = this.yPosition[d.y], + y2; + + const nextPoint: IPoint = data[i + 1]; + if (nextPoint) { + x2 = this.xPosition[nextPoint.sampleId]; + y2 = this.yPosition[nextPoint.y]; + } + + let tooltipDatum: { + mutationStatus: MutationStatus; + sampleId: string; + vaf: number; + } = { + mutationStatus: d.mutationStatus, + sampleId: d.sampleId, + vaf: d.y, + }; + + const color = this.groupColor(d.sampleId); + + return ( + + {x2 && y2 && ( + + )} + { this.props.wrapperStore } /> - )} - - - ); - }); - } - )} + + ); + }); + } + )} - {!this.groupingByIsSelected && this.sampleIcons()} - {this.getHighlights} - {this.getTooltipComponent} - + {!this.groupingByIsSelected && this.sampleIcons()} + {this.getHighlights} + {this.getTooltipComponent} + + ); } diff --git a/src/pages/patientView/timeline2/VAFChartWrapper.tsx b/src/pages/patientView/timeline2/VAFChartWrapper.tsx index f97b482a003..51fe9bc9665 100644 --- a/src/pages/patientView/timeline2/VAFChartWrapper.tsx +++ b/src/pages/patientView/timeline2/VAFChartWrapper.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { RefObject, useEffect, useState } from 'react'; import { observer } from 'mobx-react-lite'; import { CoverageInformation } from '../../resultsView/ResultsViewPageStoreUtils'; import { ClinicalEvent, Sample } from 'cbioportal-ts-api-client'; @@ -24,6 +24,7 @@ import { } from 'pages/patientView/timeline2/helpers'; import { CustomTrackSpecification } from 'cbioportal-clinical-timeline/dist/CustomTrack'; import { downloadZippedTracks } from 'pages/patientView/timeline2/timelineDataUtils'; +import { Portal } from 'react-overlays/lib'; export interface ISampleMetaDeta { color: { [sampleId: string]: string }; @@ -102,24 +103,30 @@ const VAFChartWrapper: React.FunctionComponent = observer const groupByTracks = wrapperStore.groupByTracks; const vafPlotTrack = { - renderHeader: wrapperStore.vafPlotHeader, - renderTrack: (store: TimelineStore) => ( - - ), + //renderHeader: wrapperStore.vafPlotHeader, + renderTrack: (store: TimelineStore, headerEl?: HTMLDivElement) => { + return ( + <> + + + ); + }, disableHover: true, height: (store: TimelineStore) => { return wrapperStore.vafChartHeight; }, labelForExport: 'VAF', + uid: 'vafplot', } as CustomTrackSpecification; let customTracks = [vafPlotTrack].concat(wrapperStore.groupByTracks);