import { useState, useRef, useEffect, useCallback } from 'react'; import { Loading } from 'react-basics'; import classNames from 'classnames'; import Chart from 'chart.js/auto'; import HoverTooltip from 'components/common/HoverTooltip'; import Legend from 'components/metrics/Legend'; import { formatLongNumber } from 'lib/format'; import useLocale from 'hooks/useLocale'; import useTheme from 'hooks/useTheme'; import { DEFAULT_ANIMATION_DURATION } from 'lib/constants'; import styles from './BarChart.module.css'; function defaultRenderYLabel(label) { return +label > 1000 ? formatLongNumber(label) : label; } export function BarChart({ datasets, unit, animationDuration = DEFAULT_ANIMATION_DURATION, stacked = false, loading = false, renderXLabel, renderYLabel, XAxisType = 'time', YAxisType = 'linear', renderTooltip, onCreate, onUpdate, className, }) { const canvas = useRef(); const chart = useRef(null); const [tooltip, setTooltip] = useState(null); const { locale } = useLocale(); const { theme, colors } = useTheme(); const getOptions = useCallback(() => { return { responsive: true, maintainAspectRatio: false, animation: { duration: animationDuration, resize: { duration: 0, }, active: { duration: 0, }, }, plugins: { legend: { display: false, }, tooltip: { enabled: false, external: renderTooltip ? renderTooltip.bind(null, setTooltip) : undefined, }, }, scales: { x: { type: XAxisType, stacked: true, time: { unit, }, grid: { display: false, }, border: { color: colors.chart.line, }, ticks: { color: colors.chart.text, autoSkip: false, maxRotation: 0, callback: renderXLabel, }, }, y: { type: YAxisType, min: 0, beginAtZero: true, stacked, grid: { color: colors.chart.line, }, border: { color: colors.chart.line, }, ticks: { color: colors.text, callback: renderYLabel || defaultRenderYLabel, }, }, }, }; }, [ animationDuration, renderTooltip, renderXLabel, XAxisType, YAxisType, stacked, colors, unit, locale, ]); const createChart = () => { Chart.defaults.font.family = 'Inter'; const options = getOptions(); chart.current = new Chart(canvas.current, { type: 'bar', data: { datasets, }, options, }); onCreate?.(chart.current); }; const updateChart = () => { setTooltip(null); datasets.forEach((dataset, index) => { chart.current.data.datasets[index].data = dataset.data; chart.current.data.datasets[index].label = dataset.label; }); chart.current.options = getOptions(); onUpdate?.(chart.current); chart.current.update(); }; useEffect(() => { if (datasets) { if (!chart.current) { createChart(); } else { updateChart(); } } }, [datasets, unit, theme, animationDuration, locale]); return ( <>
{loading && }
{tooltip && (
{tooltip}
)} ); } export default BarChart;