From bd757f56e97d11146998eac3fa29b1df13ac6071 Mon Sep 17 00:00:00 2001 From: shahanneda Date: Mon, 26 Dec 2022 23:04:32 -0500 Subject: [PATCH] Worked on tooltip centering --- components/Boxplot.tsx | 81 +++++---------- components/GroupedBarGraph.module.css | 3 +- components/GroupedBarGraph.tsx | 15 +-- components/StackedBarGraph.module.css | 1 + components/TooltipWrapper.tsx | 62 +++++++++++- components/WordCloud.tsx | 35 +++---- pages/playground.tsx | 15 +-- pages/samplePage.tsx | 136 ++++++++++++++++++++++++++ 8 files changed, 240 insertions(+), 108 deletions(-) diff --git a/components/Boxplot.tsx b/components/Boxplot.tsx index f413b2b..17fb477 100644 --- a/components/Boxplot.tsx +++ b/components/Boxplot.tsx @@ -11,7 +11,7 @@ import { WithTooltipProvidedProps } from "@visx/tooltip/lib/enhancers/withToolti import React from "react"; import { Color } from "utils/Color"; -import { TooltipWrapper } from "./TooltipWrapper"; +import { getTooltipPosition, TooltipWrapper } from "./TooltipWrapper"; import styles from "./Boxplot.module.css"; @@ -96,8 +96,8 @@ export const BoxPlot = withTooltip( valueAxisLabelTopOffset = 5, valueAxisLabelLeftOffset = 10, categoryAxisLabelLeftOffset = 30, - toolTipTopOffset = 20, - toolTipLeftOffset = 5, + toolTipTopOffset = 0, + toolTipLeftOffset = 0, categoryAxisLabelSize = DEFAULT_LABEL_SIZE, valueAxisLabelSize = DEFAULT_LABEL_SIZE, boxPlotWidthFactor = 0.4, @@ -149,6 +149,21 @@ export const BoxPlot = withTooltip( const constrainedWidth = Math.min(200, xScale.bandwidth()); + const mouseOverEventHandler = + (d: Stats) => + (e: React.MouseEvent) => { + const pos = getTooltipPosition(e); + + showTooltip({ + tooltipLeft: pos.x + toolTipLeftOffset, + tooltipTop: pos.y + toolTipTopOffset, + tooltipData: { + ...d.boxPlot, + category: getX(d), + }, + }); + }; + return width < 10 ? null : (
@@ -254,58 +269,19 @@ export const BoxPlot = withTooltip( strokeWidth={strokeWidth} valueScale={yScale} minProps={{ - onMouseOver: () => { - showTooltip({ - tooltipTop: - (yScale(getMin(d)) ?? 0) + toolTipTopOffset, - tooltipLeft: - xScale(getX(d))! + - constrainedWidth + - toolTipLeftOffset, - tooltipData: { - ...d.boxPlot, - category: getX(d), - }, - }); - }, + onMouseMove: mouseOverEventHandler(d), onMouseLeave: () => { hideTooltip(); }, }} maxProps={{ - onMouseOver: () => { - showTooltip({ - tooltipTop: - (yScale(getMax(d)) ?? 0) + toolTipTopOffset, - tooltipLeft: - xScale(getX(d))! + - constrainedWidth + - toolTipLeftOffset, - tooltipData: { - ...d.boxPlot, - category: getX(d), - }, - }); - }, + onMouseMove: mouseOverEventHandler(d), onMouseLeave: () => { hideTooltip(); }, }} boxProps={{ - onMouseOver: () => { - showTooltip({ - tooltipTop: - (yScale(getMedian(d)) ?? 0) + toolTipTopOffset, - tooltipLeft: - xScale(getX(d))! + - constrainedWidth + - toolTipLeftOffset, - tooltipData: { - ...d.boxPlot, - category: getX(d), - }, - }); - }, + onMouseMove: mouseOverEventHandler(d), strokeWidth: 0, onMouseLeave: () => { hideTooltip(); @@ -315,20 +291,7 @@ export const BoxPlot = withTooltip( style: { stroke: Color.label, }, - onMouseOver: () => { - showTooltip({ - tooltipTop: - (yScale(getMedian(d)) ?? 0) + toolTipTopOffset, - tooltipLeft: - xScale(getX(d))! + - constrainedWidth + - toolTipLeftOffset, - tooltipData: { - ...d.boxPlot, - category: getX(d), - }, - }); - }, + onMouseMove: mouseOverEventHandler(d), onMouseLeave: () => { hideTooltip(); }, diff --git a/components/GroupedBarGraph.module.css b/components/GroupedBarGraph.module.css index b452211..bbf8628 100644 --- a/components/GroupedBarGraph.module.css +++ b/components/GroupedBarGraph.module.css @@ -2,7 +2,6 @@ display: flex; flex-direction: column; align-items: center; - width: min-content; } .barBackground { @@ -25,4 +24,4 @@ display: flex; margin: calc(16rem / 16); justify-content: center; -} +} \ No newline at end of file diff --git a/components/GroupedBarGraph.tsx b/components/GroupedBarGraph.tsx index 7db46e6..bfb61e8 100644 --- a/components/GroupedBarGraph.tsx +++ b/components/GroupedBarGraph.tsx @@ -13,7 +13,7 @@ import { withTooltip } from "@visx/tooltip"; import React, { useState } from "react"; import { Color } from "utils/Color"; -import { TooltipWrapper } from "./TooltipWrapper"; +import { getTooltipPosition, TooltipWrapper } from "./TooltipWrapper"; import styles from "./GroupedBarGraph.module.css"; @@ -257,17 +257,12 @@ export const GroupedBarGraphVertical = withTooltip< {barGroup.bars.map((bar) => ( { - 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 - ) as Point; + const tooltipPos = getTooltipPosition(e); + showTooltip({ tooltipData: bar.value.toString(), - tooltipTop: eventSvgCoords.y, - tooltipLeft: eventSvgCoords.x, + tooltipTop: tooltipPos.y, + tooltipLeft: tooltipPos.x, }); }} onMouseOut={hideTooltip} diff --git a/components/StackedBarGraph.module.css b/components/StackedBarGraph.module.css index 40646db..38856a2 100644 --- a/components/StackedBarGraph.module.css +++ b/components/StackedBarGraph.module.css @@ -10,6 +10,7 @@ display: flex; font-size: calc(16rem / 16); top: 0; + justify-content: center; } .key { diff --git a/components/TooltipWrapper.tsx b/components/TooltipWrapper.tsx index d260852..72d9b4d 100644 --- a/components/TooltipWrapper.tsx +++ b/components/TooltipWrapper.tsx @@ -1,3 +1,5 @@ +import localPoint from "@visx/event/lib/localPoint"; +import { Point } from "@visx/point"; import { Tooltip } from "@visx/tooltip"; import React from "react"; @@ -11,6 +13,23 @@ type TooltipWrapperProps = { children?: React.ReactNode; }; +// Finds the SVG Element which is the outmost from element (highest parent of element which is svg) + +function getOutmostSVG(element: Element): SVGElement | undefined { + let rootSVG: HTMLElement | Element | null = element ?? null; + let current: HTMLElement | Element | null = element; + + while (current) { + console.log(current); + if (current.tagName == "svg") { + rootSVG = current; + } + current = current.parentElement; + } + + return rootSVG as SVGElement; +} + const TooltipWrapper = ({ top, left, @@ -32,4 +51,45 @@ const TooltipWrapper = ({ ); }; -export { TooltipWrapper }; +function getTooltipPosition( + e: React.MouseEvent< + SVGTextElement | SVGPathElement | SVGLineElement, + MouseEvent + > +) { + // ownerSVGElement is given by visx docs but not recognized by typescript + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const eventElement = e.target.ownerSVGElement as Element; + const eventSvgCoords = localPoint(eventElement, e) as Point; + const rootSVG: SVGElement | undefined = getOutmostSVG(eventElement); + + if (!rootSVG) { + console.error("Failed to find parent SVG for tooltip!"); + return { x: 0, y: 0 }; + } + console.log(eventElement); + console.log(rootSVG); + console.log("parent is ", rootSVG.parentElement); + const rootSVGLeft = rootSVG.getBoundingClientRect().left ?? 0; + console.log(rootSVGLeft); + + const parentDivLeft = + rootSVG.parentElement?.getBoundingClientRect().left ?? 0; + console.log(parentDivLeft); + // const parentParentDivLeft = + // eventElement.parentElement?.parentElement?.parentElement?.parentElement?.getBoundingClientRect() + // .left ?? 0; + // console.log(parentParentDivLeft); + + // visx localPoint does not account for the horizontal shift due to centering of the parent element, + // so manually add any shift from that + const alignmentOffset = rootSVGLeft - parentDivLeft; + console.log(alignmentOffset); + + return { + x: eventSvgCoords.x + alignmentOffset, + y: eventSvgCoords.y, + }; +} +export { TooltipWrapper, getTooltipPosition }; diff --git a/components/WordCloud.tsx b/components/WordCloud.tsx index 2a68a80..528db16 100644 --- a/components/WordCloud.tsx +++ b/components/WordCloud.tsx @@ -1,5 +1,3 @@ -import { localPoint } from "@visx/event"; -import { Point } from "@visx/point"; import { scaleLog } from "@visx/scale"; import { Text } from "@visx/text"; import { useTooltip, withTooltip } from "@visx/tooltip"; @@ -9,7 +7,7 @@ import { Color } from "utils/Color"; import { inDevEnvironment } from "utils/inDevEnviroment"; import { useIsMobile } from "utils/isMobile"; -import { TooltipWrapper } from "./TooltipWrapper"; +import { getTooltipPosition, TooltipWrapper } from "./TooltipWrapper"; import styles from "./WordCloud.module.css"; @@ -197,33 +195,22 @@ const WordCloudWords: React.FC = ({ className={styles.word} textAnchor="middle" onMouseMove={ - ((e: React.MouseEvent) => { - // ownerSVGElement is given by visx docs but not recognized by typescript - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const eventElement = e.target.ownerSVGElement as Element; - const eventSvgCoords = localPoint(eventElement, e) as Point; - const rootSVGLeft = - eventElement.parentElement?.parentElement?.getBoundingClientRect() - .left ?? 0; - const parentDivLeft = - eventElement.parentElement?.parentElement?.parentElement?.getBoundingClientRect() - .left ?? 0; - - // visx localPoint does not account for the horizontal shift due to centering of the parent element, - // so manually add any shift from that - const alignmentOffset = rootSVGLeft - parentDivLeft; - + (( + e: React.MouseEvent< + SVGTextElement | SVGLineElement, + MouseEvent + > + ) => { + const tooltipPos = getTooltipPosition(e); if (word.text) { showTooltip( { text: word.text, value: (cloudWords[index] as WordData).value, }, - eventSvgCoords.x - - word.text.length * TOOLTIP_HORIZONTAL_SHIFT_SCALER + - alignmentOffset, - eventSvgCoords.y + tooltipPos.x - + word.text.length * TOOLTIP_HORIZONTAL_SHIFT_SCALER, + tooltipPos.y ); } }) as React.MouseEventHandler diff --git a/pages/playground.tsx b/pages/playground.tsx index 0959f8f..bc261a8 100644 --- a/pages/playground.tsx +++ b/pages/playground.tsx @@ -18,6 +18,7 @@ import React from "react"; import { Color } from "utils/Color"; import { About } from "@/components/About"; +import { ComponentWrapper } from "@/components/ComponentWrapper"; import { GroupedBarGraphHorizontal, GroupedBarGraphVertical, @@ -26,6 +27,7 @@ import { LineGraph } from "@/components/LineGraph"; import { PieChart } from "@/components/PieChart"; import { QuotationCarousel } from "@/components/QuotationCarousel"; import { Sections } from "@/components/Sections"; +import { SectionWrapper } from "@/components/SectionWrapper"; import { StackedBarGraphVertical, StackedBarGraphHorizontal, @@ -67,18 +69,7 @@ export default function Home() {

{""}

- +

{""} diff --git a/pages/samplePage.tsx b/pages/samplePage.tsx index ccf08b8..8f4cde3 100644 --- a/pages/samplePage.tsx +++ b/pages/samplePage.tsx @@ -1,7 +1,11 @@ import { mockBoxPlotData, mockCategoricalData, + mockGroupedBarGraphData, mockLineData, + mockPieData, + mockStackedBarGraphData, + mockStackedBarKeys, moreMockCategoricalData, } from "data/mocks"; import { pageRoutes } from "data/routes"; @@ -14,9 +18,19 @@ import { BarGraphVertical, BarGraphHorizontal } from "@/components/BarGraph"; import { BottomNav } from "@/components/BottomNav"; import { BoxPlot } from "@/components/Boxplot"; import { ComponentWrapper } from "@/components/ComponentWrapper"; +import { + GroupedBarGraphHorizontal, + GroupedBarGraphVertical, +} from "@/components/GroupedBarGraph"; import { Header } from "@/components/Header"; import { LineGraph } from "@/components/LineGraph"; +import { PieChart } from "@/components/PieChart"; import { SectionHeader } from "@/components/SectionHeader"; +import { SectionWrapper } from "@/components/SectionWrapper"; +import { + StackedBarGraphVertical, + StackedBarGraphHorizontal, +} from "@/components/StackedBarGraph"; import { WordCloud } from "@/components/WordCloud"; import styles from "./samplePage.module.css"; @@ -46,6 +60,128 @@ export default function SamplePage() { return (
+ + + + + + + + + + + + + + ({ + text: word.key, + value: word.value, + }))} + /> +