Skip to content

Commit

Permalink
Implement Tooltip
Browse files Browse the repository at this point in the history
Signed-off-by: maria-ericsson <maria.chowdhury@ericsson.com>
  • Loading branch information
maria-ericsson committed Nov 12, 2020
1 parent 68a1b68 commit a5faeb5
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 72 deletions.
120 changes: 59 additions & 61 deletions viewer-prototype/src/browser/style/output-components-style.css
Original file line number Diff line number Diff line change
@@ -1,96 +1,94 @@
/* Output component styling */
/* Main container*/
.output-container {
display: flex;
color: var(--theia-ui-font-color0)
display: flex;
color: var(--theia-ui-font-color0)
}

.widget-handle {
background-color: var(--theia-layout-color4);
display: grid;
grid-template-rows: 25px 1fr;
background-color: var(--theia-layout-color4);
display: grid;
grid-template-rows: 25px 1fr;
}
.title-bar-label {
text-align: center;
writing-mode: vertical-rl;
height: 50%;
min-height: 150px;
transform: rotate(180deg);
user-select: none;
align-self: center;
justify-self: center;
text-align: center;
writing-mode: vertical-rl;
height: 50%;
min-height: 150px;
transform: rotate(180deg);
user-select: none;
align-self: center;
justify-self: center;
}

.remove-component-button {
background: none;
border: none;
padding: 2px 8px;
align-self: center;
justify-self: center;
color: var(--theia-ui-font-color0)
background: none;
border: none;
padding: 2px 8px;
align-self: center;
justify-self: center;
color: var(--theia-ui-font-color0)
}

.main-output-container {
display: flex;
display: flex;
}

.output-component-tree {
overflow-y: scroll;
white-space: pre-wrap;
overflow-y: scroll;
white-space: pre-wrap;
}

.output-component-chart {
align-self: center;
text-align: center;
align-self: center;
text-align: center;
}

#tooltip-box {
position:absolute;
overflow:hidden;
z-index :2;
top: 80px;
right: 20px;
background-color: rgb(247, 231, 8);
width: 250px;
height: auto;
opacity: 0.8;
font-size: 13px;
font-family: arial;
text-align: left;
color: black;
padding-inline-start: 10px;
}

#timegraph-main {
width: 100%;
display: flex;
width:100%;
overflow-y:scroll;
position:relative;
height: 300px;
z-index:1;
}

#main {
border: 1px solid;
margin: 10px 0;
overflow: hidden;
border: 1px solid;
margin: 10px 0;
overflow: hidden;
}

canvas {
display: block;
display: block;
}

.innerContainer {
width: 100%;
}

.table-tree>tbody>tr:nth-child(1)>th {
background-color: var(--theia-editor-background);
position: sticky;
top: 0;
width: 100%;
}

.table-tree th, .table-tree td {
padding: 3px 5px;
text-align: left;
border-bottom: 1px solid #333;
border-right: 1px solid #333;
white-space: nowrap;
min-width: 50px;
}

.timegraph-tree tr {
/* TODO: Fix row alignment, this number is arbitrary, it works [on my machine], but it should match line height in timeline-chart */
line-height: 18px;
position: relative;
white-space: nowrap;
top: 50%;
padding: 0 0;
#input-filter-tree {
background-color: var(--theia-input-background);
border: none;
border-bottom: 1px solid var(--theia-input-foreground);
padding: 3px;
width: 180px;
color: var(--theia-input-placeholder-foreground)
}

#input-filter-tree {
background-color: var(--theia-input-background);
border: none;
border-bottom: 1px solid var(--theia-input-foreground);
padding: 3px;
width: 180px;
color: var(--theia-input-placeholder-foreground)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { EntryTree } from './utils/filtrer-tree/entry-tree';
import { listToTree, getAllExpandedNodeIds } from './utils/filtrer-tree/utils';
import hash from '../../../common/utils/value-hash';
import ColumnHeader from './utils/filtrer-tree/column-header';
import { TooltipComponent } from './utils/tooltip-component';

