128 lines
3.3 KiB
TypeScript
128 lines
3.3 KiB
TypeScript
import React, { useEffect, useRef, useCallback } from 'react';
|
|
import { View, Text } from '@tarojs/components';
|
|
import EcCanvas from '../EcCanvas';
|
|
import type { EcCanvasRef } from '../EcCanvas';
|
|
import './index.scss';
|
|
|
|
interface TrendChartProps {
|
|
data: { date: string; value: number }[];
|
|
referenceMin?: number;
|
|
referenceMax?: number;
|
|
unit?: string;
|
|
height?: number;
|
|
}
|
|
|
|
export default function TrendChart({
|
|
data,
|
|
referenceMin,
|
|
referenceMax,
|
|
unit = '',
|
|
height = 500,
|
|
}: TrendChartProps) {
|
|
const chartRef = useRef<EcCanvasRef>(null);
|
|
|
|
const getOption = useCallback(() => {
|
|
if (!data || data.length === 0) return null;
|
|
|
|
const series: any[] = [];
|
|
const markArea: any = {};
|
|
|
|
if (referenceMin != null && referenceMax != null) {
|
|
markArea.data = [
|
|
[
|
|
{
|
|
yAxis: referenceMin,
|
|
itemStyle: { color: 'rgba(5,150,105,0.08)' },
|
|
},
|
|
{ yAxis: referenceMax },
|
|
],
|
|
];
|
|
}
|
|
|
|
series.push({
|
|
type: 'line',
|
|
data: data.map((d) => d.value),
|
|
smooth: true,
|
|
symbol: 'circle',
|
|
symbolSize: 6,
|
|
lineStyle: { color: '#0891B2', width: 2 },
|
|
itemStyle: { color: '#0891B2' },
|
|
areaStyle: {
|
|
color: {
|
|
type: 'linear',
|
|
x: 0,
|
|
y: 0,
|
|
x2: 0,
|
|
y2: 1,
|
|
colorStops: [
|
|
{ offset: 0, color: 'rgba(8,145,178,0.15)' },
|
|
{ offset: 1, color: 'rgba(8,145,178,0.01)' },
|
|
],
|
|
},
|
|
},
|
|
markArea: markArea.data
|
|
? { silent: true, data: markArea.data }
|
|
: undefined,
|
|
markPoint:
|
|
referenceMin != null && referenceMax != null
|
|
? {
|
|
data: data
|
|
.filter((d) => d.value < referenceMin || d.value > referenceMax)
|
|
.map((d) => ({
|
|
coord: [data.indexOf(d), d.value],
|
|
itemStyle: { color: '#DC2626' },
|
|
symbolSize: 12,
|
|
})),
|
|
}
|
|
: undefined,
|
|
});
|
|
|
|
return {
|
|
grid: { left: 45, right: 15, top: 20, bottom: 30 },
|
|
xAxis: {
|
|
type: 'category',
|
|
data: data.map((d) => d.date.slice(5)),
|
|
axisLabel: { fontSize: 10, color: '#94A3B8' },
|
|
axisLine: { lineStyle: { color: '#E5E7EB' } },
|
|
},
|
|
yAxis: {
|
|
type: 'value',
|
|
axisLabel: { fontSize: 10, color: '#94A3B8' },
|
|
splitLine: { lineStyle: { color: '#F3F4F6' } },
|
|
},
|
|
tooltip: {
|
|
trigger: 'axis',
|
|
formatter: (params: any) => {
|
|
const p = params[0];
|
|
const idx = p.dataIndex;
|
|
return `${data[idx]?.date || ''}\n${p.value}${unit ? ' ' + unit : ''}`;
|
|
},
|
|
},
|
|
series,
|
|
};
|
|
}, [data, referenceMin, referenceMax, unit]);
|
|
|
|
useEffect(() => {
|
|
if (chartRef.current && data && data.length > 0) {
|
|
const option = getOption();
|
|
if (option) {
|
|
chartRef.current.setOption(option);
|
|
}
|
|
}
|
|
}, [data, getOption]);
|
|
|
|
if (!data || data.length === 0) {
|
|
return (
|
|
<View className='trend-chart-empty'>
|
|
<Text className='trend-chart-empty-text'>暂无数据</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<View className='trend-chart' style={{ height: `${height}rpx` }}>
|
|
<EcCanvas canvasId='trend-chart-canvas' ref={chartRef} height={height} />
|
|
</View>
|
|
);
|
|
}
|