Browse Source

fix(common): chart helper type safety

pull/6277/head
KenTandrian 7 days ago
parent
commit
a9e6f93e3e
  1. 49
      libs/common/src/lib/chart-helper.ts

49
libs/common/src/lib/chart-helper.ts

@ -1,8 +1,11 @@
import type { ElementRef } from '@angular/core'; import type { ElementRef } from '@angular/core';
import type { import type {
Chart, Chart,
ChartTypeRegistry, ChartType,
ControllerDatasetOptions,
Plugin, Plugin,
Point,
TooltipOptions,
TooltipPosition TooltipPosition
} from 'chart.js'; } from 'chart.js';
import { format } from 'date-fns'; import { format } from 'date-fns';
@ -21,7 +24,7 @@ export function formatGroupedDate({
date, date,
groupBy groupBy
}: { }: {
date: Date; date: number;
groupBy: GroupBy; groupBy: GroupBy;
}) { }) {
if (groupBy === 'month') { if (groupBy === 'month') {
@ -33,7 +36,7 @@ export function formatGroupedDate({
return format(date, DATE_FORMAT); return format(date, DATE_FORMAT);
} }
export function getTooltipOptions({ export function getTooltipOptions<T extends ChartType>({
colorScheme, colorScheme,
currency = '', currency = '',
groupBy, groupBy,
@ -45,35 +48,39 @@ export function getTooltipOptions({
groupBy?: GroupBy; groupBy?: GroupBy;
locale?: string; locale?: string;
unit?: string; unit?: string;
}) { }): Partial<TooltipOptions<T>> {
return { return {
backgroundColor: getBackgroundColor(colorScheme), backgroundColor: getBackgroundColor(colorScheme),
bodyColor: `rgb(${getTextColor(colorScheme)})`, bodyColor: `rgb(${getTextColor(colorScheme)})`,
borderWidth: 1, borderWidth: 1,
borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`, borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`,
// @ts-expect-error: no need to set all attributes in callbacks.
callbacks: { callbacks: {
label: (context) => { label: (context) => {
let label = context.dataset.label ?? ''; let label = (context.dataset as ControllerDatasetOptions).label ?? '';
if (label) { if (label) {
label += ': '; label += ': ';
} }
if (context.parsed.y !== null) {
const yPoint = (context.parsed as Point).y;
if (yPoint !== null) {
if (currency) { if (currency) {
label += `${context.parsed.y.toLocaleString(locale, { label += `${yPoint.toLocaleString(locale, {
maximumFractionDigits: 2, maximumFractionDigits: 2,
minimumFractionDigits: 2 minimumFractionDigits: 2
})} ${currency}`; })} ${currency}`;
} else if (unit) { } else if (unit) {
label += `${context.parsed.y.toFixed(2)} ${unit}`; label += `${yPoint.toFixed(2)} ${unit}`;
} else { } else {
label += context.parsed.y.toFixed(2); label += yPoint.toFixed(2);
} }
} }
return label; return label;
}, },
title: (contexts) => { title: (contexts) => {
if (groupBy) { const xPoint = (contexts[0].parsed as Point).x;
return formatGroupedDate({ groupBy, date: contexts[0].parsed.x }); if (groupBy && xPoint !== null) {
return formatGroupedDate({ groupBy, date: xPoint });
} }
return contexts[0].label; return contexts[0].label;
@ -104,10 +111,10 @@ export function getTooltipPositionerMapTop(
}; };
} }
export function getVerticalHoverLinePlugin<T extends keyof ChartTypeRegistry>( export function getVerticalHoverLinePlugin<T extends 'line' | 'bar'>(
chartCanvas: ElementRef, chartCanvas: ElementRef<HTMLCanvasElement>,
colorScheme: ColorScheme colorScheme: ColorScheme
): Plugin<T> { ): Plugin<T, { color: string; width: number }> {
return { return {
afterDatasetsDraw: (chart, _, options) => { afterDatasetsDraw: (chart, _, options) => {
const active = chart.getActiveElements(); const active = chart.getActiveElements();
@ -125,13 +132,15 @@ export function getVerticalHoverLinePlugin<T extends keyof ChartTypeRegistry>(
const xValue = active[0].element.x; const xValue = active[0].element.x;
const context = chartCanvas.nativeElement.getContext('2d'); const context = chartCanvas.nativeElement.getContext('2d');
context.lineWidth = width; if (context) {
context.strokeStyle = color; context.lineWidth = width;
context.strokeStyle = color;
context.beginPath(); context.beginPath();
context.moveTo(xValue, top); context.moveTo(xValue, top);
context.lineTo(xValue, bottom); context.lineTo(xValue, bottom);
context.stroke(); context.stroke();
}
}, },
id: 'verticalHoverLine' id: 'verticalHoverLine'
}; };

Loading…
Cancel
Save