type TimegraphOutputProps = AbstractOutputProps & {
addWidgetResizeHandler: (handler: () => void) => void;
Expand All @@ -30,15 +31,17 @@ type TimegraphOutputState = AbstractOutputState & {
timegraphTree: TimeGraphEntry[];
collapsedNodes: number[];
columns: ColumnHeader[];
isElementSelected: boolean;
isTooltipOpened: boolean;
};

export class TimegraphOutputComponent extends AbstractTreeOutputComponent<TimegraphOutputProps, TimegraphOutputState> {
private totalHeight = 0;
private rowController: TimeGraphRowController;
private chartLayer: TimeGraphChart;
private vscrollLayer: TimeGraphVerticalScrollbar;
private horizontalContainer: React.RefObject<HTMLDivElement>;

private toolTipObject: { [key: string]: string } = {};
private toolTipPosition: { x: number, y: number } = { x: 0, y: 0 };
private tspDataProvider: TspDataProvider;
private styleMap = new Map<string, TimeGraphRowElementStyle>();

Expand All @@ -50,9 +53,13 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
outputStatus: ResponseStatus.RUNNING,
timegraphTree: [],
collapsedNodes: [],
columns: []
columns: [],
isElementSelected: false,
isTooltipOpened: false,
};
this.onToggleCollapse = this.onToggleCollapse.bind(this);
this.closeTooltip = this.closeTooltip.bind(this);
this.openTooltip = this.openTooltip.bind(this);
this.tspDataProvider = new TspDataProvider(this.props.tspClient, this.props.traceId, this.props.outputDescriptor.id);
this.rowController = new TimeGraphRowController(this.props.style.rowHeight, this.totalHeight);
this.horizontalContainer = React.createRef();
Expand All @@ -68,13 +75,23 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
};
this.chartLayer = new TimeGraphChart('timeGraphChart', providers, this.rowController);
this.vscrollLayer = new TimeGraphVerticalScrollbar('timeGraphVerticalScrollbar', this.rowController);
this.chartLayer.registerRowElementMouseInteractions({
click: (el: TimeGraphRowElement, ev: PIXI.InteractionEvent) => {
this.setTooltipPosition(el, ev);
},
mouseover: (el: TimeGraphRowElement, ev: PIXI.InteractionEvent) => {
this.setTooltipPosition(el, ev);
},
mouseout: () => {
setTimeout(() => { this.closeTooltip(); }, 6000);
}
});

this.rowController.onVerticalOffsetChangedHandler(() => {
if (this.treeRef.current) {
this.treeRef.current.scrollTop = this.rowController.verticalOffset;
}
});

