diff --git a/components/Boxplot.module.css b/components/Boxplot.module.css index f776cf6..66dda09 100644 --- a/components/Boxplot.module.css +++ b/components/Boxplot.module.css @@ -5,34 +5,4 @@ .boxplot:hover { fill: var(--primary-accent); filter: drop-shadow(0 0 calc(4rem / 16) var(--primary-accent)); -} - -.tooltip { - font-family: "Inconsolata", monospace; - top: 0; - left: 0; - position: absolute; - background-color: var(--label); - color: var(--primary-background); - pointer-events: none; - padding: calc(10rem / 16); - border-radius: calc(10rem / 16); -} - -.tooltip .category { - margin: calc(10rem / 16) 0 0 0; - font-size: calc(16rem / 16); - font-weight: 700; -} - -.tooltip .toolTipData { - margin-top: calc(5rem / 16); - margin-bottom: calc(10rem / 16); - font-size: calc(16rem / 16); -} - -.tooltip .toolTipData p { - margin: 0; - padding: 0; - font-size: calc(16rem / 16); -} +} \ No newline at end of file diff --git a/components/Boxplot.tsx b/components/Boxplot.tsx index 924bc65..f413b2b 100644 --- a/components/Boxplot.tsx +++ b/components/Boxplot.tsx @@ -6,11 +6,13 @@ import { Point } from "@visx/point"; import { scaleBand, scaleLinear } from "@visx/scale"; import { Line } from "@visx/shape"; import { BoxPlot as VisxBoxPlot } from "@visx/stats"; -import { withTooltip, Tooltip } from "@visx/tooltip"; +import { withTooltip } from "@visx/tooltip"; import { WithTooltipProvidedProps } from "@visx/tooltip/lib/enhancers/withTooltip"; import React from "react"; import { Color } from "utils/Color"; +import { TooltipWrapper } from "./TooltipWrapper"; + import styles from "./Boxplot.module.css"; const DEFAULT_LABEL_SIZE = 16; @@ -339,21 +341,17 @@ export const BoxPlot = withTooltip( {tooltipOpen && tooltipData && ( - -

{tooltipData.category}

-
-

max: {tooltipData.max}

-

third quartile: {tooltipData.thirdQuartile}

-

median: {tooltipData.median}

-

first quartile: {tooltipData.firstQuartile}

-

min: {tooltipData.min}

-
-
+

max: {tooltipData.max}

+

third quartile: {tooltipData.thirdQuartile}

+

median: {tooltipData.median}

+

first quartile: {tooltipData.firstQuartile}

+

min: {tooltipData.min}

+ )} ); diff --git a/components/LineGraph.module.css b/components/LineGraph.module.css index bb8cdfe..8fedff0 100644 --- a/components/LineGraph.module.css +++ b/components/LineGraph.module.css @@ -8,20 +8,6 @@ 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); -} .wrapper { display: flex; diff --git a/components/LineGraph.tsx b/components/LineGraph.tsx index 7e98241..878a948 100644 --- a/components/LineGraph.tsx +++ b/components/LineGraph.tsx @@ -8,10 +8,12 @@ import { LegendOrdinal } from "@visx/legend"; import { Point } from "@visx/point"; import { scaleBand, scaleLinear, scaleOrdinal } from "@visx/scale"; import { LinePath } from "@visx/shape"; -import { useTooltip, useTooltipInPortal } from "@visx/tooltip"; +import { withTooltip } from "@visx/tooltip"; import React from "react"; import { Color } from "utils/Color"; +import { TooltipWrapper } from "./TooltipWrapper"; + import styles from "./LineGraph.module.css"; interface LineData { @@ -85,8 +87,11 @@ const DEFAULT_LEGEND_GAP = 16; // TODO: Address unused props in this file /* eslint-disable unused-imports/no-unused-vars*/ -export function LineGraph(props: LineGraphProps) { - const { + +type TooltipData = string; + +export const LineGraph = withTooltip( + ({ width, height, margin, @@ -101,211 +106,199 @@ export function LineGraph(props: LineGraphProps) { yAxisLabel, yAxisLabelSize = DEFAULT_LABEL_SIZE, yAxisLabelOffset = 0, - legendProps, - } = props; - - const { - position: legendPosition = "right", - itemLabelSize: legendLabelSize = DEFAULT_LABEL_SIZE, - itemGap: legendItemGap = DEFAULT_LEGEND_GAP, - margin: legendMargin = {}, - } = legendProps ?? {}; - - const xLength = data.xValues.length; - - data.lines.forEach((line) => { - if (line.yValues.length != xLength) { - throw new Error("Invalid data with wrong length."); - } - }); - - const { - tooltipData, + tooltipOpen, tooltipLeft, tooltipTop, - tooltipOpen, - showTooltip, + tooltipData, hideTooltip, - } = useTooltip(); + showTooltip, + legendProps, + }) => { + const { + position: legendPosition = "right", + itemLabelSize: legendLabelSize = DEFAULT_LABEL_SIZE, + itemGap: legendItemGap = DEFAULT_LEGEND_GAP, + margin: legendMargin = {}, + } = legendProps ?? {}; - const { containerRef, TooltipInPortal } = useTooltipInPortal({ - // use TooltipWithBounds - detectBounds: true, - // when tooltip containers are scrolled, this will correctly update the Tooltip position - scroll: true, - }); + const xLength = data.xValues.length; - const yMax = height - margin.top - margin.bottom; - const xMax = width - margin.left - margin.right; - - const actualData = data.lines.map((line) => { - return line.yValues.map((val, idx) => { - return { x: data.xValues[idx], y: val }; + data.lines.forEach((line) => { + if (line.yValues.length != xLength) { + throw new Error("Invalid data with wrong length."); + } }); - }); - const yMaxValue = Math.max( - ...data.lines.map((line) => { - return Math.max(...line.yValues); - }) - ); + const yMax = height - margin.top - margin.bottom; + const xMax = width - margin.left - margin.right; - // data accessors - const getX = (d: PointData) => d.x; - const getY = (d: PointData) => d.y; + const actualData = data.lines.map((line) => { + return line.yValues.map((val, idx) => { + return { x: data.xValues[idx], y: val }; + }); + }); - // scales - const xScale = scaleBand({ - range: [0, xMax], - domain: data.xValues, - }); + const yMaxValue = Math.max( + ...data.lines.map((line) => { + return Math.max(...line.yValues); + }) + ); - const yScale = scaleLinear({ - range: [0, yMax], - nice: true, - domain: [yMaxValue, 0], - }); + // data accessors + const getX = (d: PointData) => d.x; + const getY = (d: PointData) => d.y; - const keys = data.lines.map((line) => line.label); + // scales + const xScale = scaleBand({ + range: [0, xMax], + domain: data.xValues, + }); - const legendScale = scaleOrdinal({ - domain: keys, - range: [Color.primaryAccent, Color.secondaryAccent], - }); + const yScale = scaleLinear({ + range: [0, yMax], + nice: true, + domain: [yMaxValue, 0], + }); - return ( -
- - - - - { - return { - ...bottomTickLabelProps(), - className: styles.tickLabel, - dy: "-0.25rem", - fontSize: `${xTickLabelSize / 16}rem`, - width: xScale.bandwidth(), - }; - }} - /> - { - return { - ...leftTickLabelProps(), - className: styles.tickLabel, - dx: "1.25rem", - dy: "0.25rem", - fontSize: `${yTickLabelSize / 16}rem`, - }; - }} - /> - - {actualData.map((lineData, i) => { - const isEven = 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 - ) as Point; - showTooltip({ - tooltipData: data.lines[i].label, - tooltipTop: eventSvgCoords.y, - tooltipLeft: eventSvgCoords.x, - }); - }} - onMouseOut={hideTooltip} - data={lineData} - className={styles.line} - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - x={(d) => xScale(getX(d))!} - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - y={(d) => yScale(getY(d))!} - stroke={ - isEven ? Color.primaryAccent : Color.secondaryAccent - } - strokeWidth={4} - strokeOpacity={2} - /> - - ); - })} - - - - line.label); + + const legendScale = scaleOrdinal({ + domain: keys, + range: [Color.primaryAccent, Color.secondaryAccent], + }); + + return ( +
+ style={{ + flexDirection: legendPosition === "right" ? "row" : "column-reverse", + }} + > + + + + + { + return { + ...bottomTickLabelProps(), + className: styles.tickLabel, + dy: "-0.25rem", + fontSize: `${xTickLabelSize / 16}rem`, + width: xScale.bandwidth(), + }; + }} + /> + { + return { + ...leftTickLabelProps(), + className: styles.tickLabel, + dx: "1.25rem", + dy: "0.25rem", + fontSize: `${yTickLabelSize / 16}rem`, + }; + }} + /> + + {actualData.map((lineData, i) => { + const isEven = 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 + ) as Point; + showTooltip({ + tooltipData: data.lines[i].label, + tooltipTop: eventSvgCoords.y, + tooltipLeft: eventSvgCoords.x, + }); + }} + onMouseOut={hideTooltip} + data={lineData} + className={styles.line} + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + x={(d) => xScale(getX(d))!} + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + y={(d) => yScale(getY(d))!} + stroke={ + isEven ? Color.primaryAccent : Color.secondaryAccent + } + strokeWidth={4} + strokeOpacity={2} + /> + + ); + })} + + + + - {tooltipOpen && ( - - <>{tooltipData} - - )} -
- ); -} + {tooltipOpen && ( + + )} +
+ ); + } +); diff --git a/components/StackedBarGraph.module.css b/components/StackedBarGraph.module.css index ffe660f..4c25e0e 100644 --- a/components/StackedBarGraph.module.css +++ b/components/StackedBarGraph.module.css @@ -13,23 +13,6 @@ top: 0; } -.toolTip { - font-family: "Inconsolata", monospace; - top: 0; - left: 0; - position: absolute; - background-color: var(--label); - color: var(--primary-background); - pointer-events: none; - border-radius: calc(10rem / 16); - padding: calc(10rem / 16); -} - -.toolTip p { - margin: 0 calc(5rem / 16); - font-size: calc(16rem / 16); -} - .key { font-weight: bold; } \ No newline at end of file diff --git a/components/StackedBarGraph.tsx b/components/StackedBarGraph.tsx index 7c195e0..9b0bd44 100644 --- a/components/StackedBarGraph.tsx +++ b/components/StackedBarGraph.tsx @@ -7,11 +7,13 @@ import { Point } from "@visx/point"; import { scaleBand, scaleLinear, scaleOrdinal } from "@visx/scale"; import { BarStack, BarStackHorizontal, Line } from "@visx/shape"; import { SeriesPoint } from "@visx/shape/lib/types"; -import { withTooltip, Tooltip } from "@visx/tooltip"; +import { withTooltip } from "@visx/tooltip"; import { WithTooltipProvidedProps } from "@visx/tooltip/lib/enhancers/withTooltip"; import React from "react"; import { Color } from "utils/Color"; +import { TooltipWrapper } from "./TooltipWrapper"; + import styles from "./StackedBarGraph.module.css"; interface StackedBarData { @@ -248,16 +250,14 @@ export const StackedBarGraphVertical = withTooltip< {tooltipOpen && tooltipData ? ( - -

{tooltipData.key}

{tooltipData.bar.data[tooltipData.key]}

{getCategory(tooltipData.bar.data)}

-
+ ) : null} ); @@ -438,16 +438,14 @@ export const StackedBarGraphHorizontal = withTooltip< {tooltipOpen && tooltipData ? ( - -

{tooltipData.key}

{tooltipData.bar.data[tooltipData.key]}

{getCategory(tooltipData.bar.data)}

-
+ ) : null} ); diff --git a/components/TooltipWrapper.module.css b/components/TooltipWrapper.module.css new file mode 100644 index 0000000..c6c0ed5 --- /dev/null +++ b/components/TooltipWrapper.module.css @@ -0,0 +1,31 @@ +.tooltip { + font-family: "Inconsolata", monospace; + top: 0; + left: 0; + position: absolute; + background-color: var(--label); + pointer-events: none; + padding: calc(10rem / 16); + border-radius: calc(10rem / 16); + font-size: calc(18rem / 16); +} + +.header { + color: var(--primary-background); + margin: 0; + font-size: calc(16rem / 16); + font-weight: 700; +} + +.body { + color: var(--primary-background); + margin-top: calc(5rem / 16); + font-size: calc(16rem / 16); +} + +.body p { + color: var(--primary-background); + margin: 0; + padding: 0; + font-size: calc(16rem / 16) !important; +} \ No newline at end of file diff --git a/components/TooltipWrapper.tsx b/components/TooltipWrapper.tsx new file mode 100644 index 0000000..d260852 --- /dev/null +++ b/components/TooltipWrapper.tsx @@ -0,0 +1,35 @@ +import { Tooltip } from "@visx/tooltip"; +import React from "react"; + +import styles from "./TooltipWrapper.module.css"; + +type TooltipWrapperProps = { + top?: number; + left?: number; + className?: string; + header?: string; + children?: React.ReactNode; +}; + +const TooltipWrapper = ({ + top, + left, + className, + header, + children, +}: TooltipWrapperProps) => { + return ( + + {header ? {header} : null} + {children ?
{children}
: null} +
+ ); +}; + +export { TooltipWrapper }; diff --git a/components/WordCloud.module.css b/components/WordCloud.module.css index 728094a..a6059ae 100644 --- a/components/WordCloud.module.css +++ b/components/WordCloud.module.css @@ -2,19 +2,4 @@ text-shadow: var(--primary-accent) 0 0 calc(20rem / 16); text-anchor: "middle"; cursor: default; -} - -.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/WordCloud.tsx b/components/WordCloud.tsx index a0e087c..fb09684 100644 --- a/components/WordCloud.tsx +++ b/components/WordCloud.tsx @@ -2,13 +2,15 @@ import { localPoint } from "@visx/event"; import { Point } from "@visx/point"; import { scaleLog } from "@visx/scale"; import { Text } from "@visx/text"; -import { TooltipWithBounds, useTooltip, withTooltip } from "@visx/tooltip"; +import { useTooltip, withTooltip } from "@visx/tooltip"; import { Wordcloud as VisxWordcloud } from "@visx/wordcloud"; import React from "react"; import { Color } from "utils/Color"; import { inDevEnvironment } from "utils/inDevEnviroment"; import { useIsMobile } from "utils/isMobile"; +import { TooltipWrapper } from "./TooltipWrapper"; + import styles from "./WordCloud.module.css"; interface WordCloudProps { @@ -101,17 +103,13 @@ export const WordCloud = withTooltip( /> {tooltipOpen && tooltipData ? ( - - {tooltipData.text} ({tooltipData.value}) - + header={`${tooltipData.text} (${tooltipData.value})`} + > ) : null} ); diff --git a/pages/samplePage.tsx b/pages/samplePage.tsx index 70b8f94..715e1fa 100644 --- a/pages/samplePage.tsx +++ b/pages/samplePage.tsx @@ -1,4 +1,9 @@ -import { mockCategoricalData, moreMockCategoricalData } from "data/mocks"; +import { + mockBoxPlotData, + mockCategoricalData, + mockLineData, + moreMockCategoricalData, +} from "data/mocks"; import { pageRoutes } from "data/routes"; import React from "react"; import { useWindowDimensions } from "utils/getWindowDimensions"; @@ -6,8 +11,10 @@ import { useIsMobile } from "utils/isMobile"; import { BarGraphVertical, BarGraphHorizontal } from "@/components/BarGraph"; import { BottomNav } from "@/components/BottomNav"; +import { BoxPlot } from "@/components/Boxplot"; import { ComponentWrapper } from "@/components/ComponentWrapper"; import { Header } from "@/components/Header"; +import { LineGraph } from "@/components/LineGraph"; import { SectionHeader } from "@/components/SectionHeader"; import { WordCloud } from "@/components/WordCloud"; @@ -53,7 +60,6 @@ export default function SamplePage() { margin={defaultVerticalBarGraphMargin} /> - - - - - - ({ @@ -142,7 +143,6 @@ export default function SamplePage() { height={defaultGraphHeight} /> - ({ @@ -153,7 +153,6 @@ export default function SamplePage() { height={defaultGraphHeight} /> - - - - ({ - text: word.key, - value: word.value, - }))} - width={defaultGraphWidth} - height={defaultGraphHeight} + + + + -