66 lines
1.9 KiB
TypeScript
66 lines
1.9 KiB
TypeScript
'use client'
|
|
|
|
import React from 'react'
|
|
|
|
interface ChartDataPoint {
|
|
value: number
|
|
label?: string
|
|
timestamp?: string
|
|
}
|
|
|
|
interface AreaChartProps {
|
|
className?: string
|
|
data?: ChartDataPoint[]
|
|
}
|
|
|
|
const AreaChart: React.FC<AreaChartProps> = ({ className = '', data }) => {
|
|
const width = 635
|
|
const height = 200
|
|
const paddingBottom = 20
|
|
const baselineY = height - paddingBottom
|
|
const maxPlotHeight = height - 40
|
|
|
|
const safeData = (Array.isArray(data) && data.length > 0)
|
|
? data
|
|
: [
|
|
{ value: 5 },
|
|
{ value: 3 },
|
|
{ value: 7 },
|
|
{ value: 2 },
|
|
{ value: 6 },
|
|
{ value: 4 },
|
|
{ value: 8 }
|
|
]
|
|
|
|
const maxVal = Math.max(...safeData.map(d => d.value || 0), 1)
|
|
const stepX = safeData.length > 1 ? width / (safeData.length - 1) : width
|
|
|
|
const points = safeData.map((d, i) => {
|
|
const x = i * stepX
|
|
const y = baselineY - (Math.min(d.value || 0, maxVal) / maxVal) * maxPlotHeight
|
|
return { x, y }
|
|
})
|
|
|
|
const linePath = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' ')
|
|
const areaPath = `${linePath} L${width},${baselineY} L0,${baselineY} Z`
|
|
|
|
return (
|
|
<div className={`w-full h-full ${className}`}>
|
|
<svg className="w-full h-full" viewBox={`0 0 ${width} ${height}`}>
|
|
<defs>
|
|
<linearGradient id="areaGradient" x1="0" y1="0" x2="0" y2="1">
|
|
<stop offset="0%" stopColor="rgb(42, 157, 144)" stopOpacity="0.3" />
|
|
<stop offset="100%" stopColor="rgb(42, 157, 144)" stopOpacity="0" />
|
|
</linearGradient>
|
|
</defs>
|
|
<path d={areaPath} fill="url(#areaGradient)" />
|
|
<path d={linePath} stroke="rgb(42, 157, 144)" strokeWidth="2" fill="none" />
|
|
{points.map((p, i) => (
|
|
<circle key={i} cx={p.x} cy={p.y} r="3" fill="rgb(42, 157, 144)" />
|
|
))}
|
|
</svg>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default AreaChart |