@opendata-ai/openchart-engine 6.6.0 → 6.7.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 +2 -2
- package/dist/index.js +23 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__test-fixtures__/specs.ts +3 -3
- package/src/charts/bar/index.ts +7 -1
- package/src/charts/bar/labels.ts +2 -0
- package/src/charts/column/index.ts +7 -1
- package/src/charts/column/labels.ts +2 -0
- package/src/charts/dot/index.ts +1 -1
- package/src/charts/dot/labels.ts +3 -1
- package/src/compiler/__tests__/normalize.test.ts +18 -3
- package/src/compiler/normalize.ts +1 -0
- package/src/compiler/types.ts +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -205,8 +205,8 @@ interface NormalizedChartSpec {
|
|
|
205
205
|
encoding: Encoding;
|
|
206
206
|
chrome: NormalizedChrome;
|
|
207
207
|
annotations: Annotation[];
|
|
208
|
-
/** Normalized label configuration with defaults applied. density and
|
|
209
|
-
labels: Required<Pick<LabelConfig, 'density' | 'format'>> & Pick<LabelConfig, 'offsets'>;
|
|
208
|
+
/** Normalized label configuration with defaults applied. density, format, and prefix are always set; offsets stays optional. */
|
|
209
|
+
labels: Required<Pick<LabelConfig, 'density' | 'format' | 'prefix'>> & Pick<LabelConfig, 'offsets'>;
|
|
210
210
|
/** Legend configuration (position override). */
|
|
211
211
|
legend?: LegendConfig;
|
|
212
212
|
responsive: boolean;
|
package/dist/index.js
CHANGED
|
@@ -844,7 +844,7 @@ var LABEL_FONT_SIZE = 11;
|
|
|
844
844
|
var LABEL_FONT_WEIGHT = 600;
|
|
845
845
|
var LABEL_PADDING = 6;
|
|
846
846
|
var MIN_WIDTH_FOR_INSIDE_LABEL = 40;
|
|
847
|
-
function computeBarLabels(marks, _chartArea, density = "auto", labelFormat) {
|
|
847
|
+
function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix) {
|
|
848
848
|
if (density === "none") return [];
|
|
849
849
|
const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
|
|
850
850
|
const candidates = [];
|
|
@@ -860,6 +860,7 @@ function computeBarLabels(marks, _chartArea, density = "auto", labelFormat) {
|
|
|
860
860
|
const num = parseDisplayNumber(rawValue);
|
|
861
861
|
if (!Number.isNaN(num)) valuePart = formatter(num);
|
|
862
862
|
}
|
|
863
|
+
if (labelPrefix) valuePart = labelPrefix + valuePart;
|
|
863
864
|
const textWidth = estimateTextWidth2(valuePart, LABEL_FONT_SIZE, LABEL_FONT_WEIGHT);
|
|
864
865
|
const textHeight = LABEL_FONT_SIZE * 1.2;
|
|
865
866
|
const isStacked = mark.cornerRadius === 0;
|
|
@@ -942,7 +943,13 @@ function computeBarLabels(marks, _chartArea, density = "auto", labelFormat) {
|
|
|
942
943
|
// src/charts/bar/index.ts
|
|
943
944
|
var barRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
944
945
|
const marks = computeBarMarks(spec, scales, chartArea, strategy);
|
|
945
|
-
const labels = computeBarLabels(
|
|
946
|
+
const labels = computeBarLabels(
|
|
947
|
+
marks,
|
|
948
|
+
chartArea,
|
|
949
|
+
spec.labels.density,
|
|
950
|
+
spec.labels.format,
|
|
951
|
+
spec.labels.prefix
|
|
952
|
+
);
|
|
946
953
|
for (let i = 0; i < marks.length && i < labels.length; i++) {
|
|
947
954
|
marks[i].label = labels[i];
|
|
948
955
|
}
|
|
@@ -1131,7 +1138,7 @@ import {
|
|
|
1131
1138
|
var LABEL_FONT_SIZE2 = 10;
|
|
1132
1139
|
var LABEL_FONT_WEIGHT2 = 600;
|
|
1133
1140
|
var LABEL_OFFSET_Y = 6;
|
|
1134
|
-
function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat) {
|
|
1141
|
+
function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix) {
|
|
1135
1142
|
if (density === "none") return [];
|
|
1136
1143
|
const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
|
|
1137
1144
|
const formatter = buildD3Formatter2(labelFormat);
|
|
@@ -1146,6 +1153,7 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat) {
|
|
|
1146
1153
|
const num = Number(rawValue.replace(/[^0-9.-]/g, ""));
|
|
1147
1154
|
if (!Number.isNaN(num)) valuePart = formatter(num);
|
|
1148
1155
|
}
|
|
1156
|
+
if (labelPrefix) valuePart = labelPrefix + valuePart;
|
|
1149
1157
|
const numericValue = parseFloat(valuePart);
|
|
1150
1158
|
const isNegative = Number.isFinite(numericValue) && numericValue < 0;
|
|
1151
1159
|
const textWidth = estimateTextWidth3(valuePart, LABEL_FONT_SIZE2, LABEL_FONT_WEIGHT2);
|
|
@@ -1186,7 +1194,13 @@ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat) {
|
|
|
1186
1194
|
// src/charts/column/index.ts
|
|
1187
1195
|
var columnRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
1188
1196
|
const marks = computeColumnMarks(spec, scales, chartArea, strategy);
|
|
1189
|
-
const labels = computeColumnLabels(
|
|
1197
|
+
const labels = computeColumnLabels(
|
|
1198
|
+
marks,
|
|
1199
|
+
chartArea,
|
|
1200
|
+
spec.labels.density,
|
|
1201
|
+
spec.labels.format,
|
|
1202
|
+
spec.labels.prefix
|
|
1203
|
+
);
|
|
1190
1204
|
for (let i = 0; i < marks.length && i < labels.length; i++) {
|
|
1191
1205
|
marks[i].label = labels[i];
|
|
1192
1206
|
}
|
|
@@ -1346,15 +1360,16 @@ import { estimateTextWidth as estimateTextWidth4, resolveCollisions as resolveCo
|
|
|
1346
1360
|
var LABEL_FONT_SIZE3 = 11;
|
|
1347
1361
|
var LABEL_FONT_WEIGHT3 = 600;
|
|
1348
1362
|
var LABEL_OFFSET_X = 10;
|
|
1349
|
-
function computeDotLabels(marks, _chartArea, density = "auto") {
|
|
1363
|
+
function computeDotLabels(marks, _chartArea, density = "auto", labelPrefix) {
|
|
1350
1364
|
if (density === "none") return [];
|
|
1351
1365
|
const targetMarks = density === "endpoints" && marks.length > 1 ? [marks[0], marks[marks.length - 1]] : marks;
|
|
1352
1366
|
const candidates = [];
|
|
1353
1367
|
for (const mark of targetMarks) {
|
|
1354
1368
|
const ariaLabel = mark.aria.label;
|
|
1355
1369
|
const lastColon = ariaLabel.lastIndexOf(":");
|
|
1356
|
-
|
|
1370
|
+
let valuePart = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
|
|
1357
1371
|
if (!valuePart) continue;
|
|
1372
|
+
if (labelPrefix) valuePart = labelPrefix + valuePart;
|
|
1358
1373
|
const textWidth = estimateTextWidth4(valuePart, LABEL_FONT_SIZE3, LABEL_FONT_WEIGHT3);
|
|
1359
1374
|
const textHeight = LABEL_FONT_SIZE3 * 1.2;
|
|
1360
1375
|
candidates.push({
|
|
@@ -1392,7 +1407,7 @@ function computeDotLabels(marks, _chartArea, density = "auto") {
|
|
|
1392
1407
|
var dotRenderer = (spec, scales, chartArea, strategy, _theme) => {
|
|
1393
1408
|
const marks = computeDotMarks(spec, scales, chartArea, strategy);
|
|
1394
1409
|
const pointMarks = marks.filter((m) => m.type === "point");
|
|
1395
|
-
const labels = computeDotLabels(pointMarks, chartArea, spec.labels.density);
|
|
1410
|
+
const labels = computeDotLabels(pointMarks, chartArea, spec.labels.density, spec.labels.prefix);
|
|
1396
1411
|
let labelIdx = 0;
|
|
1397
1412
|
for (const mark of marks) {
|
|
1398
1413
|
if (mark.type === "point" && labelIdx < labels.length) {
|
|
@@ -5971,6 +5986,7 @@ function normalizeChartSpec(spec, warnings) {
|
|
|
5971
5986
|
labels: {
|
|
5972
5987
|
density: spec.labels?.density ?? "auto",
|
|
5973
5988
|
format: spec.labels?.format ?? "",
|
|
5989
|
+
prefix: spec.labels?.prefix ?? "",
|
|
5974
5990
|
offsets: spec.labels?.offsets
|
|
5975
5991
|
},
|
|
5976
5992
|
legend: spec.legend,
|