From e5a300efb8ae275706ff3616e611e4778ea71f3b Mon Sep 17 00:00:00 2001 From: Harman-singh-waraich Date: Tue, 16 Jul 2024 15:39:03 +0530 Subject: [PATCH] feat(web): tooltip-improvement-and-line-draw --- web/global.d.ts | 6 +++ web/src/pages/Home/CourtOverview/Chart.tsx | 20 +++++++++ .../Home/CourtOverview/TimeSeriesChart.tsx | 45 +++++++++++++++++-- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/web/global.d.ts b/web/global.d.ts index cfd137485..2fa15462b 100644 --- a/web/global.d.ts +++ b/web/global.d.ts @@ -17,3 +17,9 @@ declare module "styled-components" { //eslint-disable-next-line @typescript-eslint/no-empty-interface export interface DefaultTheme extends Theme {} } + +declare module "chart.js" { + interface TooltipPositionerMap { + custom: TooltipPositionerFunction; + } +} diff --git a/web/src/pages/Home/CourtOverview/Chart.tsx b/web/src/pages/Home/CourtOverview/Chart.tsx index ab70a95d8..3be709b37 100644 --- a/web/src/pages/Home/CourtOverview/Chart.tsx +++ b/web/src/pages/Home/CourtOverview/Chart.tsx @@ -1,6 +1,7 @@ import React, { useMemo, useState } from "react"; import styled from "styled-components"; +import { Tooltip } from "chart.js"; import { formatUnits } from "viem"; import { DropdownSelect } from "@kleros/ui-components-library"; @@ -101,4 +102,23 @@ const Chart: React.FC = () => { ); }; +// custom positioner for tooltip, we need dynamic top positioning, which is not available by default. +Tooltip.positioners.custom = function (elements) { + const tooltip = this; + const height = tooltip.chart.chartArea.height; + const width = tooltip.chart.chartArea.width; + + const x = elements[0]?.element.x; + const y = elements[0]?.element.y; + const isAtTop = height > y + tooltip.height; + const isAtEnd = width < x + tooltip.width; + + return { + x: elements[0]?.element.x, + y: elements[0]?.element.y, + xAlign: isAtTop ? (isAtEnd ? "right" : "left") : "center", + yAlign: isAtTop ? "center" : "bottom", + }; +}; + export default Chart; diff --git a/web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx b/web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx index f7d06c523..41eb1ce59 100644 --- a/web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx +++ b/web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx @@ -1,7 +1,16 @@ import React from "react"; import styled, { useTheme } from "styled-components"; -import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, TimeScale, Tooltip } from "chart.js"; +import { + Chart as ChartJS, + CategoryScale, + LinearScale, + PointElement, + LineElement, + TimeScale, + Tooltip, + ScriptableContext, +} from "chart.js"; import { Line } from "react-chartjs-2"; import "chartjs-adapter-moment"; @@ -51,6 +60,7 @@ const TimeSeriesChart: React.FC = ({ data }) => { }, plugins: { tooltip: { + position: "custom", backgroundColor: theme.whiteBackground, titleColor: theme.primaryText, borderColor: theme.stroke, @@ -74,18 +84,47 @@ const TimeSeriesChart: React.FC = ({ data }) => { datasets: [ { data, - borderColor: theme.primaryBlue, + // borderColor: theme.primaryBlue, stepped: true, cubicInterpolationMode: "monotone", + borderColor: (context: ScriptableContext<"line">) => { + const ctx = context.chart.ctx; + const gradient = ctx.createLinearGradient(0, 0, 0, 200); + gradient.addColorStop(0, theme.primaryBlue); + gradient.addColorStop(1, theme.secondaryPurple); + return gradient; + }, }, ], }, options, }} + plugins={[ + { + id: "line-draw", + afterDatasetsDraw: (chart) => { + if (chart.tooltip?._active?.length) { + const x = chart.tooltip._active[0].element.x; + const y = chart.tooltip._active[0].element.y; + const yAxis = chart.scales.y; + + const ctx = chart.ctx; + ctx.save(); + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x, yAxis.bottom); + ctx.lineWidth = 1; + ctx.strokeStyle = theme.secondaryPurple; + ctx.setLineDash([4, 4]); + ctx.stroke(); + ctx.restore(); + } + }, + }, + ]} /> } ); }; - export default TimeSeriesChart;