@constela/core 0.18.2 → 0.18.3
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/index.d.ts +121 -1
- package/dist/index.js +447 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2438,4 +2438,124 @@ declare function isSuspenseBoundary(value: unknown): value is SuspenseBoundary;
|
|
|
2438
2438
|
*/
|
|
2439
2439
|
declare function isStreamChunk(value: unknown): value is StreamChunk;
|
|
2440
2440
|
|
|
2441
|
-
|
|
2441
|
+
/**
|
|
2442
|
+
* Chart Helper Functions
|
|
2443
|
+
*
|
|
2444
|
+
* Shared chart helper functions used by both @constela/runtime and @constela/server.
|
|
2445
|
+
* These are pure functions with no DOM dependencies.
|
|
2446
|
+
*/
|
|
2447
|
+
/**
|
|
2448
|
+
* Normalizes a value to 0-1 range
|
|
2449
|
+
*/
|
|
2450
|
+
declare function normalizeValue(value: unknown, min: unknown, max: unknown): number | undefined;
|
|
2451
|
+
/**
|
|
2452
|
+
* Scales a value from one range to another
|
|
2453
|
+
*/
|
|
2454
|
+
declare function scaleValue(value: unknown, domainMin: unknown, domainMax: unknown, rangeMin: unknown, rangeMax: unknown): number | undefined;
|
|
2455
|
+
/**
|
|
2456
|
+
* Finds min and max values in data
|
|
2457
|
+
*/
|
|
2458
|
+
declare function getChartBounds(data: unknown, valueKey: unknown): {
|
|
2459
|
+
min: number;
|
|
2460
|
+
max: number;
|
|
2461
|
+
} | undefined;
|
|
2462
|
+
/**
|
|
2463
|
+
* Calculates bar dimensions for bar chart
|
|
2464
|
+
*/
|
|
2465
|
+
declare function getBarDimensions(data: unknown, index: unknown, width: unknown, height: unknown, gap: unknown, orientation: unknown): {
|
|
2466
|
+
x: number;
|
|
2467
|
+
y: number;
|
|
2468
|
+
width: number;
|
|
2469
|
+
height: number;
|
|
2470
|
+
} | undefined;
|
|
2471
|
+
/**
|
|
2472
|
+
* Generates SVG path string for line chart
|
|
2473
|
+
*/
|
|
2474
|
+
declare function getLinePath(points: unknown, curved?: unknown): string | undefined;
|
|
2475
|
+
/**
|
|
2476
|
+
* Generates SVG path string for area chart
|
|
2477
|
+
*/
|
|
2478
|
+
declare function getAreaPath(points: unknown, baseline: unknown, curved?: unknown): string | undefined;
|
|
2479
|
+
/**
|
|
2480
|
+
* Generates scaled line chart points from data
|
|
2481
|
+
*/
|
|
2482
|
+
declare function getLinePoints(data: unknown, valueKey: unknown, width: unknown, height: unknown, padding?: unknown): Array<{
|
|
2483
|
+
x: number;
|
|
2484
|
+
y: number;
|
|
2485
|
+
}> | undefined;
|
|
2486
|
+
/**
|
|
2487
|
+
* Generates SVG arc path for pie/donut slices
|
|
2488
|
+
*/
|
|
2489
|
+
declare function getArcPath(cx: unknown, cy: unknown, radius: unknown, startAngle: unknown, endAngle: unknown): string | undefined;
|
|
2490
|
+
/**
|
|
2491
|
+
* Calculates pie slices from data
|
|
2492
|
+
*/
|
|
2493
|
+
declare function getPieSlices(data: unknown, valueKey: unknown): Array<{
|
|
2494
|
+
startAngle: number;
|
|
2495
|
+
endAngle: number;
|
|
2496
|
+
value: number;
|
|
2497
|
+
percentage: number;
|
|
2498
|
+
}> | undefined;
|
|
2499
|
+
/**
|
|
2500
|
+
* Calculates donut slices from data
|
|
2501
|
+
*/
|
|
2502
|
+
declare function getDonutSlices(data: unknown, valueKey: unknown, innerRadius: unknown): Array<{
|
|
2503
|
+
startAngle: number;
|
|
2504
|
+
endAngle: number;
|
|
2505
|
+
outerRadius: number;
|
|
2506
|
+
innerRadius: number;
|
|
2507
|
+
value: number;
|
|
2508
|
+
percentage: number;
|
|
2509
|
+
}> | undefined;
|
|
2510
|
+
/**
|
|
2511
|
+
* Converts data to radar polygon points
|
|
2512
|
+
*/
|
|
2513
|
+
declare function getRadarPoints(data: unknown, valueKey: unknown, cx: unknown, cy: unknown, radius: unknown, maxValue: unknown): Array<{
|
|
2514
|
+
x: number;
|
|
2515
|
+
y: number;
|
|
2516
|
+
}> | undefined;
|
|
2517
|
+
/**
|
|
2518
|
+
* Calculates radar axis line coordinates
|
|
2519
|
+
*/
|
|
2520
|
+
declare function getRadarAxes(labels: unknown, cx: unknown, cy: unknown, radius: unknown): Array<{
|
|
2521
|
+
x1: number;
|
|
2522
|
+
y1: number;
|
|
2523
|
+
x2: number;
|
|
2524
|
+
y2: number;
|
|
2525
|
+
label: string;
|
|
2526
|
+
angle: number;
|
|
2527
|
+
}> | undefined;
|
|
2528
|
+
/**
|
|
2529
|
+
* Generates nice tick values for axis
|
|
2530
|
+
*/
|
|
2531
|
+
declare function generateTicks(min: unknown, max: unknown, count: unknown): number[];
|
|
2532
|
+
/**
|
|
2533
|
+
* Bins data into histogram buckets
|
|
2534
|
+
*/
|
|
2535
|
+
declare function binData(data: unknown, valueKey: unknown, binCount: unknown): Array<{
|
|
2536
|
+
binStart: number;
|
|
2537
|
+
binEnd: number;
|
|
2538
|
+
count: number;
|
|
2539
|
+
values: number[];
|
|
2540
|
+
}> | undefined;
|
|
2541
|
+
/**
|
|
2542
|
+
* Aggregates data by group
|
|
2543
|
+
*/
|
|
2544
|
+
declare function aggregateData(data: unknown, groupKey: unknown, valueKey: unknown, aggregation: unknown): Array<{
|
|
2545
|
+
group: string;
|
|
2546
|
+
value: number;
|
|
2547
|
+
}> | undefined;
|
|
2548
|
+
/**
|
|
2549
|
+
* Downsamples data for performance
|
|
2550
|
+
*/
|
|
2551
|
+
declare function downsample(data: unknown, targetCount: unknown, method: unknown): unknown[] | undefined;
|
|
2552
|
+
/**
|
|
2553
|
+
* All chart helper functions registered as global functions
|
|
2554
|
+
*/
|
|
2555
|
+
declare const CHART_HELPERS: Record<string, (...args: unknown[]) => unknown>;
|
|
2556
|
+
/**
|
|
2557
|
+
* Calls a chart helper function by name
|
|
2558
|
+
*/
|
|
2559
|
+
declare function callChartHelper(method: string, args: unknown[]): unknown;
|
|
2560
|
+
|
|
2561
|
+
export { AI_OUTPUT_TYPES, AI_PROVIDER_TYPES, type ActionDefinition, type ActionStep, type AiDataSource, type AiOutputType, type AiProviderType, type ArrayExpr, BINARY_OPERATORS, type BinExpr, type BinaryOperator, type BindStep, type BooleanField, CHART_HELPERS, CLIPBOARD_OPERATIONS, COLOR_SCHEMES, type CallExpr, type CallStep, type ClearTimerStep, type ClipboardOperation, type ClipboardStep, type CloseStep, type CodeNode, type ColorScheme, type ComponentDef, type ComponentNode, type ComponentsRef, type CompoundVariant, type ConcatExpr, type CondExpr, type ConfirmStep, type ConstelaAst, ConstelaError, type ConstelaProgram, type CookieInitialExpr, DATA_SOURCE_TYPES, DATA_TRANSFORMS, type DataExpr, type DataSource, type DataSourceType, type DataTransform, type DelayStep, type DisposeStep, type DomStep, type EachNode, type ElementNode, type ErrorBoundaryNode, type ErrorCode, type ErrorOptions, type EventHandler, type EventHandlerOptions, type Expression, FOCUS_OPERATIONS, type FetchStep, type FlushStrategy, type FocusOperation, type FocusStep, type GenerateStep, type GetExpr, HTTP_METHODS, type HttpMethod, ISLAND_STRATEGIES, type IfNode, type IfStep, type ImportExpr, type ImportStep, type IndexExpr, type IntervalStep, type IslandNode, type IslandStrategy, type IslandStrategyOptions, type LambdaExpr, type LayoutProgram, type LifecycleHooks, type ListField, type LitExpr, type LocalActionDefinition, type LocalActionStep, type LocalExpr, type MarkdownNode, NAVIGATE_TARGETS, type NavigateStep, type NavigateTarget, type NotExpr, type NumberField, type ObjExpr, type ObjectField, type OptimisticStep, PARAM_TYPES, type ParamDef, type ParamExpr, type ParamType, type PortalNode, type Program, type ReconnectConfig, type RefExpr, type RejectStep, type RouteDefinition, type RouteExpr, type SSECloseStep, type SSEConnectStep, STORAGE_OPERATIONS, STORAGE_TYPES, type SendStep, type SetPathStep, type SetStep, type SlotNode, type StateExpr, type StateField, type StaticPathsDefinition, type StorageOperation, type StorageStep, type StorageType, type StreamChunk, type StreamChunkType, type StreamingRenderOptions, type StringField, type StyleExpr, type StylePreset, type SubscribeStep, type SuspenseBoundary, type SuspenseNode, type TextNode, type ThemeColors, type ThemeConfig, type ThemeFonts, UPDATE_OPERATIONS, type UnbindStep, type UpdateOperation, type UpdateStep, VALIDITY_PROPERTIES, type ValidationFailure, type ValidationResult, type ValidationSuccess, type ValidityExpr, type ValidityProperty, type VarExpr, type ViewNode, aggregateData, astSchema, binData, callChartHelper, createClipboardWriteMissingValueError, createComponentCycleError, createComponentNotFoundError, createComponentPropMissingError, createComponentPropTypeError, createCondElseRequiredError, createDataNotDefinedError, createDuplicateActionError, createDuplicateDefaultSlotError, createDuplicateIslandIdError, createDuplicateSlotNameError, createImportsNotDefinedError, createInvalidClipboardOperationError, createInvalidDataSourceError, createInvalidNavigateTargetError, createInvalidSlotNameError, createInvalidStorageOperationError, createInvalidStorageTypeError, createLayoutMissingSlotError, createLayoutNotFoundError, createLocalActionInvalidStepError, createOperationInvalidForTypeError, createOperationMissingFieldError, createOperationUnknownError, createRouteNotDefinedError, createSchemaError, createSlotInLoopError, createStorageSetMissingValueError, createUndefinedActionError, createUndefinedDataError, createUndefinedDataSourceError, createUndefinedImportError, createUndefinedLocalStateError, createUndefinedParamError, createUndefinedRefError, createUndefinedRouteParamError, createUndefinedStateError, createUndefinedStyleError, createUndefinedVarError, createUndefinedVariantError, createUnsupportedVersionError, downsample, findSimilarNames, generateTicks, getArcPath, getAreaPath, getBarDimensions, getChartBounds, getDonutSlices, getLinePath, getLinePoints, getPieSlices, getRadarAxes, getRadarPoints, isActionStep, isAiDataSource, isArrayExpr, isBinExpr, isBooleanField, isCallStep, isClipboardStep, isCodeNode, isColorScheme, isComponentNode, isConcatExpr, isCondExpr, isConstelaError, isCookieInitialExpr, isDataExpr, isDataSource, isDisposeStep, isEachNode, isElementNode, isErrorBoundaryNode, isEventHandler, isExpression, isFetchStep, isFocusStep, isGenerateStep, isGetExpr, isIfNode, isImportExpr, isImportStep, isIslandNode, isIslandStrategy, isIslandStrategyOptions, isLayoutProgram, isLifecycleHooks, isListField, isLitExpr, isLocalActionDefinition, isLocalActionStep, isMarkdownNode, isNamedSlotNode, isNavigateStep, isNotExpr, isNumberField, isObjectField, isParamExpr, isPortalNode, isRefExpr, isRouteDefinition, isRouteExpr, isSetPathStep, isSetStep, isSlotNode, isStateExpr, isStateField, isStaticPathsDefinition, isStorageStep, isStreamChunk, isStreamingRenderOptions, isStringField, isStyleExpr, isSubscribeStep, isSuspenseBoundary, isSuspenseNode, isTextNode, isThemeColors, isThemeConfig, isThemeFonts, isUpdateStep, isValidityExpr, isVarExpr, isViewNode, normalizeValue, scaleValue, validateAst };
|
package/dist/index.js
CHANGED
|
@@ -2654,10 +2654,440 @@ function isStreamChunk(value) {
|
|
|
2654
2654
|
}
|
|
2655
2655
|
return true;
|
|
2656
2656
|
}
|
|
2657
|
+
|
|
2658
|
+
// src/helpers/chart.ts
|
|
2659
|
+
function normalizeValue(value, min, max) {
|
|
2660
|
+
if (typeof value !== "number" || typeof min !== "number" || typeof max !== "number") {
|
|
2661
|
+
return void 0;
|
|
2662
|
+
}
|
|
2663
|
+
if (max === min) return 0;
|
|
2664
|
+
return (value - min) / (max - min);
|
|
2665
|
+
}
|
|
2666
|
+
function scaleValue(value, domainMin, domainMax, rangeMin, rangeMax) {
|
|
2667
|
+
if (typeof value !== "number" || typeof domainMin !== "number" || typeof domainMax !== "number" || typeof rangeMin !== "number" || typeof rangeMax !== "number") {
|
|
2668
|
+
return void 0;
|
|
2669
|
+
}
|
|
2670
|
+
if (domainMax === domainMin) return rangeMin;
|
|
2671
|
+
const normalized = (value - domainMin) / (domainMax - domainMin);
|
|
2672
|
+
return rangeMin + normalized * (rangeMax - rangeMin);
|
|
2673
|
+
}
|
|
2674
|
+
function getChartBounds(data, valueKey) {
|
|
2675
|
+
if (!Array.isArray(data) || data.length === 0) return void 0;
|
|
2676
|
+
if (typeof valueKey !== "string") return void 0;
|
|
2677
|
+
const values = [];
|
|
2678
|
+
for (const item of data) {
|
|
2679
|
+
if (typeof item !== "object" || item === null) continue;
|
|
2680
|
+
const val = item[valueKey];
|
|
2681
|
+
if (typeof val === "number") values.push(val);
|
|
2682
|
+
}
|
|
2683
|
+
if (values.length === 0) return void 0;
|
|
2684
|
+
return { min: Math.min(...values), max: Math.max(...values) };
|
|
2685
|
+
}
|
|
2686
|
+
function getBarDimensions(data, index, width, height, gap, orientation) {
|
|
2687
|
+
if (!Array.isArray(data) || data.length === 0) return void 0;
|
|
2688
|
+
if (typeof index !== "number" || index < 0 || index >= data.length) return void 0;
|
|
2689
|
+
if (typeof width !== "number" || typeof height !== "number" || typeof gap !== "number") {
|
|
2690
|
+
return void 0;
|
|
2691
|
+
}
|
|
2692
|
+
const isVertical = orientation === "vertical";
|
|
2693
|
+
const barCount = data.length;
|
|
2694
|
+
const values = data.map((d) => typeof d === "number" ? d : 0);
|
|
2695
|
+
const maxValue = Math.max(...values);
|
|
2696
|
+
if (isVertical) {
|
|
2697
|
+
const totalGap = gap * (barCount + 1);
|
|
2698
|
+
const barWidth = (width - totalGap) / barCount;
|
|
2699
|
+
const barX = gap + index * (barWidth + gap);
|
|
2700
|
+
const value = values[index] ?? 0;
|
|
2701
|
+
const barHeight = maxValue > 0 ? value / maxValue * height : 0;
|
|
2702
|
+
const barY = height - barHeight;
|
|
2703
|
+
return { x: barX, y: barY, width: barWidth, height: barHeight };
|
|
2704
|
+
} else {
|
|
2705
|
+
const totalGap = gap * barCount;
|
|
2706
|
+
const barHeight = (height - totalGap) / barCount;
|
|
2707
|
+
const barY = gap + index * (barHeight + gap);
|
|
2708
|
+
const value = values[index] ?? 0;
|
|
2709
|
+
const barWidth = maxValue > 0 ? value / maxValue * width : 0;
|
|
2710
|
+
return { x: 0, y: barY, width: barWidth, height: barHeight };
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
function getCurvedPath(points) {
|
|
2714
|
+
if (points.length < 2) {
|
|
2715
|
+
return points.length === 1 ? `M${points[0].x},${points[0].y}` : "";
|
|
2716
|
+
}
|
|
2717
|
+
if (points.length === 2) {
|
|
2718
|
+
return `M${points[0].x},${points[0].y} L${points[1].x},${points[1].y}`;
|
|
2719
|
+
}
|
|
2720
|
+
const pathParts = [`M${points[0].x},${points[0].y}`];
|
|
2721
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
2722
|
+
const p0 = points[Math.max(0, i - 1)];
|
|
2723
|
+
const p1 = points[i];
|
|
2724
|
+
const p2 = points[i + 1];
|
|
2725
|
+
const p3 = points[Math.min(points.length - 1, i + 2)];
|
|
2726
|
+
const cp1x = p1.x + (p2.x - p0.x) / 6;
|
|
2727
|
+
const cp1y = p1.y + (p2.y - p0.y) / 6;
|
|
2728
|
+
const cp2x = p2.x - (p3.x - p1.x) / 6;
|
|
2729
|
+
const cp2y = p2.y - (p3.y - p1.y) / 6;
|
|
2730
|
+
pathParts.push(`C${cp1x},${cp1y} ${cp2x},${cp2y} ${p2.x},${p2.y}`);
|
|
2731
|
+
}
|
|
2732
|
+
return pathParts.join(" ");
|
|
2733
|
+
}
|
|
2734
|
+
function getLinePath(points, curved) {
|
|
2735
|
+
if (!Array.isArray(points)) return void 0;
|
|
2736
|
+
if (points.length === 0) return "";
|
|
2737
|
+
for (const point of points) {
|
|
2738
|
+
if (typeof point !== "object" || point === null || typeof point.x !== "number" || typeof point.y !== "number") {
|
|
2739
|
+
return void 0;
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
const validPoints = points;
|
|
2743
|
+
if (validPoints.length === 1) return `M${validPoints[0].x},${validPoints[0].y}`;
|
|
2744
|
+
if (curved !== true) {
|
|
2745
|
+
return validPoints.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
|
|
2746
|
+
}
|
|
2747
|
+
return getCurvedPath(validPoints);
|
|
2748
|
+
}
|
|
2749
|
+
function getAreaPath(points, baseline, curved) {
|
|
2750
|
+
if (!Array.isArray(points)) return void 0;
|
|
2751
|
+
if (typeof baseline !== "number") return void 0;
|
|
2752
|
+
if (points.length === 0) return "";
|
|
2753
|
+
for (const point of points) {
|
|
2754
|
+
if (typeof point !== "object" || point === null || typeof point.x !== "number" || typeof point.y !== "number") {
|
|
2755
|
+
return void 0;
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
const validPoints = points;
|
|
2759
|
+
let upperPath;
|
|
2760
|
+
if (curved === true && validPoints.length > 2) {
|
|
2761
|
+
upperPath = getCurvedPath(validPoints);
|
|
2762
|
+
} else {
|
|
2763
|
+
upperPath = validPoints.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
|
|
2764
|
+
}
|
|
2765
|
+
const lastPoint = validPoints[validPoints.length - 1];
|
|
2766
|
+
const firstPoint = validPoints[0];
|
|
2767
|
+
return `${upperPath} L${lastPoint.x},${baseline} L${firstPoint.x},${baseline} Z`;
|
|
2768
|
+
}
|
|
2769
|
+
function getLinePoints(data, valueKey, width, height, padding) {
|
|
2770
|
+
if (!Array.isArray(data) || data.length === 0) return void 0;
|
|
2771
|
+
if (typeof valueKey !== "string") return void 0;
|
|
2772
|
+
if (typeof width !== "number" || typeof height !== "number") return void 0;
|
|
2773
|
+
const pad = typeof padding === "number" ? padding : 40;
|
|
2774
|
+
const bounds = getChartBounds(data, valueKey);
|
|
2775
|
+
if (!bounds) return void 0;
|
|
2776
|
+
const { min, max } = bounds;
|
|
2777
|
+
const chartWidth = width - pad * 2;
|
|
2778
|
+
const chartHeight = height - pad * 2;
|
|
2779
|
+
return data.map((item, idx) => {
|
|
2780
|
+
const value = item[valueKey];
|
|
2781
|
+
if (typeof value !== "number") return { x: 0, y: 0 };
|
|
2782
|
+
const x = pad + (data.length > 1 ? idx / (data.length - 1) * chartWidth : chartWidth / 2);
|
|
2783
|
+
const y = min === max ? pad + chartHeight / 2 : pad + chartHeight - scaleValue(value, min, max, 0, chartHeight);
|
|
2784
|
+
return { x, y };
|
|
2785
|
+
});
|
|
2786
|
+
}
|
|
2787
|
+
function getArcPath(cx, cy, radius, startAngle, endAngle) {
|
|
2788
|
+
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number" || typeof startAngle !== "number" || typeof endAngle !== "number") {
|
|
2789
|
+
return void 0;
|
|
2790
|
+
}
|
|
2791
|
+
if (radius <= 0) return void 0;
|
|
2792
|
+
const x1 = cx + radius * Math.cos(startAngle);
|
|
2793
|
+
const y1 = cy + radius * Math.sin(startAngle);
|
|
2794
|
+
const x2 = cx + radius * Math.cos(endAngle);
|
|
2795
|
+
const y2 = cy + radius * Math.sin(endAngle);
|
|
2796
|
+
const largeArcFlag = Math.abs(endAngle - startAngle) > Math.PI ? 1 : 0;
|
|
2797
|
+
return `M${x1},${y1} A${radius},${radius} 0 ${largeArcFlag},1 ${x2},${y2}`;
|
|
2798
|
+
}
|
|
2799
|
+
function getPieSlices(data, valueKey) {
|
|
2800
|
+
if (!Array.isArray(data)) return void 0;
|
|
2801
|
+
if (typeof valueKey !== "string") return void 0;
|
|
2802
|
+
if (data.length === 0) return [];
|
|
2803
|
+
const values = data.map((item) => {
|
|
2804
|
+
if (typeof item !== "object" || item === null) return 0;
|
|
2805
|
+
const val = item[valueKey];
|
|
2806
|
+
return typeof val === "number" ? val : 0;
|
|
2807
|
+
});
|
|
2808
|
+
const total = values.reduce((sum, val) => sum + val, 0);
|
|
2809
|
+
const slices = [];
|
|
2810
|
+
let currentAngle = 0;
|
|
2811
|
+
for (const value of values) {
|
|
2812
|
+
const percentage = total > 0 ? value / total * 100 : 0;
|
|
2813
|
+
const angleSpan = total > 0 ? value / total * Math.PI * 2 : 0;
|
|
2814
|
+
slices.push({
|
|
2815
|
+
startAngle: currentAngle,
|
|
2816
|
+
endAngle: currentAngle + angleSpan,
|
|
2817
|
+
value,
|
|
2818
|
+
percentage
|
|
2819
|
+
});
|
|
2820
|
+
currentAngle += angleSpan;
|
|
2821
|
+
}
|
|
2822
|
+
return slices;
|
|
2823
|
+
}
|
|
2824
|
+
function getDonutSlices(data, valueKey, innerRadius) {
|
|
2825
|
+
if (typeof innerRadius !== "number" || innerRadius < 0) return void 0;
|
|
2826
|
+
const pieSlices = getPieSlices(data, valueKey);
|
|
2827
|
+
if (pieSlices === void 0) return void 0;
|
|
2828
|
+
const outerRadius = 100;
|
|
2829
|
+
return pieSlices.map((slice) => ({
|
|
2830
|
+
...slice,
|
|
2831
|
+
outerRadius,
|
|
2832
|
+
innerRadius
|
|
2833
|
+
}));
|
|
2834
|
+
}
|
|
2835
|
+
function getRadarPoints(data, valueKey, cx, cy, radius, maxValue) {
|
|
2836
|
+
if (!Array.isArray(data)) return void 0;
|
|
2837
|
+
if (typeof valueKey !== "string") return void 0;
|
|
2838
|
+
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number" || typeof maxValue !== "number") {
|
|
2839
|
+
return void 0;
|
|
2840
|
+
}
|
|
2841
|
+
if (maxValue <= 0) return void 0;
|
|
2842
|
+
if (data.length === 0) return [];
|
|
2843
|
+
const points = [];
|
|
2844
|
+
const angleStep = Math.PI * 2 / data.length;
|
|
2845
|
+
for (let i = 0; i < data.length; i++) {
|
|
2846
|
+
const item = data[i];
|
|
2847
|
+
const value = typeof item === "object" && item !== null ? item[valueKey] : 0;
|
|
2848
|
+
const numValue = typeof value === "number" ? value : 0;
|
|
2849
|
+
const scaledRadius = numValue / maxValue * radius;
|
|
2850
|
+
const angle = -Math.PI / 2 + i * angleStep;
|
|
2851
|
+
points.push({
|
|
2852
|
+
x: cx + scaledRadius * Math.cos(angle),
|
|
2853
|
+
y: cy + scaledRadius * Math.sin(angle)
|
|
2854
|
+
});
|
|
2855
|
+
}
|
|
2856
|
+
return points;
|
|
2857
|
+
}
|
|
2858
|
+
function getRadarAxes(labels, cx, cy, radius) {
|
|
2859
|
+
if (!Array.isArray(labels)) return void 0;
|
|
2860
|
+
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number") return void 0;
|
|
2861
|
+
if (radius < 0) return void 0;
|
|
2862
|
+
if (labels.length === 0) return [];
|
|
2863
|
+
const axes = [];
|
|
2864
|
+
const angleStep = Math.PI * 2 / labels.length;
|
|
2865
|
+
for (let i = 0; i < labels.length; i++) {
|
|
2866
|
+
const label = String(labels[i]);
|
|
2867
|
+
const angle = -Math.PI / 2 + i * angleStep;
|
|
2868
|
+
axes.push({
|
|
2869
|
+
x1: cx,
|
|
2870
|
+
y1: cy,
|
|
2871
|
+
x2: cx + radius * Math.cos(angle),
|
|
2872
|
+
y2: cy + radius * Math.sin(angle),
|
|
2873
|
+
label,
|
|
2874
|
+
angle
|
|
2875
|
+
});
|
|
2876
|
+
}
|
|
2877
|
+
return axes;
|
|
2878
|
+
}
|
|
2879
|
+
function getNiceStep(rawStep) {
|
|
2880
|
+
const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
|
|
2881
|
+
const normalized = rawStep / magnitude;
|
|
2882
|
+
let niceNormalized;
|
|
2883
|
+
if (normalized <= 1) niceNormalized = 1;
|
|
2884
|
+
else if (normalized <= 2) niceNormalized = 2;
|
|
2885
|
+
else if (normalized <= 2.5) niceNormalized = 2.5;
|
|
2886
|
+
else if (normalized <= 5) niceNormalized = 5;
|
|
2887
|
+
else niceNormalized = 10;
|
|
2888
|
+
return niceNormalized * magnitude;
|
|
2889
|
+
}
|
|
2890
|
+
function generateTicks(min, max, count) {
|
|
2891
|
+
if (typeof min !== "number" || typeof max !== "number" || typeof count !== "number") return [];
|
|
2892
|
+
if (count <= 0) return [];
|
|
2893
|
+
if (min === max) return [min];
|
|
2894
|
+
if (count === 1) return [min];
|
|
2895
|
+
if (count === 2) return [min, max];
|
|
2896
|
+
const range = max - min;
|
|
2897
|
+
const rawStep = range / (count - 1);
|
|
2898
|
+
const niceStep = getNiceStep(rawStep);
|
|
2899
|
+
const niceMin = Math.floor(min / niceStep) * niceStep;
|
|
2900
|
+
const ticks = [];
|
|
2901
|
+
for (let i = 0; i < count; i++) {
|
|
2902
|
+
const tick = niceMin + i * niceStep;
|
|
2903
|
+
ticks.push(Math.round(tick * 1e10) / 1e10);
|
|
2904
|
+
}
|
|
2905
|
+
return ticks;
|
|
2906
|
+
}
|
|
2907
|
+
function binData(data, valueKey, binCount) {
|
|
2908
|
+
if (!Array.isArray(data)) return void 0;
|
|
2909
|
+
if (typeof valueKey !== "string") return void 0;
|
|
2910
|
+
if (typeof binCount !== "number" || binCount <= 0) return [];
|
|
2911
|
+
if (data.length === 0) return [];
|
|
2912
|
+
const values = [];
|
|
2913
|
+
for (const item of data) {
|
|
2914
|
+
if (typeof item !== "object" || item === null) continue;
|
|
2915
|
+
const val = item[valueKey];
|
|
2916
|
+
if (typeof val === "number") values.push(val);
|
|
2917
|
+
}
|
|
2918
|
+
if (values.length === 0) return [];
|
|
2919
|
+
const minVal = Math.min(...values);
|
|
2920
|
+
const maxVal = Math.max(...values);
|
|
2921
|
+
const binWidth = maxVal === minVal ? 1 : (maxVal - minVal) / binCount;
|
|
2922
|
+
const bins = [];
|
|
2923
|
+
for (let i = 0; i < binCount; i++) {
|
|
2924
|
+
bins.push({
|
|
2925
|
+
binStart: minVal + i * binWidth,
|
|
2926
|
+
binEnd: minVal + (i + 1) * binWidth,
|
|
2927
|
+
count: 0,
|
|
2928
|
+
values: []
|
|
2929
|
+
});
|
|
2930
|
+
}
|
|
2931
|
+
for (const val of values) {
|
|
2932
|
+
let binIndex = Math.floor((val - minVal) / binWidth);
|
|
2933
|
+
if (binIndex >= binCount) binIndex = binCount - 1;
|
|
2934
|
+
bins[binIndex].count++;
|
|
2935
|
+
bins[binIndex].values.push(val);
|
|
2936
|
+
}
|
|
2937
|
+
return bins;
|
|
2938
|
+
}
|
|
2939
|
+
function aggregateData(data, groupKey, valueKey, aggregation) {
|
|
2940
|
+
if (!Array.isArray(data)) return void 0;
|
|
2941
|
+
if (typeof groupKey !== "string" || typeof valueKey !== "string") return void 0;
|
|
2942
|
+
const validAggregations = /* @__PURE__ */ new Set(["sum", "avg", "min", "max", "count"]);
|
|
2943
|
+
if (typeof aggregation !== "string" || !validAggregations.has(aggregation)) return void 0;
|
|
2944
|
+
if (data.length === 0) return [];
|
|
2945
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2946
|
+
for (const item of data) {
|
|
2947
|
+
if (typeof item !== "object" || item === null) continue;
|
|
2948
|
+
const group = String(item[groupKey] ?? "");
|
|
2949
|
+
const val = item[valueKey];
|
|
2950
|
+
const numVal = typeof val === "number" ? val : 0;
|
|
2951
|
+
if (!groups.has(group)) groups.set(group, []);
|
|
2952
|
+
groups.get(group).push(numVal);
|
|
2953
|
+
}
|
|
2954
|
+
const result = [];
|
|
2955
|
+
for (const [group, values] of groups) {
|
|
2956
|
+
let value;
|
|
2957
|
+
switch (aggregation) {
|
|
2958
|
+
case "sum":
|
|
2959
|
+
value = values.reduce((a, b) => a + b, 0);
|
|
2960
|
+
break;
|
|
2961
|
+
case "avg":
|
|
2962
|
+
value = values.reduce((a, b) => a + b, 0) / values.length;
|
|
2963
|
+
break;
|
|
2964
|
+
case "min":
|
|
2965
|
+
value = Math.min(...values);
|
|
2966
|
+
break;
|
|
2967
|
+
case "max":
|
|
2968
|
+
value = Math.max(...values);
|
|
2969
|
+
break;
|
|
2970
|
+
case "count":
|
|
2971
|
+
value = values.length;
|
|
2972
|
+
break;
|
|
2973
|
+
default:
|
|
2974
|
+
value = 0;
|
|
2975
|
+
}
|
|
2976
|
+
result.push({ group, value });
|
|
2977
|
+
}
|
|
2978
|
+
return result;
|
|
2979
|
+
}
|
|
2980
|
+
function downsample(data, targetCount, method) {
|
|
2981
|
+
if (!Array.isArray(data)) return void 0;
|
|
2982
|
+
if (typeof targetCount !== "number" || targetCount <= 0) return void 0;
|
|
2983
|
+
const validMethods = /* @__PURE__ */ new Set(["uniform", "lttb"]);
|
|
2984
|
+
if (typeof method !== "string" || !validMethods.has(method)) return void 0;
|
|
2985
|
+
if (data.length === 0) return [];
|
|
2986
|
+
if (targetCount >= data.length) return data;
|
|
2987
|
+
if (method === "uniform") {
|
|
2988
|
+
return downsampleUniform(data, targetCount);
|
|
2989
|
+
} else {
|
|
2990
|
+
return downsampleLTTB(data, targetCount);
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2993
|
+
function downsampleUniform(data, targetCount) {
|
|
2994
|
+
if (targetCount === 1) return [data[0]];
|
|
2995
|
+
if (targetCount === 2) return [data[0], data[data.length - 1]];
|
|
2996
|
+
const result = [];
|
|
2997
|
+
const step = (data.length - 1) / (targetCount - 1);
|
|
2998
|
+
for (let i = 0; i < targetCount; i++) {
|
|
2999
|
+
const index = Math.round(i * step);
|
|
3000
|
+
result.push(data[index]);
|
|
3001
|
+
}
|
|
3002
|
+
return result;
|
|
3003
|
+
}
|
|
3004
|
+
function downsampleLTTB(data, targetCount) {
|
|
3005
|
+
if (targetCount === 1) return [data[0]];
|
|
3006
|
+
if (targetCount === 2) return [data[0], data[data.length - 1]];
|
|
3007
|
+
const getXY = (point) => {
|
|
3008
|
+
if (typeof point !== "object" || point === null) return { x: 0, y: 0 };
|
|
3009
|
+
const obj = point;
|
|
3010
|
+
const x = typeof obj["x"] === "number" ? obj["x"] : typeof obj["timestamp"] === "number" ? obj["timestamp"] : 0;
|
|
3011
|
+
const y = typeof obj["y"] === "number" ? obj["y"] : typeof obj["value"] === "number" ? obj["value"] : 0;
|
|
3012
|
+
return { x, y };
|
|
3013
|
+
};
|
|
3014
|
+
const result = [];
|
|
3015
|
+
result.push(data[0]);
|
|
3016
|
+
const numBuckets = targetCount - 2;
|
|
3017
|
+
const middleData = data.length - 2;
|
|
3018
|
+
const bucketSize = middleData / numBuckets;
|
|
3019
|
+
let prevSelectedIndex = 0;
|
|
3020
|
+
for (let bucketIndex = 0; bucketIndex < numBuckets; bucketIndex++) {
|
|
3021
|
+
const bucketStart = Math.floor(bucketIndex * bucketSize) + 1;
|
|
3022
|
+
const bucketEnd = Math.floor((bucketIndex + 1) * bucketSize) + 1;
|
|
3023
|
+
const nextBucketStart = bucketEnd;
|
|
3024
|
+
const nextBucketEnd = bucketIndex < numBuckets - 1 ? Math.floor((bucketIndex + 2) * bucketSize) + 1 : data.length;
|
|
3025
|
+
let avgX = 0, avgY = 0, avgCount = 0;
|
|
3026
|
+
for (let j = nextBucketStart; j < nextBucketEnd && j < data.length; j++) {
|
|
3027
|
+
const { x, y } = getXY(data[j]);
|
|
3028
|
+
avgX += x;
|
|
3029
|
+
avgY += y;
|
|
3030
|
+
avgCount++;
|
|
3031
|
+
}
|
|
3032
|
+
if (avgCount > 0) {
|
|
3033
|
+
avgX /= avgCount;
|
|
3034
|
+
avgY /= avgCount;
|
|
3035
|
+
}
|
|
3036
|
+
const prevPoint = getXY(data[prevSelectedIndex]);
|
|
3037
|
+
let maxArea = -1;
|
|
3038
|
+
let maxAreaIndex = bucketStart;
|
|
3039
|
+
for (let j = bucketStart; j < bucketEnd && j < data.length; j++) {
|
|
3040
|
+
const currPoint = getXY(data[j]);
|
|
3041
|
+
const area = Math.abs(
|
|
3042
|
+
(prevPoint.x - avgX) * (currPoint.y - prevPoint.y) - (prevPoint.x - currPoint.x) * (avgY - prevPoint.y)
|
|
3043
|
+
);
|
|
3044
|
+
if (area > maxArea) {
|
|
3045
|
+
maxArea = area;
|
|
3046
|
+
maxAreaIndex = j;
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
result.push(data[maxAreaIndex]);
|
|
3050
|
+
prevSelectedIndex = maxAreaIndex;
|
|
3051
|
+
}
|
|
3052
|
+
result.push(data[data.length - 1]);
|
|
3053
|
+
return result;
|
|
3054
|
+
}
|
|
3055
|
+
var CHART_HELPERS = {
|
|
3056
|
+
// Value scaling
|
|
3057
|
+
normalizeValue: (value, min, max) => normalizeValue(value, min, max),
|
|
3058
|
+
scaleValue: (value, domainMin, domainMax, rangeMin, rangeMax) => scaleValue(value, domainMin, domainMax, rangeMin, rangeMax),
|
|
3059
|
+
// Chart bounds
|
|
3060
|
+
getChartBounds: (data, valueKey) => getChartBounds(data, valueKey),
|
|
3061
|
+
// Bar chart
|
|
3062
|
+
getBarDimensions: (data, index, width, height, gap, orientation) => getBarDimensions(data, index, width, height, gap, orientation),
|
|
3063
|
+
// Line/Area chart
|
|
3064
|
+
getLinePath: (points, curved) => getLinePath(points, curved),
|
|
3065
|
+
getAreaPath: (points, baseline, curved) => getAreaPath(points, baseline, curved),
|
|
3066
|
+
getLinePoints: (data, valueKey, width, height, padding) => getLinePoints(data, valueKey, width, height, padding),
|
|
3067
|
+
// Pie/Donut chart
|
|
3068
|
+
getArcPath: (cx, cy, radius, startAngle, endAngle) => getArcPath(cx, cy, radius, startAngle, endAngle),
|
|
3069
|
+
getPieSlices: (data, valueKey) => getPieSlices(data, valueKey),
|
|
3070
|
+
getDonutSlices: (data, valueKey, innerRadius) => getDonutSlices(data, valueKey, innerRadius),
|
|
3071
|
+
// Radar chart
|
|
3072
|
+
getRadarPoints: (data, valueKey, cx, cy, radius, maxValue) => getRadarPoints(data, valueKey, cx, cy, radius, maxValue),
|
|
3073
|
+
getRadarAxes: (labels, cx, cy, radius) => getRadarAxes(labels, cx, cy, radius),
|
|
3074
|
+
// Axis ticks
|
|
3075
|
+
generateTicks: (min, max, count) => generateTicks(min, max, count),
|
|
3076
|
+
// Data aggregation
|
|
3077
|
+
binData: (data, valueKey, binCount) => binData(data, valueKey, binCount),
|
|
3078
|
+
aggregateData: (data, groupKey, valueKey, aggregation) => aggregateData(data, groupKey, valueKey, aggregation),
|
|
3079
|
+
downsample: (data, targetCount, method) => downsample(data, targetCount, method)
|
|
3080
|
+
};
|
|
3081
|
+
function callChartHelper(method, args) {
|
|
3082
|
+
const fn = CHART_HELPERS[method];
|
|
3083
|
+
if (!fn) return void 0;
|
|
3084
|
+
return fn(...args);
|
|
3085
|
+
}
|
|
2657
3086
|
export {
|
|
2658
3087
|
AI_OUTPUT_TYPES,
|
|
2659
3088
|
AI_PROVIDER_TYPES,
|
|
2660
3089
|
BINARY_OPERATORS,
|
|
3090
|
+
CHART_HELPERS,
|
|
2661
3091
|
CLIPBOARD_OPERATIONS,
|
|
2662
3092
|
COLOR_SCHEMES,
|
|
2663
3093
|
ConstelaError,
|
|
@@ -2672,7 +3102,10 @@ export {
|
|
|
2672
3102
|
STORAGE_TYPES,
|
|
2673
3103
|
UPDATE_OPERATIONS,
|
|
2674
3104
|
VALIDITY_PROPERTIES,
|
|
3105
|
+
aggregateData,
|
|
2675
3106
|
astSchema,
|
|
3107
|
+
binData,
|
|
3108
|
+
callChartHelper,
|
|
2676
3109
|
createClipboardWriteMissingValueError,
|
|
2677
3110
|
createComponentCycleError,
|
|
2678
3111
|
createComponentNotFoundError,
|
|
@@ -2714,7 +3147,19 @@ export {
|
|
|
2714
3147
|
createUndefinedVarError,
|
|
2715
3148
|
createUndefinedVariantError,
|
|
2716
3149
|
createUnsupportedVersionError,
|
|
3150
|
+
downsample,
|
|
2717
3151
|
findSimilarNames,
|
|
3152
|
+
generateTicks,
|
|
3153
|
+
getArcPath,
|
|
3154
|
+
getAreaPath,
|
|
3155
|
+
getBarDimensions,
|
|
3156
|
+
getChartBounds,
|
|
3157
|
+
getDonutSlices,
|
|
3158
|
+
getLinePath,
|
|
3159
|
+
getLinePoints,
|
|
3160
|
+
getPieSlices,
|
|
3161
|
+
getRadarAxes,
|
|
3162
|
+
getRadarPoints,
|
|
2718
3163
|
isActionStep,
|
|
2719
3164
|
isAiDataSource,
|
|
2720
3165
|
isArrayExpr,
|
|
@@ -2786,5 +3231,7 @@ export {
|
|
|
2786
3231
|
isValidityExpr,
|
|
2787
3232
|
isVarExpr,
|
|
2788
3233
|
isViewNode,
|
|
3234
|
+
normalizeValue,
|
|
3235
|
+
scaleValue,
|
|
2789
3236
|
validateAst
|
|
2790
3237
|
};
|