@opendata-ai/openchart-engine 7.2.0 → 7.2.2
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.js +56 -20
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/__snapshots__/compile-snapshot.test.ts.snap +3 -3
- package/src/__tests__/compile-chart.test.ts +53 -0
- package/src/__tests__/scales.test.ts +34 -0
- package/src/annotations/__tests__/compute.test.ts +64 -0
- package/src/annotations/resolve-range.ts +23 -6
- package/src/charts/line/index.ts +53 -3
- package/src/compile.ts +19 -9
- package/src/layout/dimensions.ts +10 -10
- package/src/layout/scales.ts +5 -1
package/dist/index.js
CHANGED
|
@@ -766,16 +766,18 @@ function resolveRangeAnnotation(annotation, scales, chartArea, isDark) {
|
|
|
766
766
|
let y2 = chartArea.y;
|
|
767
767
|
let width = chartArea.width;
|
|
768
768
|
let height = chartArea.height;
|
|
769
|
+
const extend2 = annotation.extendToEdges !== false;
|
|
770
|
+
const resolveEdge = (value2, scale, edge) => extend2 ? resolvePositionEdge(value2, scale, edge) : resolvePosition(value2, scale);
|
|
769
771
|
if (annotation.x1 !== void 0 && annotation.x2 !== void 0) {
|
|
770
|
-
const x1px =
|
|
771
|
-
const x2px =
|
|
772
|
+
const x1px = resolveEdge(annotation.x1, scales.x, "start");
|
|
773
|
+
const x2px = resolveEdge(annotation.x2, scales.x, "end");
|
|
772
774
|
if (x1px === null || x2px === null) return null;
|
|
773
775
|
x2 = Math.min(x1px, x2px);
|
|
774
776
|
width = Math.abs(x2px - x1px);
|
|
775
777
|
}
|
|
776
778
|
if (annotation.y1 !== void 0 && annotation.y2 !== void 0) {
|
|
777
|
-
const y1px =
|
|
778
|
-
const y2px =
|
|
779
|
+
const y1px = resolveEdge(annotation.y1, scales.y, "end");
|
|
780
|
+
const y2px = resolveEdge(annotation.y2, scales.y, "start");
|
|
779
781
|
if (y1px === null || y2px === null) return null;
|
|
780
782
|
y2 = Math.min(y1px, y2px);
|
|
781
783
|
height = Math.abs(y2px - y1px);
|
|
@@ -788,7 +790,12 @@ function resolveRangeAnnotation(annotation, scales, chartArea, isDark) {
|
|
|
788
790
|
const baseDx = centered ? 0 : anchor === "right" ? -4 : 4;
|
|
789
791
|
const baseDy = 14;
|
|
790
792
|
const labelDelta = applyOffset({ dx: baseDx, dy: baseDy }, annotation.labelOffset);
|
|
791
|
-
const style = makeAnnotationLabelStyle(
|
|
793
|
+
const style = makeAnnotationLabelStyle(
|
|
794
|
+
annotation.fontSize ?? 11,
|
|
795
|
+
annotation.fontWeight ?? 500,
|
|
796
|
+
void 0,
|
|
797
|
+
isDark
|
|
798
|
+
);
|
|
792
799
|
if (centered) {
|
|
793
800
|
style.textAnchor = "middle";
|
|
794
801
|
} else if (anchor === "right") {
|
|
@@ -3932,6 +3939,7 @@ function computeLineLabels(marks, strategy, density = "auto", labelOffsets, spec
|
|
|
3932
3939
|
}
|
|
3933
3940
|
|
|
3934
3941
|
// src/charts/line/index.ts
|
|
3942
|
+
var AREA_POINT_RADIUS = 3;
|
|
3935
3943
|
var lineRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
3936
3944
|
const marks = computeLineMarks(spec, scales, chartArea, strategy);
|
|
3937
3945
|
const lineMarks = marks.filter((m) => m.type === "line");
|
|
@@ -3957,7 +3965,8 @@ var areaRenderer = (spec, scales, chartArea, strategy, theme) => {
|
|
|
3957
3965
|
const encoding = spec.encoding;
|
|
3958
3966
|
const hasColor = !!(encoding.color && "field" in encoding.color);
|
|
3959
3967
|
const lines = hasColor ? linesFromAreas(areas) : computeLineMarks(spec, scales, chartArea, strategy);
|
|
3960
|
-
|
|
3968
|
+
const points = hasColor && spec.markDef.point ? pointsFromAreas(areas, spec.markDef.point) : [];
|
|
3969
|
+
return [...areas, ...lines, ...points];
|
|
3961
3970
|
};
|
|
3962
3971
|
function linesFromAreas(areas) {
|
|
3963
3972
|
return areas.map((a) => ({
|
|
@@ -3972,6 +3981,34 @@ function linesFromAreas(areas) {
|
|
|
3972
3981
|
aria: { label: `${a.seriesKey ?? "Series"}: line with ${a.topPoints.length} data points` }
|
|
3973
3982
|
}));
|
|
3974
3983
|
}
|
|
3984
|
+
function pointsFromAreas(areas, pointMode) {
|
|
3985
|
+
const isTransparent = pointMode === "transparent";
|
|
3986
|
+
const isEndpoints = pointMode === "endpoints";
|
|
3987
|
+
const points = [];
|
|
3988
|
+
for (const a of areas) {
|
|
3989
|
+
const stroke = getRepresentativeColor6(a.fill);
|
|
3990
|
+
const lastIdx = a.topPoints.length - 1;
|
|
3991
|
+
for (let i = 0; i < a.topPoints.length; i++) {
|
|
3992
|
+
const pt = a.topPoints[i];
|
|
3993
|
+
const isEndpoint = i === 0 || i === lastIdx;
|
|
3994
|
+
const visible = !isTransparent && (!isEndpoints || isEndpoint);
|
|
3995
|
+
const hollow = isEndpoints && visible;
|
|
3996
|
+
points.push({
|
|
3997
|
+
type: "point",
|
|
3998
|
+
cx: pt.x,
|
|
3999
|
+
cy: pt.y,
|
|
4000
|
+
r: visible ? AREA_POINT_RADIUS : 0,
|
|
4001
|
+
fill: hollow ? "transparent" : stroke,
|
|
4002
|
+
stroke: hollow ? stroke : visible ? "#ffffff" : "transparent",
|
|
4003
|
+
strokeWidth: visible ? 1.5 : 0,
|
|
4004
|
+
fillOpacity: isTransparent ? 0 : 1,
|
|
4005
|
+
data: a.data[i] ?? {},
|
|
4006
|
+
aria: { decorative: true }
|
|
4007
|
+
});
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
return points;
|
|
4011
|
+
}
|
|
3975
4012
|
|
|
3976
4013
|
// src/charts/pie/compute.ts
|
|
3977
4014
|
import { isConditionalDef, isGradientDef as isGradientDef4 } from "@opendata-ai/openchart-core";
|
|
@@ -8943,9 +8980,9 @@ function compileLayerIndependent(leaves, layerSpec, options, compileChart2) {
|
|
|
8943
8980
|
const hasRightAxisTitle = !!yAxisConfig?.title;
|
|
8944
8981
|
const tickExtent = TICK_LABEL_OFFSET + rightAxisWidth;
|
|
8945
8982
|
const bodyFontSize = theme.fonts?.sizes?.body ?? 13;
|
|
8946
|
-
const
|
|
8983
|
+
const axisTitleOffset2 = getAxisTitleOffset(options.width);
|
|
8947
8984
|
const halfGlyph = Math.ceil(bodyFontSize / 2);
|
|
8948
|
-
const titleExtent = hasRightAxisTitle ?
|
|
8985
|
+
const titleExtent = hasRightAxisTitle ? axisTitleOffset2 + halfGlyph + (options.width < BREAKPOINT_COMPACT_MAX ? 0 : AXIS_TITLE_TRAILING_PAD) : 0;
|
|
8949
8986
|
const rightReserve = Math.max(tickExtent, titleExtent);
|
|
8950
8987
|
const optionsWithReserve = {
|
|
8951
8988
|
...options,
|
|
@@ -10157,12 +10194,11 @@ function computeAxes(scales, chartArea, strategy, theme, measureText, dataContex
|
|
|
10157
10194
|
|
|
10158
10195
|
// src/layout/dimensions.ts
|
|
10159
10196
|
import {
|
|
10160
|
-
AXIS_TITLE_GAP,
|
|
10161
10197
|
AXIS_TITLE_TRAILING_PAD as AXIS_TITLE_TRAILING_PAD2,
|
|
10198
|
+
axisTitleOffset,
|
|
10162
10199
|
BREAKPOINT_COMPACT_MAX as BREAKPOINT_COMPACT_MAX2,
|
|
10163
10200
|
computeChrome as computeChrome3,
|
|
10164
10201
|
estimateTextWidth as estimateTextWidth15,
|
|
10165
|
-
getAxisTitleOffset as getAxisTitleOffset2,
|
|
10166
10202
|
HPAD_COMPACT_FRACTION,
|
|
10167
10203
|
HPAD_COMPACT_MIN,
|
|
10168
10204
|
LABEL_GAP_COMPACT,
|
|
@@ -10172,7 +10208,6 @@ import {
|
|
|
10172
10208
|
MAX_LEFT_LABEL_FRACTION_MEDIUM,
|
|
10173
10209
|
MAX_LEFT_LABEL_FRACTION_MEDIUM_MAX,
|
|
10174
10210
|
NARROW_VIEWPORT_MAX,
|
|
10175
|
-
TICK_LABEL_OFFSET as TICK_LABEL_OFFSET2,
|
|
10176
10211
|
TOP_PAD_EXTRA_NARROW
|
|
10177
10212
|
} from "@opendata-ai/openchart-core";
|
|
10178
10213
|
|
|
@@ -10623,10 +10658,10 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
|
|
|
10623
10658
|
theme.fonts.weights.normal
|
|
10624
10659
|
);
|
|
10625
10660
|
}
|
|
10626
|
-
const
|
|
10627
|
-
const
|
|
10628
|
-
const halfGlyph = Math.ceil(
|
|
10629
|
-
const rotatedLabelMargin =
|
|
10661
|
+
const titleFontSize = theme.fonts.sizes.body;
|
|
10662
|
+
const offset = axisTitleOffset(estTickLabelWidth, titleFontSize, width);
|
|
10663
|
+
const halfGlyph = Math.ceil(titleFontSize / 2);
|
|
10664
|
+
const rotatedLabelMargin = offset + halfGlyph + (width < BREAKPOINT_COMPACT_MAX2 ? 0 : AXIS_TITLE_TRAILING_PAD2);
|
|
10630
10665
|
margins.left = Math.max(margins.left, hPad + rotatedLabelMargin);
|
|
10631
10666
|
}
|
|
10632
10667
|
if (options.rightAxisReserve && options.rightAxisReserve > 0) {
|
|
@@ -10978,7 +11013,7 @@ function buildBandScale(channel, data, rangeStart, rangeEnd) {
|
|
|
10978
11013
|
}
|
|
10979
11014
|
function buildPointScale(channel, data, rangeStart, rangeEnd) {
|
|
10980
11015
|
const values = channel.scale?.domain ? channel.scale.domain : applyCategoricalSort(uniqueStrings(fieldValues(data, channel.field)), channel.sort);
|
|
10981
|
-
const padding = channel.scale?.padding ?? 0.5;
|
|
11016
|
+
const padding = channel.scale?.padding ?? channel.scale?.paddingOuter ?? 0.5;
|
|
10982
11017
|
const scale = point4().domain(values).range([rangeStart, rangeEnd]).padding(padding);
|
|
10983
11018
|
if (channel.scale?.reverse) {
|
|
10984
11019
|
const [r0, r1] = scale.range();
|
|
@@ -14235,17 +14270,18 @@ function compileChart(spec, options) {
|
|
|
14235
14270
|
const chartArea = dims.chartArea;
|
|
14236
14271
|
const legendArea = { ...chartArea };
|
|
14237
14272
|
if ("entries" in legendLayout && legendLayout.entries.length > 0) {
|
|
14273
|
+
const legendInnerWidth = options.width - theme.spacing.padding - chartArea.x;
|
|
14238
14274
|
const gap = legendGap(options.width);
|
|
14239
14275
|
switch (legendLayout.position) {
|
|
14240
14276
|
case "top":
|
|
14241
|
-
legendArea.x =
|
|
14242
|
-
legendArea.width =
|
|
14277
|
+
legendArea.x = chartArea.x;
|
|
14278
|
+
legendArea.width = legendInnerWidth;
|
|
14243
14279
|
legendArea.y -= legendLayout.bounds.height + gap;
|
|
14244
14280
|
legendArea.height += legendLayout.bounds.height + gap;
|
|
14245
14281
|
break;
|
|
14246
14282
|
case "bottom":
|
|
14247
|
-
legendArea.x =
|
|
14248
|
-
legendArea.width =
|
|
14283
|
+
legendArea.x = chartArea.x;
|
|
14284
|
+
legendArea.width = legendInnerWidth;
|
|
14249
14285
|
legendArea.height += legendLayout.bounds.height + gap + dims.xAxisHeight;
|
|
14250
14286
|
break;
|
|
14251
14287
|
case "right":
|