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