this.chartLayer.onSelectedRowElementChanged(model => {
if (model) {
const el = this.chartLayer.getElementById(model.id);
Expand All @@ -93,6 +110,32 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
this.rowController.verticalOffset = this.treeRef.current.scrollTop;
}
}
closeTooltip = (): void => {
this.setState({
isTooltipOpened: false
});
};

openTooltip(): void {
this.setState({
isElementSelected: true,
isTooltipOpened: true
});
}

setTooltipPosition(el: TimeGraphRowElement, ev: PIXI.InteractionEvent): void {
const X_MAX = document.documentElement.clientWidth * 0.5;
const Y_MAX = this.totalHeight - 100;
const TOOLTIP_OFFSET = 40;
let posx = ev.data.getLocalPosition(el.displayObject).x;
posx = Math.min(posx, X_MAX - 0.5 * TOOLTIP_OFFSET);
el.position.y = Math.min(el.position.y, Y_MAX - 1.5 * TOOLTIP_OFFSET);
this.toolTipPosition.x = (posx > 0.9 * X_MAX) ? posx - 0.5 * TOOLTIP_OFFSET : posx + 0.5 * TOOLTIP_OFFSET;
this.toolTipPosition.y = (el.position.y > 0.5 * Y_MAX) ? el.position.y - 0.5 * TOOLTIP_OFFSET : el.position.y + 0.5 * TOOLTIP_OFFSET;
this.onElementSelected(this.chartLayer.getElementById(el.id));
this.closeTooltip();
this.openTooltip();
}

async componentDidMount(): Promise<void> {
this.waitAnalysisCompletion();
Expand All @@ -109,10 +152,10 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
const columns: ColumnHeader[] = [];
if (treeResponse.model.headers && treeResponse.model.headers.length > 0) {
treeResponse.model.headers.forEach(header => {
columns.push({title: header.name, sortable: true, tooltip: header.tooltip});
columns.push({ title: header.name, sortable: true, tooltip: header.tooltip });
});
} else {
columns.push({title: 'Name', sortable: true});
columns.push({ title: 'Name', sortable: true });
}
// TODO Style should not be retreive in the "initialization" part or at least async
const styleResponse = (await this.props.tspClient.fetchStyles(this.props.traceId, this.props.outputDescriptor.id, QueryHelper.query())).getModel();
Expand Down Expand Up @@ -157,8 +200,11 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
renderChart(): React.ReactNode {
return <React.Fragment>
{this.state.outputStatus === ResponseStatus.COMPLETED ?
<div id='timegraph-main' className='ps__child--consume' onWheel={ev => { ev.preventDefault(); ev.stopPropagation(); }} style={{ height: this.props.style.height }} >
<div id='timegraph-main' className='ps__child--consume' onMouseLeave={_ev => this.closeTooltip()}
onWheel={ev => { ev.preventDefault(); ev.stopPropagation(); }} style={{ height: this.props.style.height }}>
{this.renderTimeGraphContent()}
{this.state.isElementSelected && this.state.isTooltipOpened &&
<TooltipComponent tooltip={this.toolTipObject} position={this.toolTipPosition}></TooltipComponent>}
</div> :
'Analysis running...'}
</React.Fragment>;
Expand Down Expand Up @@ -209,8 +255,7 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
layer={[this.vscrollLayer]}
></ReactTimeGraphContainer>;
}

private async onElementSelected(element: TimeGraphRowElement | undefined) {
async getToolTipObject(element: TimeGraphRowElement | undefined): Promise<{ [key: string]: string }> {
if (element && this.props.viewRange) {
const elementRange = element.model.range;
const offset = this.props.viewRange.getOffset();
Expand All @@ -225,11 +270,16 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
...responseModel.model,
'Row': element.row.model.name
};
SignalManager.getInstance().fireTooltipSignal(tooltipObject);
this.toolTipObject = tooltipObject;
this.forceUpdate();
return this.toolTipObject;
}
}
return {};
}
async onElementSelected(element: TimeGraphRowElement | undefined): Promise<void> {
SignalManager.getInstance().fireTooltipSignal(await this.getToolTipObject(element));
}

private async fetchTimegraphData(range: TimelineChart.TimeGraphRange, resolution: number) {
const treeNodes = listToTree(this.state.timegraphTree, this.state.columns);
const orderedTreeIds = getAllExpandedNodeIds(treeNodes, this.state.collapsedNodes);
Expand Down Expand Up @@ -359,3 +409,4 @@ export class TimegraphOutputComponent extends AbstractTreeOutputComponent<Timegr
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from 'react';
import { Component } from 'react';

interface TooltipProps {
tooltip: { [key: string]: string };
position: { x: number, y: number };
}

interface TooltipStates {
style: { top: string, left: string };

}

export class TooltipComponent extends Component<TooltipProps, TooltipStates> {
constructor(props: TooltipProps) {
super(props);
this.state = { style: { top: props.position.y + 'px', left: props.position.x + 'px' } };
}

tooltipRef: React.RefObject<HTMLDivElement> = React.createRef();

renderTooltip(): React.ReactNode {
const tooltipArray: React.ReactNode[] = [];
if (this.props.tooltip) {
const keys = Object.keys(this.props.tooltip);
keys.forEach(key => {
tooltipArray.push(<p key={key}>{key + ': ' + this.props.tooltip[key]}</p>);
});
}
else {
console.log('Tooltip null');
}
return <React.Fragment>
{tooltipArray.map(element => element)}
</React.Fragment>;
}

render(): React.ReactNode {
return <div id='tooltip-box' ref={this.tooltipRef} style={this.state.style}>
{this.renderTooltip()}
</div>;
}
}

0 comments on commit a5faeb5

Please sign in to comment.