You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ghostfolio/libs/common/src/lib/chart-helper.ts

143 lines
3.3 KiB

import { Chart, TooltipPosition } from 'chart.js';
import { format } from 'date-fns';
import {
DATE_FORMAT,
DATE_FORMAT_MONTHLY,
DATE_FORMAT_YEARLY,
getBackgroundColor,
getLocale,
getTextColor
} from './helper';
import { ColorScheme, GroupBy } from './types';
export function formatGroupedDate({
date,
groupBy
}: {
date: Date;
groupBy: GroupBy;
}) {
if (groupBy === 'month') {
return format(date, DATE_FORMAT_MONTHLY);
} else if (groupBy === 'year') {
return format(date, DATE_FORMAT_YEARLY);
}
return format(date, DATE_FORMAT);
}
export function getTooltipOptions({
colorScheme,
currency = '',
groupBy,
locale = getLocale(),
unit = ''
}: {
colorScheme?: ColorScheme;
currency?: string;
groupBy?: GroupBy;
locale?: string;
unit?: string;
} = {}) {
return {
backgroundColor: getBackgroundColor(colorScheme),
bodyColor: `rgb(${getTextColor(colorScheme)})`,
borderWidth: 1,
borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`,
callbacks: {
label: (context) => {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
if (currency) {
label += `${context.parsed.y.toLocaleString(locale, {
maximumFractionDigits: 2,
minimumFractionDigits: 2
})} ${currency}`;
} else if (unit) {
label += `${context.parsed.y.toFixed(2)} ${unit}`;
} else {
label += context.parsed.y.toFixed(2);
}
}
return label;
},
title: (contexts) => {
if (groupBy) {
return formatGroupedDate({ groupBy, date: contexts[0].parsed.x });
}
return contexts[0].label;
}
},
caretSize: 0,
cornerRadius: 2,
footerColor: `rgb(${getTextColor(colorScheme)})`,
itemSort: (a, b) => {
// Reverse order
return b.datasetIndex - a.datasetIndex;
},
titleColor: `rgb(${getTextColor(colorScheme)})`,
usePointStyle: true
};
}
export function getTooltipPositionerMapTop(
chart: Chart,
position: TooltipPosition
) {
if (!position || !chart?.chartArea) {
return false;
}
return {
x: position.x,
y: chart.chartArea.top
};
}
export function getVerticalHoverLinePlugin(
chartCanvas,
colorScheme?: ColorScheme
) {
return {
afterDatasetsDraw: (chart, x, options) => {
const active = chart.getActiveElements();
if (!active || active.length === 0) {
return;
}
const color = options.color || `rgb(${getTextColor(colorScheme)})`;
const width = options.width || 1;
const {
chartArea: { bottom, top }
} = chart;
const xValue = active[0].element.x;
const context = chartCanvas.nativeElement.getContext('2d');
context.lineWidth = width;
context.strokeStyle = color;
context.beginPath();
context.moveTo(xValue, top);
context.lineTo(xValue, bottom);
context.stroke();
},
id: 'verticalHoverLine'
};
}
export function transformTickToAbbreviation(value: number) {
if (value >= -999 && value <= 999) {
return value.toString();
} else if (value >= -999999 && value <= 999999) {
return `${value / 1000}K`;
} else {
return `${value / 1000000}M`;
}
}