@opendata-ai/openchart-engine 6.3.0 → 6.5.0
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 +22 -2
- package/dist/index.js +146 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/compile-animation.test.ts +161 -0
- package/src/annotations/compute.ts +3 -0
- package/src/charts/bar/compute.ts +3 -0
- package/src/charts/column/compute.ts +4 -0
- package/src/compile.ts +66 -0
- package/src/compiler/__tests__/animation.test.ts +121 -0
- package/src/compiler/animation.ts +122 -0
- package/src/compiler/normalize.ts +1 -0
- package/src/compiler/types.ts +2 -0
- package/src/index.ts +6 -0
- package/src/tables/__tests__/compile-table.test.ts +28 -0
- package/src/tables/compile-table.ts +2 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _opendata_ai_openchart_core from '@opendata-ai/openchart-core';
|
|
2
|
-
import { LegendLayout, ResolvedChrome, TooltipContent, A11yMetadata, ResolvedTheme, CompileOptions, ChartLayout, LayerSpec, CompileTableOptions, TableLayout, MarkType, MarkDef, DataRow, Encoding, ChromeText, Annotation, LabelConfig, LegendConfig, ThemeConfig, DarkMode, ColumnConfig, GraphSpec, GraphEncoding, GraphLayoutConfig, NodeOverride, VizSpec, ScaleType, EncodingChannel, Rect, LayoutStrategy, Mark, BinTransform, CalculateTransform, ConditionalValueDef, FilterPredicate, TimeUnitTransform, Transform } from '@opendata-ai/openchart-core';
|
|
2
|
+
import { LegendLayout, ResolvedChrome, TooltipContent, A11yMetadata, ResolvedTheme, CompileOptions, ChartLayout, LayerSpec, CompileTableOptions, TableLayout, AnimationSpec, ResolvedAnimation, MarkType, MarkDef, DataRow, Encoding, ChromeText, Annotation, LabelConfig, LegendConfig, ThemeConfig, DarkMode, ColumnConfig, GraphSpec, GraphEncoding, GraphLayoutConfig, NodeOverride, VizSpec, ScaleType, EncodingChannel, Rect, LayoutStrategy, Mark, BinTransform, CalculateTransform, ConditionalValueDef, FilterPredicate, TimeUnitTransform, Transform } from '@opendata-ai/openchart-core';
|
|
3
3
|
export { ChartLayout, ChartSpec, CompileOptions, CompileTableOptions, GraphLayout, GraphSpec, LayerSpec, TableLayout, TableSpec, VizSpec } from '@opendata-ai/openchart-core';
|
|
4
4
|
import { ScaleLinear, ScaleTime, ScaleLogarithmic, ScalePower, ScaleSymLog, ScaleBand, ScalePoint, ScaleOrdinal, ScaleQuantile, ScaleQuantize, ScaleThreshold } from 'd3-scale';
|
|
5
5
|
|
|
@@ -168,6 +168,25 @@ declare function compileTable(spec: unknown, options: CompileTableOptions): Tabl
|
|
|
168
168
|
*/
|
|
169
169
|
declare function compileGraph(spec: unknown, options: CompileOptions): GraphCompilation;
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Animation resolver: normalizes AnimationSpec into fully resolved config.
|
|
173
|
+
*
|
|
174
|
+
* Handles the shorthand forms:
|
|
175
|
+
* - true -> { enter: true } -> full defaults
|
|
176
|
+
* - { enter: { duration: 800 } } -> merge with defaults
|
|
177
|
+
* - false/undefined -> undefined (no animation)
|
|
178
|
+
*/
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Resolve an AnimationSpec into a fully resolved config with all defaults filled.
|
|
182
|
+
* Returns undefined if animation is disabled (false or omitted).
|
|
183
|
+
*/
|
|
184
|
+
declare function resolveAnimation(spec: AnimationSpec | undefined): ResolvedAnimation | undefined;
|
|
185
|
+
/**
|
|
186
|
+
* Clamp stagger delay so total stagger time doesn't exceed MAX_TOTAL_STAGGER_MS.
|
|
187
|
+
*/
|
|
188
|
+
declare function clampStaggerDelay(delay: number, elementCount: number): number;
|
|
189
|
+
|
|
171
190
|
/** Chrome with all string values normalized to ChromeText objects. */
|
|
172
191
|
interface NormalizedChrome {
|
|
173
192
|
title?: ChromeText;
|
|
@@ -214,6 +233,7 @@ interface NormalizedTableSpec {
|
|
|
214
233
|
stickyFirstColumn: boolean;
|
|
215
234
|
compact: boolean;
|
|
216
235
|
responsive: boolean;
|
|
236
|
+
animation?: AnimationSpec;
|
|
217
237
|
}
|
|
218
238
|
/** A GraphSpec with all optional fields filled with sensible defaults. */
|
|
219
239
|
interface NormalizedGraphSpec {
|
|
@@ -510,4 +530,4 @@ declare function runTimeUnit(data: DataRow[], transform: TimeUnitTransform): Dat
|
|
|
510
530
|
*/
|
|
511
531
|
declare function runTransforms(data: DataRow[], transforms: Transform[]): DataRow[];
|
|
512
532
|
|
|
513
|
-
export { type ChartRenderer, type CompileResult, type CompiledGraphEdge, type CompiledGraphNode, type GraphCompilation, type NormalizedChartSpec, type NormalizedChrome, type NormalizedGraphSpec, type NormalizedSpec, type NormalizedTableSpec, type SimulationConfig, type ValidationError, type ValidationErrorCode, type ValidationResult, clearRenderers, compile, compileChart, compileGraph, compileLayer, compileTable, evaluatePredicate, getChartRenderer, isConditionalValueDef, normalizeSpec, registerChartRenderer, resolveConditionalValue, runBin, runCalculate, runFilter, runTimeUnit, runTransforms, validateSpec };
|
|
533
|
+
export { type ChartRenderer, type CompileResult, type CompiledGraphEdge, type CompiledGraphNode, type GraphCompilation, type NormalizedChartSpec, type NormalizedChrome, type NormalizedGraphSpec, type NormalizedSpec, type NormalizedTableSpec, type SimulationConfig, type ValidationError, type ValidationErrorCode, type ValidationResult, clampStaggerDelay, clearRenderers, compile, compileChart, compileGraph, compileLayer, compileTable, evaluatePredicate, getChartRenderer, isConditionalValueDef, normalizeSpec, registerChartRenderer, resolveAnimation, resolveConditionalValue, runBin, runCalculate, runFilter, runTimeUnit, runTransforms, validateSpec };
|
package/dist/index.js
CHANGED
|
@@ -209,6 +209,7 @@ function resolveTextAnnotation(annotation, scales, chartArea, isDark) {
|
|
|
209
209
|
};
|
|
210
210
|
return {
|
|
211
211
|
type: "text",
|
|
212
|
+
id: annotation.id,
|
|
212
213
|
label,
|
|
213
214
|
stroke: annotation.stroke,
|
|
214
215
|
fill: annotation.fill,
|
|
@@ -261,6 +262,7 @@ function resolveRangeAnnotation(annotation, scales, chartArea, isDark) {
|
|
|
261
262
|
const defaultOpacity = isDark ? 0.2 : DEFAULT_RANGE_OPACITY;
|
|
262
263
|
return {
|
|
263
264
|
type: "range",
|
|
265
|
+
id: annotation.id,
|
|
264
266
|
rect,
|
|
265
267
|
label,
|
|
266
268
|
fill: annotation.fill ?? DEFAULT_RANGE_FILL,
|
|
@@ -314,6 +316,7 @@ function resolveRefLineAnnotation(annotation, scales, chartArea, isDark) {
|
|
|
314
316
|
const defaultStroke = isDark ? DARK_REFLINE_STROKE : LIGHT_REFLINE_STROKE;
|
|
315
317
|
return {
|
|
316
318
|
type: "refline",
|
|
319
|
+
id: annotation.id,
|
|
317
320
|
line: { start, end },
|
|
318
321
|
label,
|
|
319
322
|
stroke: annotation.stroke ?? defaultStroke,
|
|
@@ -771,7 +774,9 @@ function computeStackedBars(data, valueField, categoryField, colorField, xScale,
|
|
|
771
774
|
fill: color2,
|
|
772
775
|
cornerRadius: 0,
|
|
773
776
|
data: row,
|
|
774
|
-
aria
|
|
777
|
+
aria,
|
|
778
|
+
orient: "horizontal",
|
|
779
|
+
stackGroup: category
|
|
775
780
|
});
|
|
776
781
|
cumulativeValue += value;
|
|
777
782
|
}
|
|
@@ -810,7 +815,8 @@ function computeSimpleBars(data, valueField, categoryField, xScale, yScale, band
|
|
|
810
815
|
fill: color2,
|
|
811
816
|
cornerRadius: 2,
|
|
812
817
|
data: row,
|
|
813
|
-
aria
|
|
818
|
+
aria,
|
|
819
|
+
orient: "horizontal"
|
|
814
820
|
});
|
|
815
821
|
}
|
|
816
822
|
return marks;
|
|
@@ -1048,7 +1054,8 @@ function computeSimpleColumns(data, categoryField, valueField, xScale, yScale, b
|
|
|
1048
1054
|
fill: color2,
|
|
1049
1055
|
cornerRadius: 2,
|
|
1050
1056
|
data: row,
|
|
1051
|
-
aria
|
|
1057
|
+
aria,
|
|
1058
|
+
orient: "vertical"
|
|
1052
1059
|
});
|
|
1053
1060
|
}
|
|
1054
1061
|
return marks;
|
|
@@ -1078,7 +1085,8 @@ function computeColoredColumns(data, categoryField, valueField, colorField, xSca
|
|
|
1078
1085
|
fill: color2,
|
|
1079
1086
|
cornerRadius: 2,
|
|
1080
1087
|
data: row,
|
|
1081
|
-
aria
|
|
1088
|
+
aria,
|
|
1089
|
+
orient: "vertical"
|
|
1082
1090
|
});
|
|
1083
1091
|
}
|
|
1084
1092
|
return marks;
|
|
@@ -1110,7 +1118,9 @@ function computeStackedColumns(data, categoryField, valueField, colorField, xSca
|
|
|
1110
1118
|
fill: color2,
|
|
1111
1119
|
cornerRadius: 0,
|
|
1112
1120
|
data: row,
|
|
1113
|
-
aria
|
|
1121
|
+
aria,
|
|
1122
|
+
orient: "vertical",
|
|
1123
|
+
stackGroup: category
|
|
1114
1124
|
});
|
|
1115
1125
|
cumulativeValue += value;
|
|
1116
1126
|
}
|
|
@@ -5989,7 +5999,8 @@ function normalizeTableSpec(spec, _warnings) {
|
|
|
5989
5999
|
pagination: spec.pagination ?? false,
|
|
5990
6000
|
stickyFirstColumn: spec.stickyFirstColumn ?? false,
|
|
5991
6001
|
compact: spec.compact ?? false,
|
|
5992
|
-
responsive: spec.responsive ?? true
|
|
6002
|
+
responsive: spec.responsive ?? true,
|
|
6003
|
+
animation: spec.animation
|
|
5993
6004
|
};
|
|
5994
6005
|
}
|
|
5995
6006
|
function normalizeGraphSpec(spec, _warnings) {
|
|
@@ -6656,6 +6667,77 @@ ${errorMessages}`);
|
|
|
6656
6667
|
return { spec: normalized, warnings };
|
|
6657
6668
|
}
|
|
6658
6669
|
|
|
6670
|
+
// src/compiler/animation.ts
|
|
6671
|
+
var ENTER_DEFAULTS = {
|
|
6672
|
+
duration: 500,
|
|
6673
|
+
ease: "smooth",
|
|
6674
|
+
staggerDelay: 80,
|
|
6675
|
+
staggerOrder: "index",
|
|
6676
|
+
annotationDelay: 200
|
|
6677
|
+
};
|
|
6678
|
+
var MAX_TOTAL_STAGGER_MS = 2e3;
|
|
6679
|
+
function resolveAnimation(spec) {
|
|
6680
|
+
if (spec === void 0 || spec === false) return void 0;
|
|
6681
|
+
if (spec === true) {
|
|
6682
|
+
return {
|
|
6683
|
+
enabled: true,
|
|
6684
|
+
duration: ENTER_DEFAULTS.duration,
|
|
6685
|
+
ease: ENTER_DEFAULTS.ease,
|
|
6686
|
+
staggerDelay: ENTER_DEFAULTS.staggerDelay,
|
|
6687
|
+
staggerOrder: ENTER_DEFAULTS.staggerOrder,
|
|
6688
|
+
annotationDelay: ENTER_DEFAULTS.annotationDelay
|
|
6689
|
+
};
|
|
6690
|
+
}
|
|
6691
|
+
const config = spec;
|
|
6692
|
+
if (config.enter === false || config.enter === void 0 && !hasAnyPhase(config)) {
|
|
6693
|
+
return void 0;
|
|
6694
|
+
}
|
|
6695
|
+
const enterConfig = resolvePhaseConfig(config.enter);
|
|
6696
|
+
return {
|
|
6697
|
+
enabled: true,
|
|
6698
|
+
duration: enterConfig.duration,
|
|
6699
|
+
ease: enterConfig.ease,
|
|
6700
|
+
staggerDelay: enterConfig.staggerDelay,
|
|
6701
|
+
staggerOrder: enterConfig.staggerOrder,
|
|
6702
|
+
annotationDelay: config.annotationDelay ?? ENTER_DEFAULTS.annotationDelay
|
|
6703
|
+
};
|
|
6704
|
+
}
|
|
6705
|
+
function clampStaggerDelay(delay, elementCount) {
|
|
6706
|
+
if (elementCount <= 1) return 0;
|
|
6707
|
+
return Math.min(delay, MAX_TOTAL_STAGGER_MS / elementCount);
|
|
6708
|
+
}
|
|
6709
|
+
function hasAnyPhase(config) {
|
|
6710
|
+
return config.enter !== void 0 || config.update !== void 0 || config.exit !== void 0;
|
|
6711
|
+
}
|
|
6712
|
+
function resolvePhaseConfig(phase) {
|
|
6713
|
+
if (phase === void 0 || phase === true) {
|
|
6714
|
+
return {
|
|
6715
|
+
duration: ENTER_DEFAULTS.duration,
|
|
6716
|
+
ease: ENTER_DEFAULTS.ease,
|
|
6717
|
+
staggerDelay: ENTER_DEFAULTS.staggerDelay,
|
|
6718
|
+
staggerOrder: ENTER_DEFAULTS.staggerOrder
|
|
6719
|
+
};
|
|
6720
|
+
}
|
|
6721
|
+
const cfg = phase;
|
|
6722
|
+
const stagger = resolveStagger(cfg.stagger);
|
|
6723
|
+
return {
|
|
6724
|
+
duration: cfg.duration ?? ENTER_DEFAULTS.duration,
|
|
6725
|
+
ease: cfg.ease ?? ENTER_DEFAULTS.ease,
|
|
6726
|
+
staggerDelay: stagger.delay,
|
|
6727
|
+
staggerOrder: stagger.order
|
|
6728
|
+
};
|
|
6729
|
+
}
|
|
6730
|
+
function resolveStagger(stagger) {
|
|
6731
|
+
if (stagger === false) return { delay: 0, order: "index" };
|
|
6732
|
+
if (stagger === void 0 || stagger === true) {
|
|
6733
|
+
return { delay: ENTER_DEFAULTS.staggerDelay, order: ENTER_DEFAULTS.staggerOrder };
|
|
6734
|
+
}
|
|
6735
|
+
return {
|
|
6736
|
+
delay: stagger.delay ?? ENTER_DEFAULTS.staggerDelay,
|
|
6737
|
+
order: stagger.order ?? ENTER_DEFAULTS.staggerOrder
|
|
6738
|
+
};
|
|
6739
|
+
}
|
|
6740
|
+
|
|
6659
6741
|
// src/graphs/compile-graph.ts
|
|
6660
6742
|
import { adaptTheme, computeChrome, resolveTheme } from "@opendata-ai/openchart-core";
|
|
6661
6743
|
|
|
@@ -8744,7 +8826,8 @@ function compileTableLayout(spec, options, theme) {
|
|
|
8744
8826
|
caption,
|
|
8745
8827
|
summary: `${resolvedColumns.length} columns, ${totalFiltered} rows`
|
|
8746
8828
|
},
|
|
8747
|
-
theme
|
|
8829
|
+
theme,
|
|
8830
|
+
animation: resolveAnimation(spec.animation)
|
|
8748
8831
|
};
|
|
8749
8832
|
}
|
|
8750
8833
|
|
|
@@ -9227,6 +9310,8 @@ function compileChart(spec, options) {
|
|
|
9227
9310
|
};
|
|
9228
9311
|
}
|
|
9229
9312
|
}
|
|
9313
|
+
const rawAnimationSpec = overrides?.[breakpoint]?.animation ?? rawSpec.animation;
|
|
9314
|
+
const resolvedAnimation = resolveAnimation(rawAnimationSpec);
|
|
9230
9315
|
const mergedThemeConfig = options.theme ? { ...chartSpec.theme, ...options.theme } : chartSpec.theme;
|
|
9231
9316
|
let theme = resolveTheme2(mergedThemeConfig);
|
|
9232
9317
|
if (options.darkMode) {
|
|
@@ -9357,6 +9442,37 @@ function compileChart(spec, options) {
|
|
|
9357
9442
|
},
|
|
9358
9443
|
chartSpec.data
|
|
9359
9444
|
);
|
|
9445
|
+
if (resolvedAnimation?.enabled && resolvedAnimation.staggerOrder === "value") {
|
|
9446
|
+
const indexed = marks.map((m, i) => ({ mark: m, idx: i }));
|
|
9447
|
+
indexed.sort((a, b) => {
|
|
9448
|
+
const av = getMarkPrimaryValue(a.mark);
|
|
9449
|
+
const bv = getMarkPrimaryValue(b.mark);
|
|
9450
|
+
return av - bv;
|
|
9451
|
+
});
|
|
9452
|
+
for (let i = 0; i < indexed.length; i++) {
|
|
9453
|
+
const m = indexed[i].mark;
|
|
9454
|
+
if (m.type === "rect" && m.stackGroup) continue;
|
|
9455
|
+
m.animationIndex = i;
|
|
9456
|
+
}
|
|
9457
|
+
}
|
|
9458
|
+
if (resolvedAnimation?.enabled) {
|
|
9459
|
+
const groupIndexMap = /* @__PURE__ */ new Map();
|
|
9460
|
+
const groupStackPos = /* @__PURE__ */ new Map();
|
|
9461
|
+
let nextGroupIndex = 0;
|
|
9462
|
+
for (const mark of marks) {
|
|
9463
|
+
if (mark.type === "rect" && mark.stackGroup) {
|
|
9464
|
+
const rect = mark;
|
|
9465
|
+
const group = rect.stackGroup;
|
|
9466
|
+
if (!groupIndexMap.has(group)) {
|
|
9467
|
+
groupIndexMap.set(group, nextGroupIndex++);
|
|
9468
|
+
}
|
|
9469
|
+
rect.animationIndex = groupIndexMap.get(group);
|
|
9470
|
+
const pos = groupStackPos.get(group) ?? 0;
|
|
9471
|
+
rect.stackPos = pos;
|
|
9472
|
+
groupStackPos.set(group, pos + 1);
|
|
9473
|
+
}
|
|
9474
|
+
}
|
|
9475
|
+
}
|
|
9360
9476
|
return {
|
|
9361
9477
|
area: chartArea,
|
|
9362
9478
|
chrome: dims.chrome,
|
|
@@ -9378,9 +9494,29 @@ function compileChart(spec, options) {
|
|
|
9378
9494
|
dimensions: {
|
|
9379
9495
|
width: options.width,
|
|
9380
9496
|
height: options.height
|
|
9381
|
-
}
|
|
9497
|
+
},
|
|
9498
|
+
animation: resolvedAnimation
|
|
9382
9499
|
};
|
|
9383
9500
|
}
|
|
9501
|
+
function getMarkPrimaryValue(mark) {
|
|
9502
|
+
switch (mark.type) {
|
|
9503
|
+
case "rect":
|
|
9504
|
+
return mark.height;
|
|
9505
|
+
// bar height is the primary value encoding
|
|
9506
|
+
case "point":
|
|
9507
|
+
return mark.cy;
|
|
9508
|
+
// y position for scatter
|
|
9509
|
+
case "arc":
|
|
9510
|
+
return mark.endAngle - mark.startAngle;
|
|
9511
|
+
// arc angle extent
|
|
9512
|
+
case "line":
|
|
9513
|
+
case "area":
|
|
9514
|
+
return 0;
|
|
9515
|
+
// series marks don't have individual values
|
|
9516
|
+
default:
|
|
9517
|
+
return 0;
|
|
9518
|
+
}
|
|
9519
|
+
}
|
|
9384
9520
|
function compileLayer(spec, options) {
|
|
9385
9521
|
const leaves = flattenLayers(spec);
|
|
9386
9522
|
if (leaves.length === 0) {
|
|
@@ -9451,6 +9587,7 @@ function compileGraph2(spec, options) {
|
|
|
9451
9587
|
return compileGraph(spec, options);
|
|
9452
9588
|
}
|
|
9453
9589
|
export {
|
|
9590
|
+
clampStaggerDelay,
|
|
9454
9591
|
clearRenderers,
|
|
9455
9592
|
compile,
|
|
9456
9593
|
compileChart,
|
|
@@ -9462,6 +9599,7 @@ export {
|
|
|
9462
9599
|
isConditionalValueDef,
|
|
9463
9600
|
normalizeSpec,
|
|
9464
9601
|
registerChartRenderer,
|
|
9602
|
+
resolveAnimation,
|
|
9465
9603
|
resolveConditionalValue,
|
|
9466
9604
|
runBin,
|
|
9467
9605
|
runCalculate,
|