From a9e6f93e3e4ba734f0a90ba08d835b64a47eb991 Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Wed, 4 Feb 2026 23:52:38 +0700 Subject: [PATCH] fix(common): chart helper type safety --- libs/common/src/lib/chart-helper.ts | 49 +++++++++++++++++------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/libs/common/src/lib/chart-helper.ts b/libs/common/src/lib/chart-helper.ts index da6473645..3338675a8 100644 --- a/libs/common/src/lib/chart-helper.ts +++ b/libs/common/src/lib/chart-helper.ts @@ -1,8 +1,11 @@ import type { ElementRef } from '@angular/core'; import type { Chart, - ChartTypeRegistry, + ChartType, + ControllerDatasetOptions, Plugin, + Point, + TooltipOptions, TooltipPosition } from 'chart.js'; import { format } from 'date-fns'; @@ -21,7 +24,7 @@ export function formatGroupedDate({ date, groupBy }: { - date: Date; + date: number; groupBy: GroupBy; }) { if (groupBy === 'month') { @@ -33,7 +36,7 @@ export function formatGroupedDate({ return format(date, DATE_FORMAT); } -export function getTooltipOptions({ +export function getTooltipOptions({ colorScheme, currency = '', groupBy, @@ -45,35 +48,39 @@ export function getTooltipOptions({ groupBy?: GroupBy; locale?: string; unit?: string; -}) { +}): Partial> { return { backgroundColor: getBackgroundColor(colorScheme), bodyColor: `rgb(${getTextColor(colorScheme)})`, borderWidth: 1, borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`, + // @ts-expect-error: no need to set all attributes in callbacks. callbacks: { label: (context) => { - let label = context.dataset.label ?? ''; + let label = (context.dataset as ControllerDatasetOptions).label ?? ''; if (label) { label += ': '; } - if (context.parsed.y !== null) { + + const yPoint = (context.parsed as Point).y; + if (yPoint !== null) { if (currency) { - label += `${context.parsed.y.toLocaleString(locale, { + label += `${yPoint.toLocaleString(locale, { maximumFractionDigits: 2, minimumFractionDigits: 2 })} ${currency}`; } else if (unit) { - label += `${context.parsed.y.toFixed(2)} ${unit}`; + label += `${yPoint.toFixed(2)} ${unit}`; } else { - label += context.parsed.y.toFixed(2); + label += yPoint.toFixed(2); } } return label; }, title: (contexts) => { - if (groupBy) { - return formatGroupedDate({ groupBy, date: contexts[0].parsed.x }); + const xPoint = (contexts[0].parsed as Point).x; + if (groupBy && xPoint !== null) { + return formatGroupedDate({ groupBy, date: xPoint }); } return contexts[0].label; @@ -104,10 +111,10 @@ export function getTooltipPositionerMapTop( }; } -export function getVerticalHoverLinePlugin( - chartCanvas: ElementRef, +export function getVerticalHoverLinePlugin( + chartCanvas: ElementRef, colorScheme: ColorScheme -): Plugin { +): Plugin { return { afterDatasetsDraw: (chart, _, options) => { const active = chart.getActiveElements(); @@ -125,13 +132,15 @@ export function getVerticalHoverLinePlugin( const xValue = active[0].element.x; const context = chartCanvas.nativeElement.getContext('2d'); - context.lineWidth = width; - context.strokeStyle = color; + if (context) { + context.lineWidth = width; + context.strokeStyle = color; - context.beginPath(); - context.moveTo(xValue, top); - context.lineTo(xValue, bottom); - context.stroke(); + context.beginPath(); + context.moveTo(xValue, top); + context.lineTo(xValue, bottom); + context.stroke(); + } }, id: 'verticalHoverLine' };