From 934ab39dba11e6447c25ec1e4c1a8429dc5c3a37 Mon Sep 17 00:00:00 2001 From: Rebecca-Chou Date: Sat, 3 Sep 2022 01:13:11 -0400 Subject: [PATCH] add tooltip --- components/LineGraph.module.css | 15 +++ components/LineGraph.tsx | 198 ++++++++++++++++++++------------ 2 files changed, 139 insertions(+), 74 deletions(-) diff --git a/components/LineGraph.module.css b/components/LineGraph.module.css index 97f30b2..311a78f 100644 --- a/components/LineGraph.module.css +++ b/components/LineGraph.module.css @@ -6,4 +6,19 @@ .line:hover { filter: drop-shadow(0 0 calc(4rem / 16) var(--primary-accent)); +} + +.tooltip { + font-family: "Inconsolata", monospace; + font-weight: bold; + top: 0; + left: 0; + position: absolute; + background-color: var(--label); + color: var(--primary-background); + box-shadow: 0px calc(1rem / 16) calc(2rem / 16) var(--card-background); + pointer-events: none; + padding: calc(10rem / 16); + font-size: calc(18rem / 16); + border-radius: calc(10rem / 16); } \ No newline at end of file diff --git a/components/LineGraph.tsx b/components/LineGraph.tsx index d7055b3..ec50b97 100644 --- a/components/LineGraph.tsx +++ b/components/LineGraph.tsx @@ -1,11 +1,12 @@ import { AxisBottom, AxisLeft } from "@visx/axis"; import { bottomTickLabelProps } from "@visx/axis/lib/axis/AxisBottom"; import { leftTickLabelProps } from "@visx/axis/lib/axis/AxisLeft"; -import * as allCurves from "@visx/curve"; +import { localPoint } from "@visx/event"; import { GridColumns, GridRows } from "@visx/grid"; import { Group } from "@visx/group"; import { scaleBand, scaleLinear } from "@visx/scale"; import { LinePath } from "@visx/shape"; +import { useTooltip, useTooltipInPortal } from "@visx/tooltip"; import React from "react"; import { Color } from "utils/Color"; @@ -80,6 +81,24 @@ export function LineGraph(props: LineGraphProps) { yAxisLabelOffset = 0, } = props; + const { + tooltipData, + tooltipLeft, + tooltipTop, + tooltipOpen, + showTooltip, + hideTooltip, + } = useTooltip(); + + // If you don't want to use a Portal, simply replace `TooltipInPortal` below with + // `Tooltip` or `TooltipWithBounds` and remove `containerRef` + const { containerRef, TooltipInPortal } = useTooltipInPortal({ + // use TooltipWithBounds + detectBounds: true, + // when tooltip containers are scrolled, this will correctly update the Tooltip position + scroll: true, + }); + const yMax = height - margin.top - margin.bottom; const xMax = width - margin.left - margin.right; @@ -106,79 +125,110 @@ export function LineGraph(props: LineGraphProps) { }); return ( - - - - - { - return { - ...bottomTickLabelProps(), - className: styles.tickLabel, - dy: "-0.25rem", - fontSize: `${xTickLabelSize / 16}rem`, - width: xScale.bandwidth(), - }; - }} - /> - { - return { - ...leftTickLabelProps(), - className: styles.tickLabel, - dx: "0.75rem", - dy: "0.25rem", - fontSize: `${yTickLabelSize / 16}rem`, - }; - }} - /> - - {actualData.map((lineData, i) => { - const even = i % 2 === 0; - return ( - - xScale(getX(d)) ?? 0} - y={(d) => yScale(getY(d)) ?? 0} - stroke={even ? Color.primaryAccent : Color.secondaryAccent} - strokeWidth={3} - strokeOpacity={2} - /> - - ); - })} + <> + + + + + { + return { + ...bottomTickLabelProps(), + className: styles.tickLabel, + dy: "-0.25rem", + fontSize: `${xTickLabelSize / 16}rem`, + width: xScale.bandwidth(), + }; + }} + /> + { + return { + ...leftTickLabelProps(), + className: styles.tickLabel, + dx: "0.75rem", + dy: "0.25rem", + fontSize: `${yTickLabelSize / 16}rem`, + }; + }} + /> + + {actualData.map((lineData, i) => { + const even = i % 2 === 0; + return ( + + { + const eventSvgCoords = localPoint( + // ownerSVGElement is given by visx docs but not recognized by typescript + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + e.target.ownerSVGElement as Element, + e + ); + showTooltip({ + tooltipData: data.lines[i].label, + tooltipTop: eventSvgCoords.y, + tooltipLeft: eventSvgCoords.x, + }); + }} + onMouseOut={hideTooltip} + data={lineData} + className={styles.line} + x={(d) => xScale(getX(d)) ?? 0} + y={(d) => yScale(getY(d)) ?? 0} + stroke={even ? Color.primaryAccent : Color.secondaryAccent} + strokeWidth={3} + strokeOpacity={2} + /> + + ); + })} + - - + + + {tooltipOpen && ( + + {tooltipData} + + )} + ); }