Skip to content

Commit 7165c90

Browse files
authored
Merge pull request #1655 from kleros/feat/cases-by-court-chart
Feat: tooltip improvement and line draw
2 parents 53249a7 + f988e09 commit 7165c90

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

web/global.d.ts

+6
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,9 @@ declare module "styled-components" {
1717
//eslint-disable-next-line @typescript-eslint/no-empty-interface
1818
export interface DefaultTheme extends Theme {}
1919
}
20+
21+
declare module "chart.js" {
22+
interface TooltipPositionerMap {
23+
custom: TooltipPositionerFunction<ChartType>;
24+
}
25+
}

web/src/pages/Home/CourtOverview/Chart.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { useMemo, useState } from "react";
22
import styled from "styled-components";
33

4+
import { Tooltip } from "chart.js";
45
import { formatUnits } from "viem";
56

67
import { DropdownSelect } from "@kleros/ui-components-library";
@@ -101,4 +102,23 @@ const Chart: React.FC = () => {
101102
);
102103
};
103104

105+
// custom positioner for tooltip, we need dynamic top positioning, which is not available by default.
106+
Tooltip.positioners.custom = function (elements) {
107+
const tooltip = this;
108+
const height = tooltip.chart.chartArea.height;
109+
const width = tooltip.chart.chartArea.width;
110+
111+
const x = elements[0]?.element.x;
112+
const y = elements[0]?.element.y;
113+
const isAtTop = height > y + tooltip.height;
114+
const isAtEnd = width < x + tooltip.width;
115+
116+
return {
117+
x: elements[0]?.element.x,
118+
y: elements[0]?.element.y,
119+
xAlign: isAtTop ? (isAtEnd ? "right" : "left") : "center",
120+
yAlign: isAtTop ? "center" : "bottom",
121+
};
122+
};
123+
104124
export default Chart;

web/src/pages/Home/CourtOverview/TimeSeriesChart.tsx

+42-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import React from "react";
22
import styled, { useTheme } from "styled-components";
33

4-
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, TimeScale, Tooltip } from "chart.js";
4+
import {
5+
Chart as ChartJS,
6+
CategoryScale,
7+
LinearScale,
8+
PointElement,
9+
LineElement,
10+
TimeScale,
11+
Tooltip,
12+
ScriptableContext,
13+
} from "chart.js";
514
import { Line } from "react-chartjs-2";
615
import "chartjs-adapter-moment";
716

@@ -51,6 +60,7 @@ const TimeSeriesChart: React.FC<ITimeSeriesChart> = ({ data }) => {
5160
},
5261
plugins: {
5362
tooltip: {
63+
position: "custom",
5464
backgroundColor: theme.whiteBackground,
5565
titleColor: theme.primaryText,
5666
borderColor: theme.stroke,
@@ -74,18 +84,47 @@ const TimeSeriesChart: React.FC<ITimeSeriesChart> = ({ data }) => {
7484
datasets: [
7585
{
7686
data,
77-
borderColor: theme.primaryBlue,
87+
// borderColor: theme.primaryBlue,
7888
stepped: true,
7989
cubicInterpolationMode: "monotone",
90+
borderColor: (context: ScriptableContext<"line">) => {
91+
const ctx = context.chart.ctx;
92+
const gradient = ctx.createLinearGradient(0, 0, 0, 200);
93+
gradient.addColorStop(0, theme.primaryBlue);
94+
gradient.addColorStop(1, theme.secondaryPurple);
95+
return gradient;
96+
},
8097
},
8198
],
8299
},
83100
options,
84101
}}
102+
plugins={[
103+
{
104+
id: "line-draw",
105+
afterDatasetsDraw: (chart) => {
106+
if (chart.tooltip?._active?.length) {
107+
const x = chart.tooltip._active[0].element.x;
108+
const y = chart.tooltip._active[0].element.y;
109+
const yAxis = chart.scales.y;
110+
111+
const ctx = chart.ctx;
112+
ctx.save();
113+
ctx.beginPath();
114+
ctx.moveTo(x, y);
115+
ctx.lineTo(x, yAxis.bottom);
116+
ctx.lineWidth = 1;
117+
ctx.strokeStyle = theme.secondaryPurple;
118+
ctx.setLineDash([4, 4]);
119+
ctx.stroke();
120+
ctx.restore();
121+
}
122+
},
123+
},
124+
]}
85125
/>
86126
}
87127
</LineContainer>
88128
);
89129
};
90-
91130
export default TimeSeriesChart;

0 commit comments

Comments
 (0)