@smartnet360/svelte-components 0.0.29 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/Charts/ChartCard.svelte +11 -8
- package/dist/core/Charts/ChartCard.svelte.d.ts +2 -1
- package/dist/core/Charts/ChartComponent.svelte +7 -2
- package/dist/core/Charts/data-processor.d.ts +43 -0
- package/dist/core/Charts/data-processor.js +89 -0
- package/dist/core/Charts/data-utils.d.ts +4 -5
- package/dist/core/Charts/data-utils.js +5 -10
- package/dist/core/Charts/index.d.ts +2 -0
- package/dist/core/Charts/index.js +1 -0
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import type { Chart as ChartModel, ChartMarker, MovingAverageConfig } from './charts.model.js';
|
|
7
7
|
import { createTimeSeriesTraceWithMA, getYAxisTitle, createDefaultPlotlyLayout } from './data-utils.js';
|
|
8
8
|
import { adaptPlotlyLayout, addMarkersToLayout, type ContainerSize } from './adapt.js';
|
|
9
|
+
import { getKPIValues, type ProcessedChartData } from './data-processor.js';
|
|
9
10
|
|
|
10
11
|
const dispatch = createEventDispatcher<{
|
|
11
12
|
chartcontextmenu: {
|
|
@@ -18,7 +19,7 @@
|
|
|
18
19
|
|
|
19
20
|
interface Props {
|
|
20
21
|
chart: ChartModel;
|
|
21
|
-
|
|
22
|
+
processedData: ProcessedChartData; // Pre-processed KPI values and timestamps
|
|
22
23
|
markers?: ChartMarker[]; // Global markers for all charts
|
|
23
24
|
plotlyLayout?: any; // Optional custom Plotly layout for styling/theming
|
|
24
25
|
enableAdaptation?: boolean; // Enable size-based adaptations (default: true)
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
runtimeShowLegend?: boolean; // Runtime control for showing legend (default: true)
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
let { chart,
|
|
35
|
+
let { chart, processedData, markers, plotlyLayout, enableAdaptation = true, sectionId, sectionMovingAverage, layoutMovingAverage, runtimeMAOverride, runtimeShowOriginal, runtimeShowMarkers = true, runtimeShowLegend = true }: Props = $props();
|
|
35
36
|
|
|
36
37
|
// Chart container div and state
|
|
37
38
|
let chartDiv: HTMLElement;
|
|
@@ -145,25 +146,27 @@
|
|
|
145
146
|
};
|
|
146
147
|
});
|
|
147
148
|
|
|
148
|
-
//
|
|
149
|
-
let timestamps = $derived(
|
|
149
|
+
// Timestamps are already extracted in processedData
|
|
150
|
+
let timestamps = $derived(processedData.timestamps);
|
|
150
151
|
|
|
151
152
|
function renderChart() {
|
|
152
|
-
if (!chartDiv || !
|
|
153
|
+
if (!chartDiv || !processedData?.kpiValues.size) return;
|
|
153
154
|
|
|
154
155
|
const traces: any[] = [];
|
|
155
156
|
let colorIndex = 0;
|
|
156
157
|
|
|
157
158
|
// Add left Y-axis traces (with moving average support)
|
|
158
159
|
resolvedKPIs.left.forEach(kpi => {
|
|
159
|
-
const
|
|
160
|
+
const values = getKPIValues(processedData, kpi);
|
|
161
|
+
const kpiTraces = createTimeSeriesTraceWithMA(values, timestamps, kpi, 'y1', colorIndex);
|
|
160
162
|
traces.push(...kpiTraces);
|
|
161
163
|
colorIndex++;
|
|
162
164
|
});
|
|
163
165
|
|
|
164
166
|
// Add right Y-axis traces (with moving average support)
|
|
165
167
|
resolvedKPIs.right.forEach(kpi => {
|
|
166
|
-
const
|
|
168
|
+
const values = getKPIValues(processedData, kpi);
|
|
169
|
+
const kpiTraces = createTimeSeriesTraceWithMA(values, timestamps, kpi, 'y2', colorIndex);
|
|
167
170
|
traces.push(...kpiTraces);
|
|
168
171
|
colorIndex++;
|
|
169
172
|
});
|
|
@@ -294,7 +297,7 @@
|
|
|
294
297
|
// React to prop changes - debounce re-renders for better performance
|
|
295
298
|
$effect(() => {
|
|
296
299
|
// Watch these props and re-render when they change
|
|
297
|
-
const
|
|
300
|
+
const currentProcessedData = processedData;
|
|
298
301
|
const currentMarkers = markers;
|
|
299
302
|
const currentMAOverride = runtimeMAOverride;
|
|
300
303
|
const currentShowOriginal = runtimeShowOriginal;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Chart as ChartModel, ChartMarker, MovingAverageConfig } from './charts.model.js';
|
|
2
|
+
import { type ProcessedChartData } from './data-processor.js';
|
|
2
3
|
interface Props {
|
|
3
4
|
chart: ChartModel;
|
|
4
|
-
|
|
5
|
+
processedData: ProcessedChartData;
|
|
5
6
|
markers?: ChartMarker[];
|
|
6
7
|
plotlyLayout?: any;
|
|
7
8
|
enableAdaptation?: boolean;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { Layout, Mode, ChartMarker, Section, ChartGrid, Chart, GlobalChartControls, MovingAverageConfig } from './charts.model.js';
|
|
6
6
|
import ChartCard from './ChartCard.svelte';
|
|
7
7
|
import GlobalControls from './GlobalControls.svelte';
|
|
8
|
+
import { getPreprocessedData, type ProcessedChartData } from './data-processor.js';
|
|
8
9
|
|
|
9
10
|
interface Props {
|
|
10
11
|
layout: Layout;
|
|
@@ -54,6 +55,10 @@
|
|
|
54
55
|
|
|
55
56
|
let { layout, data, mode, markers, plotlyLayout, enableAdaptation = true, showGlobalControls = true }: Props = $props();
|
|
56
57
|
|
|
58
|
+
// Preprocess raw data once - automatically memoized by Svelte's $derived
|
|
59
|
+
// This extracts all KPI values and timestamps, cached until data or layout changes
|
|
60
|
+
let processedData = $derived(getPreprocessedData(data, layout));
|
|
61
|
+
|
|
57
62
|
// Global runtime controls state - initialize from layout config
|
|
58
63
|
let globalControls = $state<GlobalChartControls>({
|
|
59
64
|
movingAverage: {
|
|
@@ -291,7 +296,7 @@
|
|
|
291
296
|
<div class="chart-slot">
|
|
292
297
|
<ChartCard
|
|
293
298
|
{chart}
|
|
294
|
-
{
|
|
299
|
+
{processedData}
|
|
295
300
|
{markers}
|
|
296
301
|
{plotlyLayout}
|
|
297
302
|
{enableAdaptation}
|
|
@@ -433,7 +438,7 @@
|
|
|
433
438
|
</button>
|
|
434
439
|
<ChartCard
|
|
435
440
|
chart={activeZoom.chart}
|
|
436
|
-
{
|
|
441
|
+
{processedData}
|
|
437
442
|
{markers}
|
|
438
443
|
{plotlyLayout}
|
|
439
444
|
{enableAdaptation}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Layout, KPI } from './charts.model.js';
|
|
2
|
+
/**
|
|
3
|
+
* Preprocessed chart data structure
|
|
4
|
+
* Contains extracted numeric values and timestamps, ready for chart rendering
|
|
5
|
+
*/
|
|
6
|
+
export interface ProcessedChartData {
|
|
7
|
+
/** Map of KPI rawName to numeric values array */
|
|
8
|
+
kpiValues: Map<string, number[]>;
|
|
9
|
+
/** Extracted timestamps array */
|
|
10
|
+
timestamps: any[];
|
|
11
|
+
/** Original raw data reference (for cache invalidation) */
|
|
12
|
+
_rawDataRef: any[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Extract all unique KPI rawNames from a layout configuration
|
|
16
|
+
* This determines which columns we need to extract from raw data
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractKPINames(layout: Layout): Set<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Process raw data into numeric arrays for each KPI
|
|
21
|
+
* Handles type conversion and filtering of invalid values
|
|
22
|
+
*
|
|
23
|
+
* @param data - Raw data array from API/database
|
|
24
|
+
* @param layout - Chart layout configuration containing all KPIs
|
|
25
|
+
* @param timestampField - Name of timestamp field in raw data (default: 'TIMESTAMP')
|
|
26
|
+
* @returns Preprocessed data ready for chart rendering
|
|
27
|
+
*/
|
|
28
|
+
export declare function preprocessChartData(data: any[], layout: Layout, timestampField?: string): ProcessedChartData;
|
|
29
|
+
/**
|
|
30
|
+
* Get preprocessed chart data with automatic caching
|
|
31
|
+
* Returns cached result if raw data hasn't changed
|
|
32
|
+
*
|
|
33
|
+
* @param data - Raw data array
|
|
34
|
+
* @param layout - Chart layout configuration
|
|
35
|
+
* @param timestampField - Name of timestamp field (default: 'TIMESTAMP')
|
|
36
|
+
* @returns Preprocessed data (cached or freshly computed)
|
|
37
|
+
*/
|
|
38
|
+
export declare function getPreprocessedData(data: any[], layout: Layout, timestampField?: string): ProcessedChartData;
|
|
39
|
+
/**
|
|
40
|
+
* Helper to get values for a specific KPI from preprocessed data
|
|
41
|
+
* Returns empty array if KPI not found
|
|
42
|
+
*/
|
|
43
|
+
export declare function getKPIValues(processedData: ProcessedChartData, kpi: KPI): number[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract all unique KPI rawNames from a layout configuration
|
|
3
|
+
* This determines which columns we need to extract from raw data
|
|
4
|
+
*/
|
|
5
|
+
export function extractKPINames(layout) {
|
|
6
|
+
const kpiNames = new Set();
|
|
7
|
+
for (const section of layout.sections) {
|
|
8
|
+
for (const chart of section.charts) {
|
|
9
|
+
// Collect from left Y-axis KPIs
|
|
10
|
+
for (const kpi of chart.yLeft) {
|
|
11
|
+
kpiNames.add(kpi.rawName);
|
|
12
|
+
}
|
|
13
|
+
// Collect from right Y-axis KPIs
|
|
14
|
+
for (const kpi of chart.yRight) {
|
|
15
|
+
kpiNames.add(kpi.rawName);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return kpiNames;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Process raw data into numeric arrays for each KPI
|
|
23
|
+
* Handles type conversion and filtering of invalid values
|
|
24
|
+
*
|
|
25
|
+
* @param data - Raw data array from API/database
|
|
26
|
+
* @param layout - Chart layout configuration containing all KPIs
|
|
27
|
+
* @param timestampField - Name of timestamp field in raw data (default: 'TIMESTAMP')
|
|
28
|
+
* @returns Preprocessed data ready for chart rendering
|
|
29
|
+
*/
|
|
30
|
+
export function preprocessChartData(data, layout, timestampField = 'TIMESTAMP') {
|
|
31
|
+
// Extract all unique KPI names we need to process
|
|
32
|
+
const kpiNames = extractKPINames(layout);
|
|
33
|
+
// Initialize the result map
|
|
34
|
+
const kpiValues = new Map();
|
|
35
|
+
// Process each KPI column
|
|
36
|
+
for (const kpiName of kpiNames) {
|
|
37
|
+
const values = data
|
|
38
|
+
.map(row => {
|
|
39
|
+
const val = row[kpiName];
|
|
40
|
+
// Convert to number if it's a string, return as-is if already a number
|
|
41
|
+
return typeof val === 'number' ? val : parseFloat(val);
|
|
42
|
+
})
|
|
43
|
+
.filter(val => !isNaN(val)); // Remove invalid values
|
|
44
|
+
kpiValues.set(kpiName, values);
|
|
45
|
+
}
|
|
46
|
+
// Extract timestamps once
|
|
47
|
+
const timestamps = data.map(row => row[timestampField]);
|
|
48
|
+
return {
|
|
49
|
+
kpiValues,
|
|
50
|
+
timestamps,
|
|
51
|
+
_rawDataRef: data // Keep reference for cache invalidation
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Memoized wrapper for preprocessChartData
|
|
56
|
+
* Uses WeakMap to cache results by raw data reference
|
|
57
|
+
* Cache is automatically garbage collected when raw data is no longer referenced
|
|
58
|
+
*/
|
|
59
|
+
const preprocessCache = new WeakMap();
|
|
60
|
+
/**
|
|
61
|
+
* Get preprocessed chart data with automatic caching
|
|
62
|
+
* Returns cached result if raw data hasn't changed
|
|
63
|
+
*
|
|
64
|
+
* @param data - Raw data array
|
|
65
|
+
* @param layout - Chart layout configuration
|
|
66
|
+
* @param timestampField - Name of timestamp field (default: 'TIMESTAMP')
|
|
67
|
+
* @returns Preprocessed data (cached or freshly computed)
|
|
68
|
+
*/
|
|
69
|
+
export function getPreprocessedData(data, layout, timestampField = 'TIMESTAMP') {
|
|
70
|
+
// Check cache first
|
|
71
|
+
const cached = preprocessCache.get(data);
|
|
72
|
+
if (cached) {
|
|
73
|
+
// Verify cache is still valid (data reference matches)
|
|
74
|
+
if (cached._rawDataRef === data) {
|
|
75
|
+
return cached;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Cache miss or invalid - compute and cache
|
|
79
|
+
const processed = preprocessChartData(data, layout, timestampField);
|
|
80
|
+
preprocessCache.set(data, processed);
|
|
81
|
+
return processed;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Helper to get values for a specific KPI from preprocessed data
|
|
85
|
+
* Returns empty array if KPI not found
|
|
86
|
+
*/
|
|
87
|
+
export function getKPIValues(processedData, kpi) {
|
|
88
|
+
return processedData.kpiValues.get(kpi.rawName) || [];
|
|
89
|
+
}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import type { KPI } from './charts.model.js';
|
|
2
2
|
export declare function processKPIData(data: any[], kpi: KPI): number[];
|
|
3
3
|
export declare function calculateMovingAverage(values: number[], window: number): number[];
|
|
4
|
-
export declare function createTimeSeriesTrace(
|
|
4
|
+
export declare function createTimeSeriesTrace(values: number[], timestamps: any[], kpi: KPI, yaxis?: 'y1' | 'y2', colorIndex?: number): any;
|
|
5
5
|
/**
|
|
6
6
|
* Create time series trace(s) with optional moving average
|
|
7
|
-
* @param
|
|
7
|
+
* @param values - Pre-processed numeric values array for the KPI
|
|
8
|
+
* @param timestamps - Pre-extracted timestamps array
|
|
8
9
|
* @param kpi - KPI configuration (may include movingAverage config)
|
|
9
|
-
* @param timestampField - Field name for timestamp column
|
|
10
10
|
* @param yaxis - Which Y-axis to use ('y1' or 'y2')
|
|
11
11
|
* @param colorIndex - Index for color selection
|
|
12
|
-
* @param precomputedTimestamps - Optional pre-extracted timestamps array (performance optimization)
|
|
13
12
|
* @returns Array of traces (original + MA if configured)
|
|
14
13
|
*/
|
|
15
|
-
export declare function createTimeSeriesTraceWithMA(
|
|
14
|
+
export declare function createTimeSeriesTraceWithMA(values: number[], timestamps: any[], kpi: KPI, yaxis?: 'y1' | 'y2', colorIndex?: number): any[];
|
|
16
15
|
export declare function getYAxisTitle(kpis: KPI[]): string;
|
|
17
16
|
export declare function formatValue(value: number, scale: 'percent' | 'absolute', unit: string): string;
|
|
18
17
|
export declare function createDefaultPlotlyLayout(title?: string): any;
|
|
@@ -72,9 +72,7 @@ export function calculateMovingAverage(values, window) {
|
|
|
72
72
|
maCache.set(cacheKey, result);
|
|
73
73
|
return result;
|
|
74
74
|
}
|
|
75
|
-
export function createTimeSeriesTrace(
|
|
76
|
-
const values = processKPIData(data, kpi);
|
|
77
|
-
const timestamps = data.map(row => row[timestampField]);
|
|
75
|
+
export function createTimeSeriesTrace(values, timestamps, kpi, yaxis = 'y1', colorIndex = 0) {
|
|
78
76
|
// Use KPI color if provided, otherwise cycle through modern colors
|
|
79
77
|
const traceColor = kpi.color || modernColors[colorIndex % modernColors.length];
|
|
80
78
|
return {
|
|
@@ -98,22 +96,19 @@ export function createTimeSeriesTrace(data, kpi, timestampField = 'TIMESTAMP', y
|
|
|
98
96
|
}
|
|
99
97
|
/**
|
|
100
98
|
* Create time series trace(s) with optional moving average
|
|
101
|
-
* @param
|
|
99
|
+
* @param values - Pre-processed numeric values array for the KPI
|
|
100
|
+
* @param timestamps - Pre-extracted timestamps array
|
|
102
101
|
* @param kpi - KPI configuration (may include movingAverage config)
|
|
103
|
-
* @param timestampField - Field name for timestamp column
|
|
104
102
|
* @param yaxis - Which Y-axis to use ('y1' or 'y2')
|
|
105
103
|
* @param colorIndex - Index for color selection
|
|
106
|
-
* @param precomputedTimestamps - Optional pre-extracted timestamps array (performance optimization)
|
|
107
104
|
* @returns Array of traces (original + MA if configured)
|
|
108
105
|
*/
|
|
109
|
-
export function createTimeSeriesTraceWithMA(
|
|
106
|
+
export function createTimeSeriesTraceWithMA(values, timestamps, kpi, yaxis = 'y1', colorIndex = 0) {
|
|
110
107
|
const traces = [];
|
|
111
|
-
const values = processKPIData(data, kpi);
|
|
112
|
-
const timestamps = precomputedTimestamps || data.map(row => row[timestampField]);
|
|
113
108
|
const traceColor = kpi.color || modernColors[colorIndex % modernColors.length];
|
|
114
109
|
// Add original trace (unless explicitly disabled)
|
|
115
110
|
if (!kpi.movingAverage || kpi.movingAverage.showOriginal !== false) {
|
|
116
|
-
const originalTrace = createTimeSeriesTrace(
|
|
111
|
+
const originalTrace = createTimeSeriesTrace(values, timestamps, kpi, yaxis, colorIndex);
|
|
117
112
|
// If MA is enabled, make the original line slightly transparent
|
|
118
113
|
if (kpi.movingAverage?.enabled) {
|
|
119
114
|
originalTrace.opacity = 0.4;
|
|
@@ -4,6 +4,8 @@ export type { Layout, Section, Chart, KPI, Mode, Scale, ChartMarker, ChartGrid,
|
|
|
4
4
|
export { createTimeSeriesTrace, getYAxisTitle, formatValue, processKPIData, createDefaultPlotlyLayout } from './data-utils.js';
|
|
5
5
|
export { adaptPlotlyLayout, getSizeCategory, createMarkerShapes, createMarkerAnnotations, addMarkersToLayout } from './adapt.js';
|
|
6
6
|
export type { ContainerSize, ChartInfo, AdaptationConfig } from './adapt.js';
|
|
7
|
+
export { getPreprocessedData, extractKPINames, getKPIValues, preprocessChartData } from './data-processor.js';
|
|
8
|
+
export type { ProcessedChartData } from './data-processor.js';
|
|
7
9
|
export { default as ChartLayoutEditor } from './editor/ChartLayoutEditor.svelte';
|
|
8
10
|
export { editorStore, currentLayout, savedLayouts, selection, isDirty, selectedItem } from './editor/editorState.js';
|
|
9
11
|
export type { Selection, SelectionType, EditorState } from './editor/editorState.js';
|
|
@@ -2,6 +2,7 @@ export { default as ChartComponent } from './ChartComponent.svelte';
|
|
|
2
2
|
export { default as ChartCard } from './ChartCard.svelte';
|
|
3
3
|
export { createTimeSeriesTrace, getYAxisTitle, formatValue, processKPIData, createDefaultPlotlyLayout } from './data-utils.js';
|
|
4
4
|
export { adaptPlotlyLayout, getSizeCategory, createMarkerShapes, createMarkerAnnotations, addMarkersToLayout } from './adapt.js';
|
|
5
|
+
export { getPreprocessedData, extractKPINames, getKPIValues, preprocessChartData } from './data-processor.js';
|
|
5
6
|
// Editor exports
|
|
6
7
|
export { default as ChartLayoutEditor } from './editor/ChartLayoutEditor.svelte';
|
|
7
8
|
export { editorStore, currentLayout, savedLayouts, selection, isDirty, selectedItem } from './editor/editorState.js';
|