import { useCallback, useEffect, useId, useMemo, useRef } from 'react' import { Divider, Flex } from 'antd' import ReactECharts from 'echarts-for-react' import PropTypes from 'prop-types' import { useTooltipContext } from '../context/TooltipContext' const toCssHeight = (height) => { if (height == null) { return '100%' } if (typeof height === 'number') { return `${height}px` } return /^\d+$/.test(height) ? `${height}px` : height } const getTooltipDataIndex = (params) => { if (params.dataIndex != null) { return params.dataIndex } return ( params.dataByCoordSys?.[0]?.dataByAxis?.[0]?.seriesDataIndices?.[0] ?.dataIndex ?? null ) } const HistoryChartTooltipContent = ({ header, items }) => ( {header} {items.map(({ label, color, value }) => ( ))}
{label} {value}
) HistoryChartTooltipContent.propTypes = { header: PropTypes.string.isRequired, items: PropTypes.arrayOf( PropTypes.shape({ label: PropTypes.string.isRequired, color: PropTypes.string.isRequired, value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) .isRequired }) ).isRequired } const HistoryEChart = ({ chartRows, seriesLabels, chartType = 'bar', isDarkMode, height, formatTooltipValue }) => { const chartRef = useRef(null) const tooltipId = useId() const { showTooltip, hideTooltip } = useTooltipContext() useEffect(() => () => hideTooltip(tooltipId), [hideTooltip, tooltipId]) const handleShowTip = useCallback( (params) => { const dataIndex = getTooltipDataIndex(params) if (dataIndex == null) { return } const row = chartRows[dataIndex] if (!row) { return } const chart = chartRef.current?.getEchartsInstance() const dom = chart?.getDom() if (!dom || params.x == null || params.y == null) { return } const rect = dom.getBoundingClientRect() const items = seriesLabels.map(({ label, color }) => ({ label, color, value: formatTooltipValue ? formatTooltipValue(row[label], label) : row[label] })) showTooltip( tooltipId, , rect.left + params.x, rect.top + params.y ) }, [chartRows, seriesLabels, formatTooltipValue, showTooltip, tooltipId] ) const handleHideTip = useCallback(() => { hideTooltip(tooltipId) }, [hideTooltip, tooltipId]) const onEvents = useMemo( () => ({ showTip: handleShowTip, hideTip: handleHideTip, globalout: handleHideTip }), [handleShowTip, handleHideTip] ) const option = useMemo(() => { const axisColor = isDarkMode ? '#d9d9d9' : '#595959' const gridColor = isDarkMode ? '#303030' : '#f0f0f0' const categories = chartRows.map((row) => row.dateFormatted) return { textStyle: { fontFamily: "'DM Sans', sans-serif" }, grid: { left: 8, right: 8, top: 8, bottom: 8, containLabel: true }, tooltip: { trigger: 'axis', showContent: false, axisPointer: { type: chartType === 'line' ? 'line' : 'shadow' } }, xAxis: { type: 'category', data: categories, axisLabel: { color: axisColor, fontSize: 12 }, axisLine: { lineStyle: { color: gridColor } }, axisTick: { lineStyle: { color: gridColor } } }, yAxis: { type: 'value', axisLabel: { color: axisColor, fontSize: 12 }, splitLine: { lineStyle: { color: gridColor, type: 'dashed' } } }, series: seriesLabels.map(({ label, color }) => ({ name: label, type: chartType, stack: chartType === 'bar' ? 'history' : undefined, smooth: chartType === 'line', showSymbol: false, emphasis: { focus: 'series' }, itemStyle: { color }, lineStyle: chartType === 'line' ? { width: 2, color } : undefined, data: chartRows.map((row) => row[label] ?? 0) })) } }, [chartRows, seriesLabels, chartType, isDarkMode]) return ( ) } HistoryEChart.propTypes = { chartRows: PropTypes.arrayOf(PropTypes.object).isRequired, seriesLabels: PropTypes.arrayOf( PropTypes.shape({ label: PropTypes.string.isRequired, color: PropTypes.string.isRequired }) ).isRequired, chartType: PropTypes.oneOf(['line', 'bar']), isDarkMode: PropTypes.bool, height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), formatTooltipValue: PropTypes.func } export default HistoryEChart