Skip to content

Commit

Permalink
Feature/parallel chart tooltip (#1186)
Browse files Browse the repository at this point in the history
* first draft of the tooltip

Signed-off-by: huongg <huongg1409@gmail.com>

* create share tooltip for chart

Signed-off-by: huongg <huongg1409@gmail.com>

* set timeout to show tooltip

Signed-off-by: huongg <huongg1409@gmail.com>

* remove LinePath component as it no longer needs

Signed-off-by: huongg <huongg1409@gmail.com>

* remove unused styling

Signed-off-by: huongg <huongg1409@gmail.com>

* styling sorting

Signed-off-by: huongg <huongg1409@gmail.com>

* set default props for tooltip

Signed-off-by: huongg <huongg1409@gmail.com>

* use css to fadein tooltip instead timeout

Signed-off-by: huongg <huongg1409@gmail.com>

* not to reset opacity after the animation

Signed-off-by: huongg <huongg1409@gmail.com>

* sorting

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

* sorting props

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

* set tooltip to default value on mouseout

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

* declare variable on the top

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

* declare variable on the top

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

* pull the latest changes

Signed-off-by: huongg <huongg1409@gmail.com>

* formate date

Signed-off-by: huongg <huongg1409@gmail.com>

* use sidebarWidth from the config

Signed-off-by: huongg <huongg1409@gmail.com>

* update label name

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

* update label name

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

* update label name

Co-authored-by: Tynan DeBold <thdebold@gmail.com>

Signed-off-by: huongg <huongg1409@gmail.com>
Co-authored-by: Tynan DeBold <thdebold@gmail.com>
  • Loading branch information
Huongg and tynandebold authored Nov 30, 2022
1 parent 2c9f5ef commit b39299a
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 54 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import classnames from 'classnames';
import * as d3 from 'd3';
import { HoverStateContext } from '../utils/hover-state-context';
import { v4 as uuidv4 } from 'uuid';
import { MetricsChartsTooltip, tooltipDefaultProps } from '../tooltip/tooltip';
import { sidebarWidth } from '../../../config';
import { formatTimestamp } from '../../../utils/date-utils';

import './parallel-coordinates.css';

Expand All @@ -12,6 +15,11 @@ const paddingLr = 80;
const axisGapBuffer = 3;
const selectedMarkerRotate = [45, 0, 0];

const tooltipMaxWidth = 300;
const tooltipLeftGap = 90;
const tooltipRightGap = 60;
const tooltipTopGap = 150;

const selectedMarkerColors = ['#00E3FF', '#3BFF95', '#FFE300'];

const yAxis = {};
Expand All @@ -21,6 +29,7 @@ export const ParallelCoordinates = ({ metricsData, selectedRuns }) => {
const [hoveredAxisG, setHoveredAxisG] = useState(null);
const [chartHeight, setChartHeight] = useState(0);
const [chartWidth, setChartWidth] = useState(0);
const [showTooltip, setShowTooltip] = useState(tooltipDefaultProps);

const { hoveredElementId, setHoveredElementId } =
useContext(HoverStateContext);
Expand Down Expand Up @@ -76,11 +85,81 @@ export const ParallelCoordinates = ({ metricsData, selectedRuns }) => {
};

const handleMouseOverMetric = (e, key) => {
const runsCount = graph.find((each) => each[0] === key)[1].length;
setHoveredAxisG(key);

const rect = e.target.getBoundingClientRect();
const y = rect.y - tooltipTopGap + rect.height / 2;
let x, direction;

if (window.innerWidth - rect.x > tooltipMaxWidth) {
x = e.clientX - sidebarWidth.open - tooltipRightGap;
direction = 'right';
} else {
x =
e.clientX - sidebarWidth.open - sidebarWidth.open / 2 - tooltipLeftGap;
direction = 'left';
}

setShowTooltip({
content: {
label1: 'Metric name',
value1: key,
label2: 'Run count',
value2: runsCount,
},
direction,
position: { x, y },
visible: true,
});
};

const handleMouseOutMetric = () => {
setHoveredAxisG(null);
setShowTooltip(tooltipDefaultProps);
};

const handleMouseOverLine = (e, key) => {
setHoveredElementId(key);

if (e) {
const y = e.clientY - tooltipTopGap;
const parsedDate = new Date(formatTimestamp(key));
let x, direction;

if (window.innerWidth - e.clientX > tooltipMaxWidth) {
x = e.clientX - sidebarWidth.open - tooltipRightGap;
direction = 'right';
} else {
x =
e.clientX -
sidebarWidth.open -
sidebarWidth.open / 2 -
tooltipLeftGap;
direction = 'left';
}

setShowTooltip({
content: {
label1: 'Run name',
value1: key,
label2: 'Date',
value2: parsedDate.toLocaleDateString('default', {
day: 'numeric',
month: 'long',
year: 'numeric',
}),
},
direction,
position: { x, y },
visible: true,
});
}
};

const handleMouseOutLine = () => {
setHoveredElementId(null);
setShowTooltip(tooltipDefaultProps);
};

useEffect(() => {
Expand All @@ -95,6 +174,13 @@ export const ParallelCoordinates = ({ metricsData, selectedRuns }) => {

return (
<div className="parallel-coordinates">
<MetricsChartsTooltip
content={showTooltip.content}
direction={showTooltip.direction}
position={showTooltip.position}
visible={showTooltip.visible}
/>

<svg
preserveAspectRatio="xMinYMin meet"
viewBox={`0 0 ${chartWidth} ${chartHeight}`}
Expand Down Expand Up @@ -139,9 +225,9 @@ export const ParallelCoordinates = ({ metricsData, selectedRuns }) => {
d={linePath(value, i)}
id={id}
key={id}
onMouseLeave={() => setHoveredElementId(null)}
onMouseLeave={handleMouseOutLine}
onMouseOver={(e) => {
setHoveredElementId(id);
handleMouseOverLine(e, id);
d3.select(e.target).raise();
}}
/>
Expand Down
35 changes: 35 additions & 0 deletions src/components/experiment-tracking/tooltip/tooltip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import classnames from 'classnames';

import './tooltip.css';

export const tooltipDefaultProps = {
content: { label1: '', value1: '', label2: '', value2: '' },
direction: 'right',
position: { x: -500, y: -500 },
visible: false,
};

export const MetricsChartsTooltip = ({
content = tooltipDefaultProps.content,
direction = tooltipDefaultProps.direction,
position = tooltipDefaultProps.position,
visible = tooltipDefaultProps.visible,
}) => {
return (
<div
className={classnames('tooltip', { 'tooltip--show': visible })}
style={{ transform: `translate(${position.x}px, ${position.y}px)` }}
>
<span
className={classnames('tooltip-arrow', `tooltip-arrow--${direction}`)}
/>
<h3 className="tooltip-label">{`${content?.label1}:`}</h3>
<h4 className="tooltip-value">{content?.value1}</h4>

<br />
<h3 className="tooltip-label">{`${content?.label2}:`}</h3>
<h4 className="tooltip-value">{content?.value2}</h4>
</div>
);
};
104 changes: 104 additions & 0 deletions src/components/experiment-tracking/tooltip/tooltip.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
@use '../../../styles/variables' as colors;

@mixin fade-in($waitTime) {
animation: wait #{$waitTime}, fade-in 800ms #{$waitTime};
}

@keyframes wait {
0% {
opacity: 0;
}

100% {
opacity: 0;
}
}

@keyframes fade-in {
0% {
opacity: 0;
}

100% {
opacity: 1;
}
}

$triangle-size: 10px;

.tooltip {
background: white;
display: flex;
flex-direction: column;
opacity: 0;
padding: 10px 30px 10px 10px;
position: absolute;
}

.tooltip--show {
@include fade-in('700ms');
animation-fill-mode: forwards;
}

.tooltip-arrow {
display: inline-block;
height: 0;
left: 1px;

margin-right: 1.6em;
margin-top: -1.2em;

position: absolute;
top: 22px;
white-space: nowrap;
width: 0;
}

.tooltip-arrow--right {
&::before {
border-left: $triangle-size solid transparent;
border-top: $triangle-size solid var(--color-bg-alt);

content: '';

height: 0;
left: -$triangle-size + 0.5;
position: absolute;
top: calc(50% - #{$triangle-size});
width: 0;
}
}

.tooltip-arrow--left {
&::before {
border-right: $triangle-size solid transparent;
border-top: $triangle-size solid var(--color-bg-alt);

content: '';

height: 0;
position: absolute;
right: -225.5px;
top: calc(50% - #{$triangle-size});
width: 0;
}
}

.tooltip-label,
.tooltip-value {
font-size: 12px;
font-weight: 400;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 180px;
}

.tooltip-label {
color: #{colors.$black-500};
}

.tooltip-value {
color: #{colors.$black-900};
}
2 changes: 1 addition & 1 deletion src/utils/date-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
const _dayJs = dayjs.extend(relativeTime);

const formatTimestamp = (timestamp) =>
export const formatTimestamp = (timestamp) =>
timestamp.replace('.', ':').replace('.', ':');

/**
Expand Down

0 comments on commit b39299a

Please sign in to comment.