diff --git a/components/LineGraph.module.css b/components/LineGraph.module.css index 311a78f..bb8cdfe 100644 --- a/components/LineGraph.module.css +++ b/components/LineGraph.module.css @@ -21,4 +21,15 @@ padding: calc(10rem / 16); font-size: calc(18rem / 16); border-radius: calc(10rem / 16); +} + +.wrapper { + display: flex; + align-items: center; + width: min-content; +} + +.legend { + display: flex; + margin: calc(16rem / 8); } \ No newline at end of file diff --git a/components/LineGraph.tsx b/components/LineGraph.tsx index d24d654..673bd05 100644 --- a/components/LineGraph.tsx +++ b/components/LineGraph.tsx @@ -4,8 +4,9 @@ import { leftTickLabelProps } from "@visx/axis/lib/axis/AxisLeft"; import { localPoint } from "@visx/event"; import { GridColumns, GridRows } from "@visx/grid"; import { Group } from "@visx/group"; +import { LegendOrdinal } from "@visx/legend"; import { Point } from "@visx/point"; -import { scaleBand, scaleLinear } from "@visx/scale"; +import { scaleBand, scaleLinear, scaleOrdinal } from "@visx/scale"; import { LinePath } from "@visx/shape"; import { useTooltip, useTooltipInPortal } from "@visx/tooltip"; import React from "react"; @@ -28,6 +29,22 @@ interface LineGraphData { lines: LineData[]; } +interface LegendProps { + /** Position of the legend, relative to the graph. */ + position?: "top" | "right"; + /** Font size of the labels in the legend, in pixels. Default is 16px. */ + itemLabelSize?: number; + /** Gap between items in the legend, in pixels. */ + itemGap?: number; + /** Distance between the legend and other adjacent elements, in pixels. */ + margin?: { + top?: number; + bottom?: number; + left?: number; + right?: number; + }; +} + interface LineGraphProps { data: LineGraphData; /** Width of the entire graph, in pixels. */ @@ -60,9 +77,11 @@ interface LineGraphProps { yAxisLabelSize?: number; /** Controls the distance between the value axis label and the value axis. */ yAxisLabelOffset?: number; + legendProps?: LegendProps; } const DEFAULT_LABEL_SIZE = 16; +const DEFAULT_LEGEND_GAP = 16; export function LineGraph(props: LineGraphProps) { const { @@ -80,8 +99,16 @@ 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) => { @@ -137,8 +164,20 @@ export function LineGraph(props: LineGraphProps) { domain: [yMaxValue, 0], }); + const keys = data.lines.map((line) => line.label); + + const legendScale = scaleOrdinal({ + domain: keys, + range: [Color.primaryAccent, Color.secondaryAccent], + }); + return ( - <> +
+ {tooltipOpen && ( {tooltipData} )} - +
); } diff --git a/package-lock.json b/package-lock.json index c95839f..e345883 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,12 +5,14 @@ "requires": true, "packages": { "": { + "name": "cs-2022-class-profile", "version": "0.1.0", "dependencies": { "@visx/axis": "^2.10.0", "@visx/event": "^2.6.0", "@visx/grid": "^2.10.0", "@visx/group": "^2.10.0", + "@visx/legend": "^2.10.0", "@visx/mock-data": "^2.1.2", "@visx/scale": "^2.2.2", "@visx/shape": "^2.10.0", @@ -973,6 +975,21 @@ "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" } }, + "node_modules/@visx/legend": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@visx/legend/-/legend-2.10.0.tgz", + "integrity": "sha512-OI8BYE6QQI9eXAng/C7UzuVw7d0fwlzrth6RmrdhlyT1K+BA3WpExapV+pDfwxu/tkEik8Ps5cZRV6HjX1/Mww==", + "dependencies": { + "@types/react": "*", + "@visx/group": "2.10.0", + "@visx/scale": "2.2.2", + "classnames": "^2.3.1", + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "react": "^16.3.0-0 || ^17.0.0-0 || ^18.0.0-0" + } + }, "node_modules/@visx/mock-data": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@visx/mock-data/-/mock-data-2.1.2.tgz", @@ -5093,6 +5110,18 @@ "prop-types": "^15.6.2" } }, + "@visx/legend": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@visx/legend/-/legend-2.10.0.tgz", + "integrity": "sha512-OI8BYE6QQI9eXAng/C7UzuVw7d0fwlzrth6RmrdhlyT1K+BA3WpExapV+pDfwxu/tkEik8Ps5cZRV6HjX1/Mww==", + "requires": { + "@types/react": "*", + "@visx/group": "2.10.0", + "@visx/scale": "2.2.2", + "classnames": "^2.3.1", + "prop-types": "^15.5.10" + } + }, "@visx/mock-data": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@visx/mock-data/-/mock-data-2.1.2.tgz", diff --git a/package.json b/package.json index f59b11a..7a18472 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@visx/event": "^2.6.0", "@visx/grid": "^2.10.0", "@visx/group": "^2.10.0", + "@visx/legend": "^2.10.0", "@visx/mock-data": "^2.1.2", "@visx/scale": "^2.2.2", "@visx/shape": "^2.10.0",