@moontra/moonui-pro
Version:
Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components
206 lines (176 loc) • 5.97 kB
text/typescript
"use client"
import React from 'react'
import { ChartDataPoint, ChartSeries } from '../components/advanced-chart'
interface UseChartOptions {
data: ChartDataPoint[]
series: ChartSeries[]
realtime?: boolean
refreshInterval?: number
maxDataPoints?: number
}
interface UseChartReturn {
data: ChartDataPoint[]
series: ChartSeries[]
isLoading: boolean
error: string | null
addDataPoint: (point: ChartDataPoint) => void
updateSeries: (seriesUpdate: Partial<ChartSeries>[]) => void
toggleSeries: (dataKey: string) => void
resetData: () => void
exportData: (format: 'csv' | 'json') => void
getStats: () => {
total: number
average: number
min: number
max: number
trend: 'up' | 'down' | 'neutral'
}
}
export function useChart({
data: initialData,
series: initialSeries,
realtime = false,
refreshInterval = 5000,
maxDataPoints = 100,
}: UseChartOptions): UseChartReturn {
const [data, setData] = React.useState<ChartDataPoint[]>(initialData)
const [series, setSeries] = React.useState<ChartSeries[]>(initialSeries)
const [isLoading, setIsLoading] = React.useState(false)
const [error, setError] = React.useState<string | null>(null)
// Realtime data updates
React.useEffect(() => {
if (!realtime) return
const interval = setInterval(() => {
// This would typically fetch new data from an API
// For demo purposes, we'll simulate data updates
setData(prevData => {
const newData = [...prevData]
// Keep only the last maxDataPoints
if (newData.length >= maxDataPoints) {
newData.shift()
}
// Add simulated new data point
const lastPoint = newData[newData.length - 1]
if (lastPoint) {
const newPoint: ChartDataPoint = { ...lastPoint }
// Simulate data changes for each series
series.forEach(s => {
if (typeof lastPoint[s.dataKey] === 'number') {
const currentValue = lastPoint[s.dataKey] as number
const change = (Math.random() - 0.5) * currentValue * 0.1
newPoint[s.dataKey] = Math.max(0, currentValue + change)
}
})
// Update timestamp if exists
if ('timestamp' in newPoint) {
newPoint.timestamp = Date.now()
}
newData.push(newPoint)
}
return newData
})
}, refreshInterval)
return () => clearInterval(interval)
}, [realtime, refreshInterval, maxDataPoints, series])
const addDataPoint = React.useCallback((point: ChartDataPoint) => {
setData(prevData => {
const newData = [...prevData, point]
// Keep only the last maxDataPoints
if (newData.length > maxDataPoints) {
return newData.slice(-maxDataPoints)
}
return newData
})
}, [maxDataPoints])
const updateSeries = React.useCallback((seriesUpdate: Partial<ChartSeries>[]) => {
setSeries(prevSeries => {
return prevSeries.map(s => {
const update = seriesUpdate.find(u => u.dataKey === s.dataKey)
return update ? { ...s, ...update } : s
})
})
}, [])
const toggleSeries = React.useCallback((dataKey: string) => {
setSeries(prevSeries => {
return prevSeries.map(s =>
s.dataKey === dataKey ? { ...s, hide: !s.hide } : s
)
})
}, [])
const resetData = React.useCallback(() => {
setData(initialData)
setSeries(initialSeries)
setError(null)
}, [initialData, initialSeries])
const exportData = React.useCallback((format: 'csv' | 'json') => {
try {
if (format === 'csv') {
const headers = Object.keys(data[0] || {})
const csvContent = [
headers.join(','),
...data.map(row =>
headers.map(header => {
const value = row[header]
if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) {
return `"${value.replace(/"/g, '""')}"`
}
return value
}).join(',')
)
].join('\n')
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = 'chart-data.csv'
link.click()
} else if (format === 'json') {
const jsonContent = JSON.stringify({ data, series }, null, 2)
const blob = new Blob([jsonContent], { type: 'application/json;charset=utf-8;' })
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = 'chart-data.json'
link.click()
}
} catch (err) {
setError('Failed to export data')
}
}, [data, series])
const getStats = React.useCallback(() => {
if (!data.length || !series.length) {
return { total: 0, average: 0, min: 0, max: 0, trend: 'neutral' as const }
}
const firstSeries = series[0]
const values = data
.map(d => Number(d[firstSeries.dataKey]))
.filter(v => !isNaN(v))
if (!values.length) {
return { total: 0, average: 0, min: 0, max: 0, trend: 'neutral' as const }
}
const total = values.reduce((sum, val) => sum + val, 0)
const average = total / values.length
const min = Math.min(...values)
const max = Math.max(...values)
// Calculate trend
let trend: 'up' | 'down' | 'neutral' = 'neutral'
if (values.length >= 2) {
const first = values[0]
const last = values[values.length - 1]
const change = ((last - first) / first) * 100
if (change > 5) trend = 'up'
else if (change < -5) trend = 'down'
}
return { total, average, min, max, trend }
}, [data, series])
return {
data,
series,
isLoading,
error,
addDataPoint,
updateSeries,
toggleSeries,
resetData,
exportData,
getStats,
}
}