@opendata-ai/openchart-engine 7.7.0 → 7.9.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 +63 -4
- package/dist/index.js +227 -55
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/compile-snapshot.test.ts.snap +31 -0
- package/src/__tests__/compile-animation.test.ts +8 -8
- package/src/__tests__/compile-chart.test.ts +5 -5
- package/src/__tests__/mark-keys.test.ts +294 -0
- package/src/charts/__tests__/post-process.test.ts +5 -26
- package/src/charts/bar/compute.ts +18 -0
- package/src/charts/column/compute.ts +18 -0
- package/src/charts/dot/compute.ts +30 -13
- package/src/charts/line/area.ts +20 -0
- package/src/charts/line/compute.ts +35 -1
- package/src/charts/line/curves.ts +47 -2
- package/src/charts/pie/compute.ts +13 -0
- package/src/charts/post-process.ts +2 -2
- package/src/charts/rule/index.ts +9 -0
- package/src/charts/scatter/compute.ts +15 -0
- package/src/charts/text/index.ts +9 -0
- package/src/charts/tick/index.ts +9 -0
- package/src/compile.ts +1 -1
- package/src/compiler/__tests__/animation.test.ts +78 -22
- package/src/compiler/__tests__/keys.test.ts +89 -0
- package/src/compiler/animation.ts +70 -50
- package/src/compiler/keys.ts +54 -0
- package/src/compiler/normalize.ts +1 -1
- package/src/index.ts +19 -1
- package/src/tables/__tests__/compile-table.test.ts +5 -5
- package/src/tilemap/compile-tilemap.ts +10 -2
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, AnimationSpec, ResolvedAnimation, DataRow, BarListEncoding, ThemeConfig, DarkMode, TileMapEncoding, TileMapPalette, LegendConfig, MarkType, MarkDef, Encoding, ChromeText, Annotation, LabelConfig, Display, ColumnConfig, GraphSpec, GraphEncoding, GraphLayoutConfig, NodeOverride, SankeyEncoding, SankeyNodeAlign, SankeyLinkColor, ScaleType, EncodingChannel, Rect, LayoutStrategy, VizSpec, Mark, BinTransform, CalculateTransform, ConditionalValueDef, FilterPredicate, TimeUnitTransform, Transform } from '@opendata-ai/openchart-core';
|
|
2
|
+
import { LegendLayout, ResolvedChrome, TooltipContent, A11yMetadata, ResolvedTheme, CompileOptions, ChartLayout, LayerSpec, CompileTableOptions, TableLayout, ResolvedAnimationPhase, AnimationSpec, ResolvedAnimation, Point, DataRow, BarListEncoding, ThemeConfig, DarkMode, TileMapEncoding, TileMapPalette, LegendConfig, MarkType, MarkDef, Encoding, ChromeText, Annotation, LabelConfig, Display, ColumnConfig, GraphSpec, GraphEncoding, GraphLayoutConfig, NodeOverride, SankeyEncoding, SankeyNodeAlign, SankeyLinkColor, ScaleType, EncodingChannel, Rect, LayoutStrategy, VizSpec, Mark, BinTransform, CalculateTransform, ConditionalValueDef, FilterPredicate, TimeUnitTransform, Transform } from '@opendata-ai/openchart-core';
|
|
3
3
|
export { BarListLayout, BarListSpec, ChartLayout, ChartSpec, CompileOptions, CompileTableOptions, GraphLayout, GraphSpec, LayerSpec, SankeyLayout, SankeySpec, TableLayout, TableSpec, TileMapLayout, TileMapSpec, 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
|
|
|
@@ -189,11 +189,24 @@ declare function compileBarList(spec: unknown, options: CompileOptions): _openda
|
|
|
189
189
|
* Animation resolver: normalizes AnimationSpec into fully resolved config.
|
|
190
190
|
*
|
|
191
191
|
* Handles the shorthand forms:
|
|
192
|
-
* - true ->
|
|
193
|
-
* - { enter: { duration: 800 } } -> merge with defaults
|
|
192
|
+
* - true -> all three phases with defaults
|
|
193
|
+
* - { enter: { duration: 800 } } -> merge with defaults per phase
|
|
194
194
|
* - false/undefined -> undefined (no animation)
|
|
195
|
+
*
|
|
196
|
+
* Each phase resolves independently:
|
|
197
|
+
* - true/config-object -> resolved phase merged onto that phase's defaults
|
|
198
|
+
* - false -> phase absent
|
|
199
|
+
* - undefined -> phase present with defaults (animation: {} behaves like true)
|
|
200
|
+
*
|
|
201
|
+
* Returns undefined only when ALL phases resolve absent.
|
|
195
202
|
*/
|
|
196
203
|
|
|
204
|
+
/** Default values for entrance animation. */
|
|
205
|
+
declare const ENTER_DEFAULTS: ResolvedAnimationPhase;
|
|
206
|
+
/** Default values for update (data transition) animation. */
|
|
207
|
+
declare const UPDATE_DEFAULTS: ResolvedAnimationPhase;
|
|
208
|
+
/** Default values for exit animation. */
|
|
209
|
+
declare const EXIT_DEFAULTS: ResolvedAnimationPhase;
|
|
197
210
|
/**
|
|
198
211
|
* Resolve an AnimationSpec into a fully resolved config with all defaults filled.
|
|
199
212
|
* Returns undefined if animation is disabled (false or omitted).
|
|
@@ -204,6 +217,52 @@ declare function resolveAnimation(spec: AnimationSpec | undefined): ResolvedAnim
|
|
|
204
217
|
*/
|
|
205
218
|
declare function clampStaggerDelay(delay: number, elementCount: number): number;
|
|
206
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Mark key utilities for data-update transitions.
|
|
222
|
+
*
|
|
223
|
+
* Keys uniquely identify marks across data updates so the renderer can
|
|
224
|
+
* match old marks to new marks and animate the difference. Each chart
|
|
225
|
+
* type stamps keys during its compute phase; these helpers provide the
|
|
226
|
+
* shared serialization and deduplication logic.
|
|
227
|
+
*/
|
|
228
|
+
/**
|
|
229
|
+
* Serialize a datum value into a stable key fragment.
|
|
230
|
+
* - Date -> epoch ms string (avoids locale-dependent Date.toString)
|
|
231
|
+
* - number/string/boolean -> String(v)
|
|
232
|
+
* - null/undefined -> null sentinel
|
|
233
|
+
*/
|
|
234
|
+
declare function serializeKeyValue(v: unknown): string;
|
|
235
|
+
/**
|
|
236
|
+
* Append occurrence suffixes to duplicate keys, in order.
|
|
237
|
+
*
|
|
238
|
+
* Only keys that appear more than once get suffixed. Unique keys pass
|
|
239
|
+
* through unchanged so keys remain human-readable when possible.
|
|
240
|
+
* Uses SOH (\x01) as separator to avoid collisions with real data values.
|
|
241
|
+
*/
|
|
242
|
+
declare function dedupeKeys(keys: string[]): string[];
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Curve interpolation mapping and path builders.
|
|
246
|
+
*
|
|
247
|
+
* Maps Vega-Lite-style interpolation strings to d3-shape curve factories.
|
|
248
|
+
* Used by both line and area chart computations.
|
|
249
|
+
*
|
|
250
|
+
* Also exports pure path-builder helpers (`buildLinePath`, `buildAreaPath`)
|
|
251
|
+
* so downstream consumers (e.g. transition interpolators) can reconstruct
|
|
252
|
+
* SVG paths from point arrays without pulling in chart-specific code.
|
|
253
|
+
*/
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Build an SVG path string from an array of points using d3 line generator.
|
|
257
|
+
* Accepts an optional interpolation string (defaults to 'monotone').
|
|
258
|
+
*/
|
|
259
|
+
declare function buildLinePath(points: Point[], interpolate?: string): string;
|
|
260
|
+
/**
|
|
261
|
+
* Build an SVG path string for a filled area from top and bottom point arrays.
|
|
262
|
+
* Accepts an optional interpolation string (defaults to 'monotone').
|
|
263
|
+
*/
|
|
264
|
+
declare function buildAreaPath(topPoints: Point[], bottomPoints: Point[], interpolate?: string): string;
|
|
265
|
+
|
|
207
266
|
/**
|
|
208
267
|
* Internal normalized barlist spec type used by the compilation pipeline.
|
|
209
268
|
*/
|
|
@@ -733,4 +792,4 @@ declare function runTimeUnit(data: DataRow[], transform: TimeUnitTransform): Dat
|
|
|
733
792
|
*/
|
|
734
793
|
declare function runTransforms(data: DataRow[], transforms: Transform[]): DataRow[];
|
|
735
794
|
|
|
736
|
-
export { type AnnotationContext, type AnnotationMeasureTextFn, type ChartRenderer, type CompileResult, type CompiledGraphEdge, type CompiledGraphNode, type GraphCompilation, type NormalizedBarListSpec, type NormalizedChartSpec, type NormalizedChrome, type NormalizedGraphSpec, type NormalizedSankeySpec, type NormalizedSpec, type NormalizedTableSpec, type NormalizedTileMapSpec, type ObstacleKind, type PlacementObstacle, type SimulationConfig, type ValidationError, type ValidationErrorCode, type ValidationResult, clampStaggerDelay, clearRenderers, compile, compileBarList, compileChart, compileGraph, compileLayer, compileSankey, compileTable, compileTileMap, evaluatePredicate, getChartRenderer, heuristicMeasure, isConditionalValueDef, normalizeSpec, registerChartRenderer, resolveAnimation, resolveConditionalValue, runBin, runCalculate, runFilter, runTimeUnit, runTransforms, validateSpec };
|
|
795
|
+
export { type AnnotationContext, type AnnotationMeasureTextFn, type ChartRenderer, type CompileResult, type CompiledGraphEdge, type CompiledGraphNode, ENTER_DEFAULTS, EXIT_DEFAULTS, type GraphCompilation, type NormalizedBarListSpec, type NormalizedChartSpec, type NormalizedChrome, type NormalizedGraphSpec, type NormalizedSankeySpec, type NormalizedSpec, type NormalizedTableSpec, type NormalizedTileMapSpec, type ObstacleKind, type PlacementObstacle, type SimulationConfig, UPDATE_DEFAULTS, type ValidationError, type ValidationErrorCode, type ValidationResult, buildAreaPath, buildLinePath, clampStaggerDelay, clearRenderers, compile, compileBarList, compileChart, compileGraph, compileLayer, compileSankey, compileTable, compileTileMap, dedupeKeys, evaluatePredicate, getChartRenderer, heuristicMeasure, isConditionalValueDef, normalizeSpec, registerChartRenderer, resolveAnimation, resolveConditionalValue, runBin, runCalculate, runFilter, runTimeUnit, runTransforms, serializeKeyValue, validateSpec };
|
package/dist/index.js
CHANGED
|
@@ -2125,6 +2125,32 @@ function computeEndpointLabels(spec, marks, theme, chartArea, strategy, endpoint
|
|
|
2125
2125
|
// src/charts/bar/compute.ts
|
|
2126
2126
|
import { isGradientDef, NARROW_VIEWPORT_MAX } from "@opendata-ai/openchart-core";
|
|
2127
2127
|
|
|
2128
|
+
// src/compiler/keys.ts
|
|
2129
|
+
var NULL_KEY = "\u2205";
|
|
2130
|
+
function serializeKeyValue(v) {
|
|
2131
|
+
if (v === null || v === void 0) return NULL_KEY;
|
|
2132
|
+
if (v instanceof Date) return String(v.getTime());
|
|
2133
|
+
return String(v);
|
|
2134
|
+
}
|
|
2135
|
+
function dedupeKeys(keys) {
|
|
2136
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2137
|
+
for (const k of keys) {
|
|
2138
|
+
counts.set(k, (counts.get(k) ?? 0) + 1);
|
|
2139
|
+
}
|
|
2140
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2141
|
+
const result = [];
|
|
2142
|
+
for (const k of keys) {
|
|
2143
|
+
if (counts.get(k) > 1) {
|
|
2144
|
+
const idx = seen.get(k) ?? 0;
|
|
2145
|
+
result.push(`${k}${idx}`);
|
|
2146
|
+
seen.set(k, idx + 1);
|
|
2147
|
+
} else {
|
|
2148
|
+
result.push(k);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
return result;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2128
2154
|
// src/transforms/predicates.ts
|
|
2129
2155
|
function isFieldPredicate(pred) {
|
|
2130
2156
|
return "field" in pred;
|
|
@@ -2374,8 +2400,21 @@ function computeBarMarks(spec, scales, _chartArea, _strategy, containerWidth) {
|
|
|
2374
2400
|
);
|
|
2375
2401
|
}
|
|
2376
2402
|
}
|
|
2403
|
+
const categoryField = yChannel.field;
|
|
2404
|
+
stampBarKeys(marks, categoryField, colorField);
|
|
2377
2405
|
return applyMarkDefOverrides(marks, spec, bandwidth);
|
|
2378
2406
|
}
|
|
2407
|
+
function stampBarKeys(marks, categoryField, colorField) {
|
|
2408
|
+
const rawKeys = marks.map((m) => {
|
|
2409
|
+
const series = colorField ? String(m.data[colorField] ?? "") : "";
|
|
2410
|
+
const cat = serializeKeyValue(m.data[categoryField]);
|
|
2411
|
+
return `${series}|${cat}`;
|
|
2412
|
+
});
|
|
2413
|
+
const keys = dedupeKeys(rawKeys);
|
|
2414
|
+
for (let i = 0; i < marks.length; i++) {
|
|
2415
|
+
marks[i].key = keys[i];
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2379
2418
|
function computeStackedBars(data, valueField, categoryField, colorField, xScale, yScale, bandwidth, _baseline, scales, stackMode = "zero") {
|
|
2380
2419
|
const marks = [];
|
|
2381
2420
|
const categoryGroups = groupByField(data, categoryField);
|
|
@@ -2873,8 +2912,21 @@ function computeColumnMarks(spec, scales, _chartArea, _strategy) {
|
|
|
2873
2912
|
conditionalColor
|
|
2874
2913
|
);
|
|
2875
2914
|
}
|
|
2915
|
+
const categoryField = xChannel.field;
|
|
2916
|
+
stampColumnKeys(marks, categoryField, colorField);
|
|
2876
2917
|
return applyMarkDefOverrides2(marks, spec, bandwidth);
|
|
2877
2918
|
}
|
|
2919
|
+
function stampColumnKeys(marks, categoryField, colorField) {
|
|
2920
|
+
const rawKeys = marks.map((m) => {
|
|
2921
|
+
const series = colorField ? String(m.data[colorField] ?? "") : "";
|
|
2922
|
+
const cat = serializeKeyValue(m.data[categoryField]);
|
|
2923
|
+
return `${series}|${cat}`;
|
|
2924
|
+
});
|
|
2925
|
+
const keys = dedupeKeys(rawKeys);
|
|
2926
|
+
for (let i = 0; i < marks.length; i++) {
|
|
2927
|
+
marks[i].key = keys[i];
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2878
2930
|
function computeSimpleColumns(data, categoryField, valueField, xScale, yScale, bandwidth, baseline, scales, sequentialColor = false, conditionalColor) {
|
|
2879
2931
|
const marks = [];
|
|
2880
2932
|
for (const row of data) {
|
|
@@ -3198,8 +3250,9 @@ function computeDotMarks(spec, scales, _chartArea, _strategy) {
|
|
|
3198
3250
|
const colorEnc = encoding.color && "field" in encoding.color ? encoding.color : void 0;
|
|
3199
3251
|
const isSequentialColor = colorEnc?.type === "quantitative";
|
|
3200
3252
|
const colorField = isSequentialColor ? void 0 : colorEnc?.field;
|
|
3253
|
+
let marks;
|
|
3201
3254
|
if (colorField) {
|
|
3202
|
-
|
|
3255
|
+
marks = computeDumbbellMarks(
|
|
3203
3256
|
spec.data,
|
|
3204
3257
|
xChannel.field,
|
|
3205
3258
|
yChannel.field,
|
|
@@ -3209,18 +3262,30 @@ function computeDotMarks(spec, scales, _chartArea, _strategy) {
|
|
|
3209
3262
|
bandwidth,
|
|
3210
3263
|
scales
|
|
3211
3264
|
);
|
|
3265
|
+
} else {
|
|
3266
|
+
marks = computeLollipopMarks(
|
|
3267
|
+
spec.data,
|
|
3268
|
+
xChannel.field,
|
|
3269
|
+
yChannel.field,
|
|
3270
|
+
xScale,
|
|
3271
|
+
yScale,
|
|
3272
|
+
bandwidth,
|
|
3273
|
+
baseline,
|
|
3274
|
+
scales,
|
|
3275
|
+
isSequentialColor
|
|
3276
|
+
);
|
|
3212
3277
|
}
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3278
|
+
const pointMarks = marks.filter((m) => m.type === "point");
|
|
3279
|
+
const rawKeys = pointMarks.map((m) => {
|
|
3280
|
+
const cat = serializeKeyValue(m.data[yChannel.field]);
|
|
3281
|
+
const series = colorField ? String(m.data[colorField] ?? "") : "";
|
|
3282
|
+
return series ? `${series}|${cat}` : cat;
|
|
3283
|
+
});
|
|
3284
|
+
const keys = dedupeKeys(rawKeys);
|
|
3285
|
+
for (let i = 0; i < pointMarks.length; i++) {
|
|
3286
|
+
pointMarks[i].key = keys[i];
|
|
3287
|
+
}
|
|
3288
|
+
return marks;
|
|
3224
3289
|
}
|
|
3225
3290
|
function computeDumbbellMarks(data, valueField, categoryField, colorField, xScale, yScale, bandwidth, scales) {
|
|
3226
3291
|
const marks = [];
|
|
@@ -4335,6 +4400,23 @@ function resolveCurve(interpolate) {
|
|
|
4335
4400
|
if (!interpolate) return monotoneX;
|
|
4336
4401
|
return CURVE_MAP[interpolate] ?? monotoneX;
|
|
4337
4402
|
}
|
|
4403
|
+
function buildLinePath(points, interpolate) {
|
|
4404
|
+
if (points.length === 0) return "";
|
|
4405
|
+
const curve = resolveCurve(interpolate);
|
|
4406
|
+
const generator = line_default().x((d) => d.x).y((d) => d.y).curve(curve);
|
|
4407
|
+
return generator(points) ?? "";
|
|
4408
|
+
}
|
|
4409
|
+
function buildAreaPath(topPoints, bottomPoints, interpolate) {
|
|
4410
|
+
if (topPoints.length === 0) return "";
|
|
4411
|
+
const curve = resolveCurve(interpolate);
|
|
4412
|
+
const paired = topPoints.map((tp, i) => ({
|
|
4413
|
+
x: tp.x,
|
|
4414
|
+
yTop: tp.y,
|
|
4415
|
+
yBottom: bottomPoints[i]?.y ?? 0
|
|
4416
|
+
}));
|
|
4417
|
+
const generator = area_default().x((d) => d.x).y0((d) => d.yBottom).y1((d) => d.yTop).curve(curve);
|
|
4418
|
+
return generator(paired) ?? "";
|
|
4419
|
+
}
|
|
4338
4420
|
|
|
4339
4421
|
// src/charts/line/area.ts
|
|
4340
4422
|
var DEFAULT_FILL_OPACITY = 0.15;
|
|
@@ -4436,8 +4518,15 @@ function computeSingleArea(spec, scales, _chartArea) {
|
|
|
4436
4518
|
fillValue = buildGradientFill(colorStr, defaultGradientStops);
|
|
4437
4519
|
fillOpacity = 1;
|
|
4438
4520
|
}
|
|
4521
|
+
const keyField = encoding.key && "field" in encoding.key ? encoding.key.field : void 0;
|
|
4522
|
+
const rawPointKeys = validPoints.map(
|
|
4523
|
+
(p) => keyField ? serializeKeyValue(p.row[keyField]) : serializeKeyValue(p.row[xChannel.field])
|
|
4524
|
+
);
|
|
4439
4525
|
marks.push({
|
|
4440
4526
|
type: "area",
|
|
4527
|
+
key: seriesKey === "__default__" ? "area" : seriesKey,
|
|
4528
|
+
pointKeys: dedupeKeys(rawPointKeys),
|
|
4529
|
+
interpolate: spec.markDef.interpolate ?? "monotone",
|
|
4441
4530
|
topPoints,
|
|
4442
4531
|
bottomPoints,
|
|
4443
4532
|
path: pathStr,
|
|
@@ -4536,8 +4625,12 @@ function computeStackedArea(spec, scales, chartArea, darkMode) {
|
|
|
4536
4625
|
fillValue = buildGradientFill(colorStr, stackedStops);
|
|
4537
4626
|
fillOpacity = 1;
|
|
4538
4627
|
}
|
|
4628
|
+
const rawPointKeys = validPoints.map((_p, idx) => serializeKeyValue(layer[idx]?.data.__x__));
|
|
4539
4629
|
marks.push({
|
|
4540
4630
|
type: "area",
|
|
4631
|
+
key: seriesKey,
|
|
4632
|
+
pointKeys: dedupeKeys(rawPointKeys),
|
|
4633
|
+
interpolate: spec.markDef.interpolate ?? "monotone",
|
|
4541
4634
|
topPoints,
|
|
4542
4635
|
bottomPoints,
|
|
4543
4636
|
path: pathStr,
|
|
@@ -4570,6 +4663,10 @@ function computeAreaMarks(spec, scales, chartArea, darkMode) {
|
|
|
4570
4663
|
} else {
|
|
4571
4664
|
marks = computeSingleArea(spec, scales, chartArea);
|
|
4572
4665
|
}
|
|
4666
|
+
const areaKeys = dedupeKeys(marks.map((m) => m.key));
|
|
4667
|
+
marks.forEach((m, i) => {
|
|
4668
|
+
m.key = areaKeys[i];
|
|
4669
|
+
});
|
|
4573
4670
|
const highlight = spec.highlight ?? [];
|
|
4574
4671
|
if (highlight.length > 0) {
|
|
4575
4672
|
const highlightSet = new Set(highlight);
|
|
@@ -4655,8 +4752,15 @@ function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4655
4752
|
let strokeDasharray;
|
|
4656
4753
|
if (styleOverride?.lineStyle === "dashed") strokeDasharray = "6 4";
|
|
4657
4754
|
else if (styleOverride?.lineStyle === "dotted") strokeDasharray = "2 3";
|
|
4755
|
+
const keyField = encoding.key && "field" in encoding.key ? encoding.key.field : void 0;
|
|
4756
|
+
const rawPointKeys = pointsWithData.map(
|
|
4757
|
+
(p) => keyField ? serializeKeyValue(p.row[keyField]) : serializeKeyValue(p.row[xChannel.field])
|
|
4758
|
+
);
|
|
4658
4759
|
const lineMark = {
|
|
4659
4760
|
type: "line",
|
|
4761
|
+
key: seriesStyleKey ?? "series",
|
|
4762
|
+
pointKeys: dedupeKeys(rawPointKeys),
|
|
4763
|
+
interpolate: spec.markDef.interpolate ?? "monotone",
|
|
4660
4764
|
points: allPoints,
|
|
4661
4765
|
path: combinedPath,
|
|
4662
4766
|
stroke: strokeColor,
|
|
@@ -4695,9 +4799,11 @@ function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4695
4799
|
}
|
|
4696
4800
|
const hollow = isEndpoints && visible;
|
|
4697
4801
|
const pointColorStr = getRepresentativeColor5(pointColor);
|
|
4802
|
+
const pointKey = keyField ? serializeKeyValue(p.row[keyField]) : seriesStyleKey ? `${seriesStyleKey}|${serializeKeyValue(p.row[xChannel.field])}` : serializeKeyValue(p.row[xChannel.field]);
|
|
4698
4803
|
if (isSingleEndpoint) {
|
|
4699
4804
|
bucket.push({
|
|
4700
4805
|
type: "point",
|
|
4806
|
+
key: pointKey,
|
|
4701
4807
|
cx: p.x,
|
|
4702
4808
|
cy: p.y,
|
|
4703
4809
|
r: 3.5,
|
|
@@ -4712,6 +4818,7 @@ function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4712
4818
|
}
|
|
4713
4819
|
const pointMark = {
|
|
4714
4820
|
type: "point",
|
|
4821
|
+
key: pointKey,
|
|
4715
4822
|
cx: p.x,
|
|
4716
4823
|
cy: p.y,
|
|
4717
4824
|
r: visible ? DEFAULT_POINT_RADIUS : 0,
|
|
@@ -4728,7 +4835,20 @@ function computeLineMarks(spec, scales, _chartArea, _strategy) {
|
|
|
4728
4835
|
}
|
|
4729
4836
|
}
|
|
4730
4837
|
}
|
|
4731
|
-
|
|
4838
|
+
const allMarks = [...mutedMarks, ...highlightedMarks];
|
|
4839
|
+
const lineMarks = allMarks.filter((m) => m.type === "line");
|
|
4840
|
+
const lineKeys = dedupeKeys(lineMarks.map((m) => m.key));
|
|
4841
|
+
lineMarks.forEach((m, i) => {
|
|
4842
|
+
m.key = lineKeys[i];
|
|
4843
|
+
});
|
|
4844
|
+
const pointMarks = allMarks.filter((m) => m.type === "point");
|
|
4845
|
+
if (pointMarks.length > 0) {
|
|
4846
|
+
const pointKeys = dedupeKeys(pointMarks.map((m) => m.key ?? ""));
|
|
4847
|
+
pointMarks.forEach((m, i) => {
|
|
4848
|
+
m.key = pointKeys[i];
|
|
4849
|
+
});
|
|
4850
|
+
}
|
|
4851
|
+
return allMarks;
|
|
4732
4852
|
}
|
|
4733
4853
|
function _getMidValue(rows, field) {
|
|
4734
4854
|
const values = rows.map((r) => Number(r[field])).filter(Number.isFinite);
|
|
@@ -5028,6 +5148,14 @@ function computePieMarks(spec, scales, chartArea, _strategy, isDonut = false) {
|
|
|
5028
5148
|
aria
|
|
5029
5149
|
});
|
|
5030
5150
|
}
|
|
5151
|
+
const rawKeys = marks.map((m) => {
|
|
5152
|
+
const label = categoryField ? String(m.data[categoryField] ?? "") : String(m.data.label ?? m.data.name ?? m.data.category ?? "");
|
|
5153
|
+
return serializeKeyValue(label);
|
|
5154
|
+
});
|
|
5155
|
+
const keys = dedupeKeys(rawKeys);
|
|
5156
|
+
for (let i = 0; i < marks.length; i++) {
|
|
5157
|
+
marks[i].key = keys[i];
|
|
5158
|
+
}
|
|
5031
5159
|
return marks;
|
|
5032
5160
|
}
|
|
5033
5161
|
|
|
@@ -5202,6 +5330,12 @@ function computeRuleMarks(spec, scales, chartArea) {
|
|
|
5202
5330
|
aria
|
|
5203
5331
|
});
|
|
5204
5332
|
}
|
|
5333
|
+
const posField = xChannel?.field ?? yChannel?.field;
|
|
5334
|
+
const rawKeys = marks.map((m, i) => posField ? serializeKeyValue(m.data[posField]) : String(i));
|
|
5335
|
+
const keys = dedupeKeys(rawKeys);
|
|
5336
|
+
for (let i = 0; i < marks.length; i++) {
|
|
5337
|
+
marks[i].key = keys[i];
|
|
5338
|
+
}
|
|
5205
5339
|
return marks;
|
|
5206
5340
|
}
|
|
5207
5341
|
var ruleRenderer = (spec, scales, chartArea, _strategy, _theme) => {
|
|
@@ -7639,6 +7773,8 @@ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
|
7639
7773
|
const [radiusMin, radiusMax] = explicitRange ?? [MIN_BUBBLE_RADIUS, MAX_BUBBLE_RADIUS];
|
|
7640
7774
|
sizeScale = sqrt2().domain([sizeMin, sizeMax]).range([radiusMin, radiusMax]).clamp(true);
|
|
7641
7775
|
}
|
|
7776
|
+
const keyEnc = encoding.key && "field" in encoding.key ? encoding.key : void 0;
|
|
7777
|
+
const keyField = keyEnc?.field;
|
|
7642
7778
|
const marks = [];
|
|
7643
7779
|
for (const row of spec.data) {
|
|
7644
7780
|
const rawX = row[xChannel.field];
|
|
@@ -7682,6 +7818,16 @@ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
|
|
|
7682
7818
|
aria
|
|
7683
7819
|
});
|
|
7684
7820
|
}
|
|
7821
|
+
const rawKeys = marks.map((m) => {
|
|
7822
|
+
if (keyField) return serializeKeyValue(m.data[keyField]);
|
|
7823
|
+
const cat = colorField ? String(m.data[colorField] ?? "") : "";
|
|
7824
|
+
const xVal = serializeKeyValue(m.data[xChannel.field]);
|
|
7825
|
+
return cat ? `${cat}|${xVal}` : xVal;
|
|
7826
|
+
});
|
|
7827
|
+
const keys = dedupeKeys(rawKeys);
|
|
7828
|
+
for (let i = 0; i < marks.length; i++) {
|
|
7829
|
+
marks[i].key = keys[i];
|
|
7830
|
+
}
|
|
7685
7831
|
return marks;
|
|
7686
7832
|
}
|
|
7687
7833
|
|
|
@@ -7799,6 +7945,12 @@ function computeTextMarks(spec, scales) {
|
|
|
7799
7945
|
aria
|
|
7800
7946
|
});
|
|
7801
7947
|
}
|
|
7948
|
+
const posField = xChannel?.field ?? yChannel?.field;
|
|
7949
|
+
const rawKeys = marks.map((m, i) => posField ? serializeKeyValue(m.data[posField]) : String(i));
|
|
7950
|
+
const keys = dedupeKeys(rawKeys);
|
|
7951
|
+
for (let i = 0; i < marks.length; i++) {
|
|
7952
|
+
marks[i].key = keys[i];
|
|
7953
|
+
}
|
|
7802
7954
|
return marks;
|
|
7803
7955
|
}
|
|
7804
7956
|
var textRenderer = (spec, scales, _chartArea, _strategy, _theme) => {
|
|
@@ -7841,6 +7993,12 @@ function computeTickMarks(spec, scales, _chartArea) {
|
|
|
7841
7993
|
aria
|
|
7842
7994
|
});
|
|
7843
7995
|
}
|
|
7996
|
+
const posField = isHorizontal ? xChannel.field : yChannel.field;
|
|
7997
|
+
const rawKeys = marks.map((m) => serializeKeyValue(m.data[posField]));
|
|
7998
|
+
const keys = dedupeKeys(rawKeys);
|
|
7999
|
+
for (let i = 0; i < marks.length; i++) {
|
|
8000
|
+
marks[i].key = keys[i];
|
|
8001
|
+
}
|
|
7844
8002
|
return marks;
|
|
7845
8003
|
}
|
|
7846
8004
|
var tickRenderer = (spec, scales, chartArea, _strategy, _theme) => {
|
|
@@ -7893,69 +8051,70 @@ var ENTER_DEFAULTS = {
|
|
|
7893
8051
|
duration: 500,
|
|
7894
8052
|
ease: "smooth",
|
|
7895
8053
|
staggerDelay: 80,
|
|
7896
|
-
staggerOrder: "index"
|
|
7897
|
-
annotationDelay: 200
|
|
8054
|
+
staggerOrder: "index"
|
|
7898
8055
|
};
|
|
8056
|
+
var UPDATE_DEFAULTS = {
|
|
8057
|
+
duration: 500,
|
|
8058
|
+
ease: "smooth",
|
|
8059
|
+
staggerDelay: 0,
|
|
8060
|
+
staggerOrder: "index"
|
|
8061
|
+
};
|
|
8062
|
+
var EXIT_DEFAULTS = {
|
|
8063
|
+
duration: 300,
|
|
8064
|
+
ease: "smooth",
|
|
8065
|
+
staggerDelay: 0,
|
|
8066
|
+
staggerOrder: "index"
|
|
8067
|
+
};
|
|
8068
|
+
var DEFAULT_ANNOTATION_DELAY = 200;
|
|
7899
8069
|
var MAX_TOTAL_STAGGER_MS = 2e3;
|
|
7900
8070
|
function resolveAnimation(spec) {
|
|
7901
8071
|
if (spec === void 0 || spec === false) return void 0;
|
|
7902
8072
|
if (spec === true) {
|
|
7903
8073
|
return {
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
staggerOrder: ENTER_DEFAULTS.staggerOrder,
|
|
7909
|
-
annotationDelay: ENTER_DEFAULTS.annotationDelay
|
|
8074
|
+
enter: { ...ENTER_DEFAULTS },
|
|
8075
|
+
update: { ...UPDATE_DEFAULTS },
|
|
8076
|
+
exit: { ...EXIT_DEFAULTS },
|
|
8077
|
+
annotationDelay: DEFAULT_ANNOTATION_DELAY
|
|
7910
8078
|
};
|
|
7911
8079
|
}
|
|
7912
8080
|
const config = spec;
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
8081
|
+
const enter = resolvePhase(config.enter, ENTER_DEFAULTS);
|
|
8082
|
+
const update = resolvePhase(config.update, UPDATE_DEFAULTS);
|
|
8083
|
+
const exit = resolvePhase(config.exit, EXIT_DEFAULTS);
|
|
8084
|
+
if (!enter && !update && !exit) return void 0;
|
|
7917
8085
|
return {
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
staggerOrder: enterConfig.staggerOrder,
|
|
7923
|
-
annotationDelay: config.annotationDelay ?? ENTER_DEFAULTS.annotationDelay
|
|
8086
|
+
enter: enter ?? void 0,
|
|
8087
|
+
update: update ?? void 0,
|
|
8088
|
+
exit: exit ?? void 0,
|
|
8089
|
+
annotationDelay: config.annotationDelay ?? DEFAULT_ANNOTATION_DELAY
|
|
7924
8090
|
};
|
|
7925
8091
|
}
|
|
7926
8092
|
function clampStaggerDelay(delay, elementCount) {
|
|
7927
8093
|
if (elementCount <= 1) return 0;
|
|
7928
8094
|
return Math.min(delay, MAX_TOTAL_STAGGER_MS / elementCount);
|
|
7929
8095
|
}
|
|
7930
|
-
function
|
|
7931
|
-
|
|
7932
|
-
}
|
|
7933
|
-
function resolvePhaseConfig(phase) {
|
|
8096
|
+
function resolvePhase(phase, defaults) {
|
|
8097
|
+
if (phase === false) return null;
|
|
7934
8098
|
if (phase === void 0 || phase === true) {
|
|
7935
|
-
return {
|
|
7936
|
-
duration: ENTER_DEFAULTS.duration,
|
|
7937
|
-
ease: ENTER_DEFAULTS.ease,
|
|
7938
|
-
staggerDelay: ENTER_DEFAULTS.staggerDelay,
|
|
7939
|
-
staggerOrder: ENTER_DEFAULTS.staggerOrder
|
|
7940
|
-
};
|
|
8099
|
+
return { ...defaults };
|
|
7941
8100
|
}
|
|
7942
8101
|
const cfg = phase;
|
|
7943
|
-
const stagger = resolveStagger(cfg.stagger);
|
|
8102
|
+
const stagger = resolveStagger(cfg.stagger, defaults);
|
|
7944
8103
|
return {
|
|
7945
|
-
duration: cfg.duration ??
|
|
7946
|
-
ease: cfg.ease ??
|
|
8104
|
+
duration: cfg.duration ?? defaults.duration,
|
|
8105
|
+
ease: cfg.ease ?? defaults.ease,
|
|
7947
8106
|
staggerDelay: stagger.delay,
|
|
7948
8107
|
staggerOrder: stagger.order
|
|
7949
8108
|
};
|
|
7950
8109
|
}
|
|
7951
|
-
function resolveStagger(stagger) {
|
|
8110
|
+
function resolveStagger(stagger, defaults) {
|
|
7952
8111
|
if (stagger === false) return { delay: 0, order: "index" };
|
|
7953
8112
|
if (stagger === void 0 || stagger === true) {
|
|
7954
|
-
return { delay:
|
|
8113
|
+
return { delay: defaults.staggerDelay, order: defaults.staggerOrder };
|
|
7955
8114
|
}
|
|
7956
8115
|
return {
|
|
7957
|
-
delay: stagger.delay ??
|
|
7958
|
-
order: stagger.order ??
|
|
8116
|
+
delay: stagger.delay ?? defaults.staggerDelay,
|
|
8117
|
+
order: stagger.order ?? defaults.staggerOrder
|
|
7959
8118
|
};
|
|
7960
8119
|
}
|
|
7961
8120
|
|
|
@@ -8160,7 +8319,7 @@ function inferFieldType(data, field) {
|
|
|
8160
8319
|
}
|
|
8161
8320
|
function inferEncodingTypes(encoding, data, warnings) {
|
|
8162
8321
|
const result = { ...encoding };
|
|
8163
|
-
for (const channel of ["x", "y", "color", "size", "detail"]) {
|
|
8322
|
+
for (const channel of ["x", "y", "color", "size", "detail", "key"]) {
|
|
8164
8323
|
const spec = result[channel];
|
|
8165
8324
|
if (!spec) continue;
|
|
8166
8325
|
if ("condition" in spec) continue;
|
|
@@ -9799,8 +9958,8 @@ function getMarkPrimaryValue(mark) {
|
|
|
9799
9958
|
}
|
|
9800
9959
|
}
|
|
9801
9960
|
function assignAnimationIndices(marks, animation) {
|
|
9802
|
-
if (!animation?.
|
|
9803
|
-
if (animation.staggerOrder === "value") {
|
|
9961
|
+
if (!animation?.enter) return;
|
|
9962
|
+
if (animation.enter.staggerOrder === "value") {
|
|
9804
9963
|
const indexed = marks.map((m, i) => ({ mark: m, idx: i }));
|
|
9805
9964
|
indexed.sort((a, b) => {
|
|
9806
9965
|
const av = getMarkPrimaryValue(a.mark);
|
|
@@ -14782,6 +14941,7 @@ import {
|
|
|
14782
14941
|
computeChrome as computeChrome7,
|
|
14783
14942
|
estimateTextWidth as estimateTextWidth20,
|
|
14784
14943
|
formatNumber as formatNumber8,
|
|
14944
|
+
pickLabelColor as pickLabelColor2,
|
|
14785
14945
|
resolveTheme as resolveTheme5,
|
|
14786
14946
|
SEQUENTIAL_PALETTES
|
|
14787
14947
|
} from "@opendata-ai/openchart-core";
|
|
@@ -14897,7 +15057,8 @@ function compileQuantitative(tilemapSpec, options, theme, chrome, fullArea, isDa
|
|
|
14897
15057
|
value: value2,
|
|
14898
15058
|
formattedValue,
|
|
14899
15059
|
hasData,
|
|
14900
|
-
theme
|
|
15060
|
+
theme,
|
|
15061
|
+
isDarkMode: !!isDarkMode
|
|
14901
15062
|
})
|
|
14902
15063
|
);
|
|
14903
15064
|
}
|
|
@@ -15024,6 +15185,7 @@ function compileCategorical(tilemapSpec, options, theme, chrome, fullArea, isDar
|
|
|
15024
15185
|
formattedValue,
|
|
15025
15186
|
hasData,
|
|
15026
15187
|
theme,
|
|
15188
|
+
isDarkMode: !!isDarkMode,
|
|
15027
15189
|
category: hasData ? category : void 0
|
|
15028
15190
|
})
|
|
15029
15191
|
);
|
|
@@ -15096,22 +15258,25 @@ function buildTileMark(opts) {
|
|
|
15096
15258
|
formattedValue,
|
|
15097
15259
|
hasData,
|
|
15098
15260
|
theme,
|
|
15261
|
+
isDarkMode,
|
|
15099
15262
|
category
|
|
15100
15263
|
} = opts;
|
|
15101
15264
|
const tileCenterX = gridOffsetX + pos.x + tileSize / 2;
|
|
15102
15265
|
const tileTopY = gridOffsetY + pos.y;
|
|
15266
|
+
const textColor = hasData ? pickLabelColor2(fill, isDarkMode) : "#ffffff";
|
|
15267
|
+
const isLightText = textColor === "#ffffff";
|
|
15103
15268
|
const labelStyle = {
|
|
15104
15269
|
fontFamily: theme.fonts.family,
|
|
15105
15270
|
fontSize: tileSize > 24 ? 10 : 7,
|
|
15106
15271
|
fontWeight: 700,
|
|
15107
|
-
fill:
|
|
15272
|
+
fill: textColor,
|
|
15108
15273
|
lineHeight: 1.2
|
|
15109
15274
|
};
|
|
15110
15275
|
const valueLabelStyle = {
|
|
15111
15276
|
fontFamily: theme.fonts.family,
|
|
15112
15277
|
fontSize: tileSize > 24 ? 10 : 7,
|
|
15113
15278
|
fontWeight: 300,
|
|
15114
|
-
fill: "rgba(255,255,255,0.6)",
|
|
15279
|
+
fill: isLightText ? "rgba(255,255,255,0.6)" : "rgba(0,0,0,0.45)",
|
|
15115
15280
|
lineHeight: 1.2
|
|
15116
15281
|
};
|
|
15117
15282
|
const valueLabel = tileSize < 24 ? { text: "", x: 0, y: 0, style: valueLabelStyle, visible: false } : {
|
|
@@ -16433,7 +16598,7 @@ function compileFaceted(chartSpec, renderSpec, facetChannel, options, theme, str
|
|
|
16433
16598
|
encoding: panelEnc
|
|
16434
16599
|
};
|
|
16435
16600
|
const panelScales = computeScales(panelSpecWithDomains, gridPanel.area, panelData);
|
|
16436
|
-
applyColorScaleRange(panelScales, panelSpecWithDomains.encoding, theme);
|
|
16601
|
+
applyColorScaleRange(panelScales, panelSpecWithDomains.encoding, theme, renderSpec.highlight);
|
|
16437
16602
|
panelScales.defaultColor = chartSpec.markDef.fill ?? chartSpec.markDef.stroke ?? theme.colors.categorical[0];
|
|
16438
16603
|
const isLeftCol = gridPanel.col === 0;
|
|
16439
16604
|
const isBottomRow = gridPanel.row === grid.rows - 1;
|
|
@@ -16566,6 +16731,11 @@ function compileBarList2(spec, options) {
|
|
|
16566
16731
|
return compileBarList(spec, options);
|
|
16567
16732
|
}
|
|
16568
16733
|
export {
|
|
16734
|
+
ENTER_DEFAULTS,
|
|
16735
|
+
EXIT_DEFAULTS,
|
|
16736
|
+
UPDATE_DEFAULTS,
|
|
16737
|
+
buildAreaPath,
|
|
16738
|
+
buildLinePath,
|
|
16569
16739
|
clampStaggerDelay,
|
|
16570
16740
|
clearRenderers,
|
|
16571
16741
|
compile,
|
|
@@ -16576,6 +16746,7 @@ export {
|
|
|
16576
16746
|
compileSankey2 as compileSankey,
|
|
16577
16747
|
compileTable,
|
|
16578
16748
|
compileTileMap2 as compileTileMap,
|
|
16749
|
+
dedupeKeys,
|
|
16579
16750
|
evaluatePredicate,
|
|
16580
16751
|
getChartRenderer,
|
|
16581
16752
|
heuristicMeasure,
|
|
@@ -16589,6 +16760,7 @@ export {
|
|
|
16589
16760
|
runFilter,
|
|
16590
16761
|
runTimeUnit,
|
|
16591
16762
|
runTransforms,
|
|
16763
|
+
serializeKeyValue,
|
|
16592
16764
|
validateSpec
|
|
16593
16765
|
};
|
|
16594
16766
|
//# sourceMappingURL=index.js.map
|