UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

294 lines (292 loc) 10.7 kB
class ChartDataUtils { /** * Normalize data points to a specific range */ static normalizeData(data, min = 0, max = 1) { if (data.length === 0) return data; const numericValues = data.map(p => typeof p.y === 'number' ? p.y : 0).filter(v => !isNaN(v)); if (numericValues.length === 0) return data; const dataMin = Math.min(...numericValues); const dataMax = Math.max(...numericValues); const range = dataMax - dataMin; if (range === 0) { return data.map(p => ({ ...p, y: typeof p.y === 'number' ? min : p.y })); } return data.map(point => { if (typeof point.y !== 'number') return point; const normalized = min + (point.y - dataMin) / range * (max - min); return { ...point, y: normalized }; }); } /** * Apply smoothing to data points using moving average */ static smoothData(data, windowSize = 3) { if (data.length < windowSize || windowSize < 2) return data; const smoothed = []; const halfWindow = Math.floor(windowSize / 2); for (let i = 0; i < data.length; i++) { const start = Math.max(0, i - halfWindow); const end = Math.min(data.length - 1, i + halfWindow); const values = []; for (let j = start; j <= end; j++) { const value = typeof data[j].y === 'number' ? data[j].y : 0; values.push(value); } const average = values.reduce((sum, val) => sum + val, 0) / values.length; smoothed.push({ ...data[i], y: typeof data[i].y === 'number' ? average : data[i].y }); } return smoothed; } /** * Remove outliers using statistical methods */ static removeOutliers(data, threshold = 2) { const numericData = data.filter(p => typeof p.y === 'number'); if (numericData.length < 4) return data; const values = numericData.map(p => p.y); const mean = values.reduce((sum, val) => sum + val, 0) / values.length; const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length; const stdDev = Math.sqrt(variance); return data.filter(point => { if (typeof point.y !== 'number') return true; return Math.abs(point.y - mean) <= threshold * stdDev; }); } /** * Aggregate data points using various methods */ static aggregateData(data, method = 'avg', windowSize = 1) { if (windowSize <= 1) return data; const aggregated = []; for (let i = 0; i < data.length; i += windowSize) { const window = data.slice(i, i + windowSize); const numericValues = window.map(p => typeof p.y === 'number' ? p.y : 0).filter(v => !isNaN(v)); if (numericValues.length === 0) continue; let aggregatedValue; switch (method) { case 'sum': aggregatedValue = numericValues.reduce((sum, val) => sum + val, 0); break; case 'avg': aggregatedValue = numericValues.reduce((sum, val) => sum + val, 0) / numericValues.length; break; case 'min': aggregatedValue = Math.min(...numericValues); break; case 'max': aggregatedValue = Math.max(...numericValues); break; case 'count': aggregatedValue = numericValues.length; break; default: aggregatedValue = numericValues[0]; } // Use the first point in the window as the base const basePoint = window[0]; aggregated.push({ ...basePoint, y: aggregatedValue, label: `${method}(${window.length})` }); } return aggregated; } /** * Sort data points by specified criteria */ static sortData(data, sortBy = 'x', order = 'asc') { return [...data].sort((a, b) => { let aValue, bValue; switch (sortBy) { case 'x': aValue = a.x; bValue = b.x; break; case 'y': aValue = typeof a.y === 'number' ? a.y : 0; bValue = typeof b.y === 'number' ? b.y : 0; break; case 'value': aValue = typeof a.y === 'number' ? a.y : a.x; bValue = typeof b.y === 'number' ? b.y : b.x; break; } // Handle different data types if (typeof aValue === 'string' && typeof bValue === 'string') { return order === 'asc' ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); } if (aValue instanceof Date && bValue instanceof Date) { return order === 'asc' ? aValue.getTime() - bValue.getTime() : bValue.getTime() - aValue.getTime(); } const numA = Number(aValue) || 0; const numB = Number(bValue) || 0; return order === 'asc' ? numA - numB : numB - numA; }); } /** * Filter data points using a predicate function */ static filterData(data, predicate) { return data.filter(predicate); } /** * Transform data points using a transformation function */ static transformData(data, transformer) { return data.map(transformer); } /** * Process data with multiple operations in sequence */ static processData(data, options) { let processed = [...data]; if (options.filter) { processed = this.filterData(processed, options.filter); } if (options.transform) { processed = this.transformData(processed, options.transform); } if (options.removeOutliers) { processed = this.removeOutliers(processed, options.outlierThreshold || 2); } if (options.smooth) { processed = this.smoothData(processed, options.smoothWindow || 3); } if (options.aggregate) { processed = this.aggregateData(processed, options.aggregateMethod || 'avg', options.aggregateWindow || 1); } if (options.normalize) { processed = this.normalizeData(processed); } if (options.sort) { processed = this.sortData(processed, options.sortBy || 'x', options.sortOrder || 'asc'); } return processed; } /** * Generate sample data for testing */ static generateSampleData(count = 20, type = 'random', range = [0, 100]) { const data = []; for (let i = 0; i < count; i++) { const x = i; let y; switch (type) { case 'linear': y = range[0] + (range[1] - range[0]) * (i / (count - 1)); break; case 'sine': y = range[0] + (range[1] - range[0]) * (Math.sin(i * 0.5) + 1) / 2; break; case 'exponential': y = range[0] + (range[1] - range[0]) * Math.pow(i / (count - 1), 2); break; case 'random': default: y = range[0] + Math.random() * (range[1] - range[0]); break; } data.push({ x, y, label: `Point ${i + 1}` }); } return data; } /** * Calculate statistical measures for data */ static calculateStatistics(data) { const numericValues = data.map(p => typeof p.y === 'number' ? p.y : 0).filter(v => !isNaN(v)).sort((a, b) => a - b); if (numericValues.length === 0) { return { mean: 0, median: 0, mode: [], variance: 0, standardDeviation: 0, min: 0, max: 0, range: 0, quartiles: [0, 0, 0] }; } const mean = numericValues.reduce((sum, val) => sum + val, 0) / numericValues.length; const median = numericValues.length % 2 === 0 ? (numericValues[numericValues.length / 2 - 1] + numericValues[numericValues.length / 2]) / 2 : numericValues[Math.floor(numericValues.length / 2)]; const variance = numericValues.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / numericValues.length; const standardDeviation = Math.sqrt(variance); const min = Math.min(...numericValues); const max = Math.max(...numericValues); const range = max - min; // Calculate quartiles const q1Index = Math.floor(numericValues.length * 0.25); const q2Index = Math.floor(numericValues.length * 0.5); const q3Index = Math.floor(numericValues.length * 0.75); const quartiles = [numericValues[q1Index], numericValues[q2Index], numericValues[q3Index]]; // Calculate mode (most frequent values) const frequency = {}; numericValues.forEach(val => { frequency[val] = (frequency[val] || 0) + 1; }); const maxFrequency = Math.max(...Object.values(frequency)); const mode = Object.keys(frequency).filter(key => frequency[Number(key)] === maxFrequency).map(Number); return { mean, median, mode, variance, standardDeviation, min, max, range, quartiles }; } /** * Detect trends in data */ static detectTrend(data) { const numericData = data.filter(p => typeof p.y === 'number'); if (numericData.length < 3) return 'stable'; const values = numericData.map(p => p.y); const diffs = []; for (let i = 1; i < values.length; i++) { diffs.push(values[i] - values[i - 1]); } const positiveDiffs = diffs.filter(d => d > 0).length; const negativeDiffs = diffs.filter(d => d < 0).length; const totalDiffs = diffs.length; const positiveRatio = positiveDiffs / totalDiffs; const negativeRatio = negativeDiffs / totalDiffs; if (positiveRatio > 0.7) return 'increasing'; if (negativeRatio > 0.7) return 'decreasing'; if (positiveRatio > 0.3 && negativeRatio > 0.3) return 'volatile'; return 'stable'; } } // Utility functions for common data processing patterns const normalizeData = (data, min, max) => ChartDataUtils.normalizeData(data, min, max); const smoothData = (data, windowSize) => ChartDataUtils.smoothData(data, windowSize); const removeOutliers = (data, threshold) => ChartDataUtils.removeOutliers(data, threshold); const aggregateData = (data, method, windowSize) => ChartDataUtils.aggregateData(data, method, windowSize); const sortData = (data, sortBy, order) => ChartDataUtils.sortData(data, sortBy, order); const filterData = (data, predicate) => ChartDataUtils.filterData(data, predicate); const transformData = (data, transformer) => ChartDataUtils.transformData(data, transformer); const processData = (data, options) => ChartDataUtils.processData(data, options); const generateSampleData = (count, type, range) => ChartDataUtils.generateSampleData(count, type, range); const calculateStatistics = data => ChartDataUtils.calculateStatistics(data); const detectTrend = data => ChartDataUtils.detectTrend(data); export { ChartDataUtils, aggregateData, calculateStatistics, detectTrend, filterData, generateSampleData, normalizeData, processData, removeOutliers, smoothData, sortData, transformData }; //# sourceMappingURL=ChartDataUtils.js.map