2024-09-24 13:47:21 +02:00
|
|
|
import type { Theme } from '@mui/material/styles/createTheme';
|
|
|
|
import type { ChartOptions } from 'chart.js';
|
|
|
|
import type { ILocationSettings } from '../../hooks/useLocationSettings';
|
|
|
|
import type { IPoint } from '../feature/FeatureView/FeatureMetrics/FeatureMetricsChart/createChartData';
|
|
|
|
import {
|
|
|
|
formatDateHM,
|
|
|
|
formatDateYMD,
|
|
|
|
formatDateYMDHM,
|
|
|
|
} from '../../utils/formatDate';
|
|
|
|
|
|
|
|
const formatVariantEntry = (
|
|
|
|
variant: [string, number],
|
|
|
|
totalExposure: number,
|
|
|
|
) => {
|
|
|
|
if (totalExposure === 0) return '';
|
|
|
|
const [key, value] = variant;
|
|
|
|
const percentage = Math.floor((Number(value) / totalExposure) * 100);
|
|
|
|
return `${value} (${percentage}%) - ${key}`;
|
|
|
|
};
|
|
|
|
|
|
|
|
export const createPlaceholderBarChartOptions = (
|
|
|
|
theme: Theme,
|
|
|
|
): ChartOptions<'bar'> => ({
|
|
|
|
plugins: {
|
|
|
|
legend: {
|
2024-10-09 13:16:57 +02:00
|
|
|
position: 'top',
|
2024-09-24 13:47:21 +02:00
|
|
|
labels: {
|
|
|
|
color: theme.palette.text.primary,
|
|
|
|
usePointStyle: true,
|
2024-10-09 13:16:57 +02:00
|
|
|
pointStyle: 'none',
|
|
|
|
boxHeight: 0,
|
2024-09-24 13:47:21 +02:00
|
|
|
padding: 15,
|
|
|
|
boxPadding: 5,
|
|
|
|
},
|
|
|
|
},
|
2024-10-09 13:16:57 +02:00
|
|
|
|
2024-09-24 13:47:21 +02:00
|
|
|
tooltip: {
|
|
|
|
enabled: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
responsive: true,
|
|
|
|
scales: {
|
|
|
|
x: {
|
|
|
|
stacked: true,
|
|
|
|
ticks: {
|
2024-10-09 13:16:57 +02:00
|
|
|
display: false,
|
2024-09-24 13:47:21 +02:00
|
|
|
},
|
|
|
|
grid: {
|
|
|
|
display: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
y: {
|
|
|
|
stacked: true,
|
|
|
|
ticks: {
|
|
|
|
maxTicksLimit: 5,
|
2024-10-09 13:16:57 +02:00
|
|
|
display: false,
|
2024-09-24 13:47:21 +02:00
|
|
|
},
|
|
|
|
grid: {
|
|
|
|
drawBorder: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
elements: {
|
|
|
|
bar: {
|
|
|
|
borderRadius: 5,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
interaction: {
|
|
|
|
mode: 'index',
|
|
|
|
intersect: false,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
export const createBarChartOptions = (
|
|
|
|
theme: Theme,
|
|
|
|
hoursBack: number,
|
|
|
|
locationSettings: ILocationSettings,
|
|
|
|
): ChartOptions<'bar'> => {
|
2024-10-09 13:16:57 +02:00
|
|
|
const { responsive, elements, interaction, scales } =
|
2024-09-24 13:47:21 +02:00
|
|
|
createPlaceholderBarChartOptions(theme);
|
|
|
|
return {
|
|
|
|
plugins: {
|
2024-10-09 13:16:57 +02:00
|
|
|
legend: {
|
|
|
|
position: 'bottom',
|
|
|
|
labels: {
|
|
|
|
color: theme.palette.text.primary,
|
|
|
|
pointStyle: 'circle',
|
|
|
|
usePointStyle: true,
|
|
|
|
boxHeight: 6,
|
|
|
|
padding: 15,
|
|
|
|
boxPadding: 5,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2024-09-25 08:36:30 +02:00
|
|
|
// required to avoid the highlight plugin highlighting empty annotation
|
|
|
|
annotation: {
|
|
|
|
clip: false,
|
|
|
|
annotations: {},
|
|
|
|
},
|
2024-09-24 13:47:21 +02:00
|
|
|
tooltip: {
|
|
|
|
backgroundColor: theme.palette.background.paper,
|
|
|
|
titleColor: theme.palette.text.primary,
|
|
|
|
bodyColor: theme.palette.text.primary,
|
|
|
|
bodySpacing: 6,
|
|
|
|
padding: {
|
|
|
|
top: 20,
|
|
|
|
bottom: 20,
|
|
|
|
left: 30,
|
|
|
|
right: 30,
|
|
|
|
},
|
|
|
|
borderColor: 'rgba(0, 0, 0, 0.05)',
|
|
|
|
borderWidth: 3,
|
|
|
|
usePointStyle: true,
|
|
|
|
caretSize: 0,
|
|
|
|
boxPadding: 10,
|
|
|
|
callbacks: {
|
|
|
|
label: (item) => {
|
|
|
|
return `${item.formattedValue} - ${item.dataset.label}`;
|
|
|
|
},
|
|
|
|
afterLabel: (item) => {
|
|
|
|
const data = item.dataset.data[
|
|
|
|
item.dataIndex
|
|
|
|
] as unknown as IPoint;
|
|
|
|
|
|
|
|
if (
|
|
|
|
item.dataset.label !== 'Exposed' ||
|
|
|
|
data.variants === undefined
|
|
|
|
) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
const { disabled, ...actualVariants } = data.variants;
|
|
|
|
return Object.entries(actualVariants)
|
|
|
|
.map((entry) => formatVariantEntry(entry, data.y))
|
|
|
|
.join('\n');
|
|
|
|
},
|
|
|
|
title: (items) => {
|
|
|
|
return `Time: ${
|
|
|
|
hoursBack > 48
|
|
|
|
? formatDateYMDHM(
|
|
|
|
items[0].label,
|
|
|
|
locationSettings.locale,
|
|
|
|
'UTC',
|
|
|
|
)
|
|
|
|
: formatDateHM(
|
|
|
|
items[0].label,
|
|
|
|
locationSettings.locale,
|
|
|
|
)
|
|
|
|
}`;
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
responsive,
|
|
|
|
scales: {
|
|
|
|
x: {
|
|
|
|
...(scales ? scales.x : {}),
|
|
|
|
ticks: {
|
|
|
|
color: theme.palette.text.secondary,
|
|
|
|
callback(tickValue) {
|
|
|
|
const label = this.getLabelForValue(Number(tickValue));
|
|
|
|
return hoursBack > 48
|
|
|
|
? formatDateYMD(
|
|
|
|
label,
|
|
|
|
locationSettings.locale,
|
|
|
|
'UTC',
|
|
|
|
)
|
|
|
|
: formatDateHM(label, locationSettings.locale);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
y: scales ? scales.y : {},
|
|
|
|
},
|
|
|
|
elements,
|
|
|
|
interaction,
|
|
|
|
};
|
|
|
|
};
|