UNPKG

@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
"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, } }