@opendata-ai/openchart-engine 6.23.0 → 6.24.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.js CHANGED
@@ -35,9 +35,9 @@ function computeTextBounds(labelX, labelY, text, fontSize, fontWeight) {
35
35
  const isMultiLine = lines.length > 1;
36
36
  const maxWidth = Math.max(...lines.map((line) => estimateTextWidth(line, fontSize, fontWeight)));
37
37
  const totalHeight = lines.length * fontSize * DEFAULT_LINE_HEIGHT;
38
- const x = isMultiLine ? labelX - maxWidth / 2 : labelX;
38
+ const x2 = isMultiLine ? labelX - maxWidth / 2 : labelX;
39
39
  return {
40
- x,
40
+ x: x2,
41
41
  y: labelY - fontSize,
42
42
  width: maxWidth,
43
43
  height: totalHeight
@@ -395,25 +395,25 @@ function resolveTextAnnotation(annotation, scales, chartArea, isDark) {
395
395
 
396
396
  // src/annotations/resolve-range.ts
397
397
  function resolveRangeAnnotation(annotation, scales, chartArea, isDark) {
398
- let x = chartArea.x;
399
- let y = chartArea.y;
398
+ let x2 = chartArea.x;
399
+ let y2 = chartArea.y;
400
400
  let width = chartArea.width;
401
401
  let height = chartArea.height;
402
402
  if (annotation.x1 !== void 0 && annotation.x2 !== void 0) {
403
403
  const x1px = resolvePosition(annotation.x1, scales.x);
404
404
  const x2px = resolvePosition(annotation.x2, scales.x);
405
405
  if (x1px === null || x2px === null) return null;
406
- x = Math.min(x1px, x2px);
406
+ x2 = Math.min(x1px, x2px);
407
407
  width = Math.abs(x2px - x1px);
408
408
  }
409
409
  if (annotation.y1 !== void 0 && annotation.y2 !== void 0) {
410
410
  const y1px = resolvePosition(annotation.y1, scales.y);
411
411
  const y2px = resolvePosition(annotation.y2, scales.y);
412
412
  if (y1px === null || y2px === null) return null;
413
- y = Math.min(y1px, y2px);
413
+ y2 = Math.min(y1px, y2px);
414
414
  height = Math.abs(y2px - y1px);
415
415
  }
416
- const rect = { x, y, width, height };
416
+ const rect = { x: x2, y: y2, width, height };
417
417
  let label;
418
418
  if (annotation.label) {
419
419
  const anchor = annotation.labelAnchor ?? "top";
@@ -427,11 +427,11 @@ function resolveRangeAnnotation(annotation, scales, chartArea, isDark) {
427
427
  } else if (anchor === "right") {
428
428
  style.textAnchor = "end";
429
429
  }
430
- const baseX = centered ? x + width / 2 : anchor === "right" ? x + width : x;
430
+ const baseX = centered ? x2 + width / 2 : anchor === "right" ? x2 + width : x2;
431
431
  label = {
432
432
  text: annotation.label,
433
433
  x: baseX + labelDelta.dx,
434
- y: y + labelDelta.dy,
434
+ y: y2 + labelDelta.dy,
435
435
  style,
436
436
  visible: true
437
437
  };
@@ -581,6 +581,9 @@ function computeAnnotations(spec, scales, chartArea, strategy, isDark = false, o
581
581
  return annotations;
582
582
  }
583
583
 
584
+ // src/charts/bar/compute.ts
585
+ import { isGradientDef } from "@opendata-ai/openchart-core";
586
+
584
587
  // src/transforms/predicates.ts
585
588
  function isFieldPredicate(pred) {
586
589
  return "field" in pred;
@@ -598,57 +601,2667 @@ function evaluateFieldPredicate(datum, pred) {
598
601
  if (pred.lt !== void 0) {
599
602
  return numValue < pred.lt;
600
603
  }
601
- if (pred.lte !== void 0) {
602
- return numValue <= pred.lte;
604
+ if (pred.lte !== void 0) {
605
+ return numValue <= pred.lte;
606
+ }
607
+ if (pred.gt !== void 0) {
608
+ return numValue > pred.gt;
609
+ }
610
+ if (pred.gte !== void 0) {
611
+ return numValue >= pred.gte;
612
+ }
613
+ if (pred.range !== void 0) {
614
+ const [min4, max4] = pred.range;
615
+ return numValue >= min4 && numValue <= max4;
616
+ }
617
+ if (pred.oneOf !== void 0) {
618
+ return pred.oneOf.some((v) => v == value2);
619
+ }
620
+ return true;
621
+ }
622
+ function evaluatePredicate(datum, predicate) {
623
+ if (isFieldPredicate(predicate)) {
624
+ return evaluateFieldPredicate(datum, predicate);
625
+ }
626
+ if ("and" in predicate) {
627
+ return predicate.and.every((p) => evaluatePredicate(datum, p));
628
+ }
629
+ if ("or" in predicate) {
630
+ return predicate.or.some((p) => evaluatePredicate(datum, p));
631
+ }
632
+ if ("not" in predicate) {
633
+ return !evaluatePredicate(datum, predicate.not);
634
+ }
635
+ return true;
636
+ }
637
+
638
+ // src/transforms/conditional.ts
639
+ function resolveConditionalValue(datum, channelDef) {
640
+ const conditions = Array.isArray(channelDef.condition) ? channelDef.condition : [channelDef.condition];
641
+ for (const cond of conditions) {
642
+ if (evaluatePredicate(datum, cond.test)) {
643
+ if (cond.field !== void 0) {
644
+ return datum[cond.field];
645
+ }
646
+ return cond.value;
647
+ }
648
+ }
649
+ return channelDef.value;
650
+ }
651
+ function isConditionalValueDef(def) {
652
+ return def !== null && typeof def === "object" && "condition" in def;
653
+ }
654
+
655
+ // src/charts/_shared/format-label-value.ts
656
+ import { abbreviateNumber, formatNumber } from "@opendata-ai/openchart-core";
657
+ function formatLabelValue(value2) {
658
+ if (Math.abs(value2) >= 1e3) return abbreviateNumber(value2);
659
+ return formatNumber(value2);
660
+ }
661
+
662
+ // src/charts/utils.ts
663
+ var DEFAULT_COLOR = "#1b7fa3";
664
+ function scaleValue(scale, scaleType, value2) {
665
+ if (value2 == null) return null;
666
+ if (scaleType === "time" || scaleType === "utc") {
667
+ const date2 = value2 instanceof Date ? value2 : new Date(String(value2));
668
+ if (Number.isNaN(date2.getTime())) return null;
669
+ return scale(date2);
670
+ }
671
+ if (scaleType === "point" || scaleType === "band" || scaleType === "ordinal") {
672
+ const result = scale(String(value2));
673
+ return result ?? null;
674
+ }
675
+ const num = typeof value2 === "number" ? value2 : Number(value2);
676
+ if (!Number.isFinite(num)) return null;
677
+ return scale(num);
678
+ }
679
+ function groupByField(data, field) {
680
+ const groups = /* @__PURE__ */ new Map();
681
+ if (!field) {
682
+ groups.set("__default__", data);
683
+ return groups;
684
+ }
685
+ for (const row of data) {
686
+ const key = String(row[field] ?? "__default__");
687
+ const existing = groups.get(key);
688
+ if (existing) {
689
+ existing.push(row);
690
+ } else {
691
+ groups.set(key, [row]);
692
+ }
693
+ }
694
+ return groups;
695
+ }
696
+ function sortByField(data, field) {
697
+ if (data.length <= 1) return [...data];
698
+ return [...data].sort((a, b) => {
699
+ const aVal = a[field];
700
+ const bVal = b[field];
701
+ if (aVal == null && bVal == null) return 0;
702
+ if (aVal == null) return 1;
703
+ if (bVal == null) return -1;
704
+ if (typeof aVal === "number" && typeof bVal === "number") {
705
+ return aVal - bVal;
706
+ }
707
+ if (aVal instanceof Date && bVal instanceof Date) {
708
+ return aVal.getTime() - bVal.getTime();
709
+ }
710
+ const aStr = String(aVal);
711
+ const bStr = String(bVal);
712
+ const aNum = Number(aStr);
713
+ const bNum = Number(bStr);
714
+ if (Number.isFinite(aNum) && Number.isFinite(bNum)) {
715
+ return aNum - bNum;
716
+ }
717
+ return aStr.localeCompare(bStr);
718
+ });
719
+ }
720
+ function getColor(scales, key, _index, fallback = DEFAULT_COLOR) {
721
+ if (scales.color && key !== "__default__") {
722
+ const colorScale = scales.color.scale;
723
+ return colorScale(key);
724
+ }
725
+ return scales.defaultColor ?? fallback;
726
+ }
727
+ function getSequentialColor(scales, value2, fallback = DEFAULT_COLOR) {
728
+ if (scales.color?.type === "sequential") {
729
+ const colorScale = scales.color.scale;
730
+ return colorScale(value2);
731
+ }
732
+ return scales.defaultColor ?? fallback;
733
+ }
734
+
735
+ // src/charts/bar/compute.ts
736
+ function orientGradientForHorizontalBar(grad) {
737
+ if (grad.gradient !== "linear") return grad;
738
+ const lg = grad;
739
+ const isDefaultVertical = (lg.x1 === void 0 || lg.x1 === 0) && (lg.y1 === void 0 || lg.y1 === 0) && (lg.x2 === void 0 || lg.x2 === 0) && (lg.y2 === void 0 || lg.y2 === 1);
740
+ if (!isDefaultVertical) return grad;
741
+ return { ...lg, x1: 0, y1: 0, x2: 1, y2: 0 };
742
+ }
743
+ var MIN_BAR_WIDTH = 1;
744
+ function computeBarMarks(spec, scales, _chartArea, _strategy) {
745
+ const encoding = spec.encoding;
746
+ const xChannel = encoding.x;
747
+ const yChannel = encoding.y;
748
+ if (!xChannel || !yChannel || !scales.x || !scales.y) {
749
+ return [];
750
+ }
751
+ const yScale = scales.y.scale;
752
+ const xScale = scales.x.scale;
753
+ if (typeof yScale.bandwidth !== "function") {
754
+ return [];
755
+ }
756
+ const bandwidth = yScale.bandwidth();
757
+ const baseline = xScale(0);
758
+ const colorEnc = encoding.color && "field" in encoding.color ? encoding.color : void 0;
759
+ const conditionalColor = encoding.color && isConditionalValueDef(encoding.color) ? encoding.color : void 0;
760
+ const colorField = colorEnc?.field;
761
+ const isSequentialColor = colorEnc?.type === "quantitative";
762
+ if (!colorField || isSequentialColor) {
763
+ return computeSimpleBars(
764
+ spec.data,
765
+ xChannel.field,
766
+ yChannel.field,
767
+ xScale,
768
+ yScale,
769
+ bandwidth,
770
+ baseline,
771
+ scales,
772
+ isSequentialColor,
773
+ conditionalColor
774
+ );
775
+ }
776
+ const categoryGroups = groupByField(spec.data, yChannel.field);
777
+ const needsStacking = Array.from(categoryGroups.values()).some((rows) => rows.length > 1);
778
+ if (needsStacking) {
779
+ const stackDisabled = xChannel.stack === null || xChannel.stack === false;
780
+ if (stackDisabled) {
781
+ return computeGroupedBars(
782
+ spec.data,
783
+ xChannel.field,
784
+ yChannel.field,
785
+ colorField,
786
+ xScale,
787
+ yScale,
788
+ bandwidth,
789
+ baseline,
790
+ scales
791
+ );
792
+ }
793
+ const stackMode = xChannel.stack === "normalize" ? "normalize" : xChannel.stack === "center" ? "center" : "zero";
794
+ return computeStackedBars(
795
+ spec.data,
796
+ xChannel.field,
797
+ yChannel.field,
798
+ colorField,
799
+ xScale,
800
+ yScale,
801
+ bandwidth,
802
+ baseline,
803
+ scales,
804
+ stackMode
805
+ );
806
+ }
807
+ return computeColoredBars(
808
+ spec.data,
809
+ xChannel.field,
810
+ yChannel.field,
811
+ colorField,
812
+ xScale,
813
+ yScale,
814
+ bandwidth,
815
+ baseline,
816
+ scales
817
+ );
818
+ }
819
+ function computeStackedBars(data, valueField, categoryField, colorField, xScale, yScale, bandwidth, _baseline, scales, stackMode = "zero") {
820
+ const marks = [];
821
+ const categoryGroups = groupByField(data, categoryField);
822
+ for (const [category, rows] of categoryGroups) {
823
+ const bandY = yScale(category);
824
+ if (bandY === void 0) continue;
825
+ let categoryTotal = 0;
826
+ for (const row of rows) {
827
+ const v = Number(row[valueField] ?? 0);
828
+ if (Number.isFinite(v) && v > 0) categoryTotal += v;
829
+ }
830
+ let cumulativeValue = stackMode === "center" ? -categoryTotal / 2 : 0;
831
+ for (const row of rows) {
832
+ const groupKey2 = String(row[colorField] ?? "");
833
+ const rawValue = Number(row[valueField] ?? 0);
834
+ if (!Number.isFinite(rawValue) || rawValue <= 0) continue;
835
+ const value2 = stackMode === "normalize" && categoryTotal > 0 ? rawValue / categoryTotal : rawValue;
836
+ const color2 = getColor(scales, groupKey2);
837
+ const xLeft = xScale(cumulativeValue);
838
+ const xRight = xScale(cumulativeValue + value2);
839
+ const barWidth = Math.max(Math.abs(xRight - xLeft), MIN_BAR_WIDTH);
840
+ const aria = {
841
+ label: `${category}, ${groupKey2}: ${formatLabelValue(rawValue)}`
842
+ };
843
+ marks.push({
844
+ type: "rect",
845
+ x: Math.min(xLeft, xRight),
846
+ y: bandY,
847
+ width: barWidth,
848
+ height: bandwidth,
849
+ fill: isGradientDef(color2) ? orientGradientForHorizontalBar(color2) : color2,
850
+ cornerRadius: 0,
851
+ data: row,
852
+ aria,
853
+ orient: "horizontal",
854
+ stackGroup: category
855
+ });
856
+ cumulativeValue += value2;
857
+ }
858
+ }
859
+ return marks;
860
+ }
861
+ function computeGroupedBars(data, valueField, categoryField, colorField, xScale, yScale, bandwidth, baseline, scales) {
862
+ const marks = [];
863
+ const categoryGroups = groupByField(data, categoryField);
864
+ const groupIndexMap = /* @__PURE__ */ new Map();
865
+ for (const row of data) {
866
+ const key = String(row[colorField] ?? "");
867
+ if (!groupIndexMap.has(key)) {
868
+ groupIndexMap.set(key, groupIndexMap.size);
869
+ }
870
+ }
871
+ const groupCount = groupIndexMap.size;
872
+ if (groupCount === 0) return marks;
873
+ const gap = Math.min(1, bandwidth * 0.05);
874
+ const subBandHeight = Math.max((bandwidth - gap * (groupCount - 1)) / groupCount, MIN_BAR_WIDTH);
875
+ for (const [category, rows] of categoryGroups) {
876
+ const bandY = yScale(category);
877
+ if (bandY === void 0) continue;
878
+ for (const row of rows) {
879
+ const groupKey2 = String(row[colorField] ?? "");
880
+ const value2 = Number(row[valueField] ?? 0);
881
+ if (!Number.isFinite(value2)) continue;
882
+ const groupIndex = groupIndexMap.get(groupKey2) ?? 0;
883
+ const color2 = getColor(scales, groupKey2);
884
+ const xPos = value2 >= 0 ? baseline : xScale(value2);
885
+ const barWidth = Math.max(Math.abs(xScale(value2) - baseline), MIN_BAR_WIDTH);
886
+ const subY = bandY + groupIndex * (subBandHeight + gap);
887
+ const aria = {
888
+ label: `${category}, ${groupKey2}: ${formatLabelValue(value2)}`
889
+ };
890
+ marks.push({
891
+ type: "rect",
892
+ x: xPos,
893
+ y: subY,
894
+ width: barWidth,
895
+ height: subBandHeight,
896
+ fill: isGradientDef(color2) ? orientGradientForHorizontalBar(color2) : color2,
897
+ cornerRadius: 2,
898
+ data: row,
899
+ aria,
900
+ orient: "horizontal"
901
+ });
902
+ }
903
+ }
904
+ return marks;
905
+ }
906
+ function computeColoredBars(data, valueField, categoryField, colorField, xScale, yScale, bandwidth, baseline, scales) {
907
+ const marks = [];
908
+ for (const row of data) {
909
+ const category = String(row[categoryField] ?? "");
910
+ const value2 = Number(row[valueField] ?? 0);
911
+ if (!Number.isFinite(value2)) continue;
912
+ const bandY = yScale(category);
913
+ if (bandY === void 0) continue;
914
+ const groupKey2 = String(row[colorField] ?? "");
915
+ const color2 = getColor(scales, groupKey2);
916
+ const xPos = value2 >= 0 ? baseline : xScale(value2);
917
+ const barWidth = Math.max(Math.abs(xScale(value2) - baseline), MIN_BAR_WIDTH);
918
+ const aria = {
919
+ label: `${category}, ${groupKey2}: ${formatLabelValue(value2)}`
920
+ };
921
+ marks.push({
922
+ type: "rect",
923
+ x: xPos,
924
+ y: bandY,
925
+ width: barWidth,
926
+ height: bandwidth,
927
+ fill: isGradientDef(color2) ? orientGradientForHorizontalBar(color2) : color2,
928
+ cornerRadius: 2,
929
+ data: row,
930
+ aria,
931
+ orient: "horizontal"
932
+ });
933
+ }
934
+ return marks;
935
+ }
936
+ function computeSimpleBars(data, valueField, categoryField, xScale, yScale, bandwidth, baseline, scales, sequentialColor = false, conditionalColor) {
937
+ const marks = [];
938
+ for (const row of data) {
939
+ const category = String(row[categoryField] ?? "");
940
+ const value2 = Number(row[valueField] ?? 0);
941
+ if (!Number.isFinite(value2)) continue;
942
+ const bandY = yScale(category);
943
+ if (bandY === void 0) continue;
944
+ let color2;
945
+ if (conditionalColor) {
946
+ const resolved = resolveConditionalValue(row, conditionalColor);
947
+ if (resolved != null) {
948
+ color2 = isGradientDef(resolved) ? resolved : String(resolved);
949
+ } else {
950
+ color2 = getColor(scales, "__default__");
951
+ }
952
+ } else if (sequentialColor) {
953
+ color2 = getSequentialColor(scales, value2);
954
+ } else {
955
+ color2 = getColor(scales, "__default__");
956
+ }
957
+ const xPos = value2 >= 0 ? baseline : xScale(value2);
958
+ const barWidth = Math.max(Math.abs(xScale(value2) - baseline), MIN_BAR_WIDTH);
959
+ const aria = {
960
+ label: `${category}: ${formatLabelValue(value2)}`
961
+ };
962
+ marks.push({
963
+ type: "rect",
964
+ x: xPos,
965
+ y: bandY,
966
+ width: barWidth,
967
+ height: bandwidth,
968
+ fill: isGradientDef(color2) ? orientGradientForHorizontalBar(color2) : color2,
969
+ cornerRadius: 2,
970
+ data: row,
971
+ aria,
972
+ orient: "horizontal"
973
+ });
974
+ }
975
+ return marks;
976
+ }
977
+
978
+ // src/charts/bar/labels.ts
979
+ import {
980
+ buildD3Formatter,
981
+ estimateTextWidth as estimateTextWidth2,
982
+ getRepresentativeColor,
983
+ resolveCollisions
984
+ } from "@opendata-ai/openchart-core";
985
+
986
+ // src/charts/_shared/density-filter.ts
987
+ function filterByDensity(marks, density) {
988
+ if (density === "none") return [];
989
+ if (density === "endpoints" && marks.length > 1) {
990
+ return [marks[0], marks[marks.length - 1]];
991
+ }
992
+ return marks;
993
+ }
994
+
995
+ // src/charts/bar/labels.ts
996
+ var SUFFIX_MULTIPLIERS = {
997
+ K: 1e3,
998
+ M: 1e6,
999
+ B: 1e9,
1000
+ T: 1e12
1001
+ };
1002
+ function parseDisplayNumber(raw) {
1003
+ const trimmed = raw.trim().replace(/\u2212/g, "-");
1004
+ if (!trimmed) return NaN;
1005
+ const last = trimmed[trimmed.length - 1].toUpperCase();
1006
+ const multiplier = SUFFIX_MULTIPLIERS[last];
1007
+ if (multiplier) {
1008
+ const numPart = trimmed.slice(0, -1).replace(/,/g, "");
1009
+ const n = Number(numPart);
1010
+ return Number.isNaN(n) ? NaN : n * multiplier;
1011
+ }
1012
+ if (last === "%") {
1013
+ return Number(trimmed.slice(0, -1).replace(/,/g, ""));
1014
+ }
1015
+ return Number(trimmed.replace(/,/g, ""));
1016
+ }
1017
+ var LABEL_FONT_SIZE = 11;
1018
+ var LABEL_FONT_WEIGHT = 600;
1019
+ var LABEL_PADDING = 6;
1020
+ var MIN_WIDTH_FOR_INSIDE_LABEL = 40;
1021
+ function computeBarLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix, valueField) {
1022
+ const targetMarks = filterByDensity(marks, density);
1023
+ const candidates = [];
1024
+ const fitsInSegment = [];
1025
+ const formatter = buildD3Formatter(labelFormat);
1026
+ for (const mark of targetMarks) {
1027
+ let valuePart;
1028
+ const rawNum = valueField != null ? Number(mark.data[valueField]) : NaN;
1029
+ if (formatter && Number.isFinite(rawNum)) {
1030
+ valuePart = formatter(rawNum);
1031
+ } else if (Number.isFinite(rawNum)) {
1032
+ valuePart = formatLabelValue(rawNum);
1033
+ } else {
1034
+ const ariaLabel = mark.aria.label;
1035
+ const lastColon = ariaLabel.lastIndexOf(":");
1036
+ const rawValue = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
1037
+ if (!rawValue) continue;
1038
+ if (formatter) {
1039
+ const num = parseDisplayNumber(rawValue);
1040
+ valuePart = !Number.isNaN(num) ? formatter(num) : rawValue;
1041
+ } else {
1042
+ valuePart = rawValue;
1043
+ }
1044
+ }
1045
+ if (labelPrefix) valuePart = labelPrefix + valuePart;
1046
+ const textWidth = estimateTextWidth2(valuePart, LABEL_FONT_SIZE, LABEL_FONT_WEIGHT);
1047
+ const textHeight = LABEL_FONT_SIZE * 1.2;
1048
+ const isStacked = mark.cornerRadius === 0;
1049
+ const isInside = mark.width >= MIN_WIDTH_FOR_INSIDE_LABEL;
1050
+ let anchorX;
1051
+ let fill;
1052
+ let textAnchor;
1053
+ if (isStacked && isInside) {
1054
+ anchorX = mark.x + mark.width / 2;
1055
+ fill = "#ffffff";
1056
+ textAnchor = "middle";
1057
+ } else if (isInside) {
1058
+ anchorX = mark.x + mark.width - LABEL_PADDING;
1059
+ fill = "#ffffff";
1060
+ textAnchor = "end";
1061
+ } else {
1062
+ anchorX = mark.x + mark.width + LABEL_PADDING;
1063
+ fill = getRepresentativeColor(mark.fill);
1064
+ textAnchor = "start";
1065
+ }
1066
+ const anchorY = mark.y + mark.height / 2;
1067
+ const fits = !(isStacked && textWidth > mark.width - 2 * LABEL_PADDING);
1068
+ fitsInSegment.push(fits);
1069
+ candidates.push({
1070
+ text: valuePart,
1071
+ anchorX,
1072
+ anchorY,
1073
+ width: textWidth,
1074
+ height: textHeight,
1075
+ priority: "data",
1076
+ style: {
1077
+ fontFamily: "system-ui, -apple-system, sans-serif",
1078
+ fontSize: LABEL_FONT_SIZE,
1079
+ fontWeight: LABEL_FONT_WEIGHT,
1080
+ fill,
1081
+ lineHeight: 1.2,
1082
+ textAnchor,
1083
+ dominantBaseline: "central"
1084
+ }
1085
+ });
1086
+ }
1087
+ if (candidates.length === 0) return [];
1088
+ if (density === "all") {
1089
+ return candidates.map((c, i) => ({
1090
+ text: c.text,
1091
+ x: c.anchorX,
1092
+ y: c.anchorY,
1093
+ style: c.style,
1094
+ visible: fitsInSegment[i] !== false
1095
+ }));
1096
+ }
1097
+ const fittingCandidates = [];
1098
+ const unfittingIndices = /* @__PURE__ */ new Set();
1099
+ for (let i = 0; i < candidates.length; i++) {
1100
+ if (fitsInSegment[i] === false) {
1101
+ unfittingIndices.add(i);
1102
+ } else {
1103
+ fittingCandidates.push(candidates[i]);
1104
+ }
1105
+ }
1106
+ const resolved = resolveCollisions(fittingCandidates);
1107
+ const results = [];
1108
+ let resolvedIdx = 0;
1109
+ for (let i = 0; i < candidates.length; i++) {
1110
+ if (unfittingIndices.has(i)) {
1111
+ results.push({
1112
+ text: candidates[i].text,
1113
+ x: candidates[i].anchorX,
1114
+ y: candidates[i].anchorY,
1115
+ style: candidates[i].style,
1116
+ visible: false
1117
+ });
1118
+ } else {
1119
+ results.push(resolved[resolvedIdx++]);
1120
+ }
1121
+ }
1122
+ return results;
1123
+ }
1124
+
1125
+ // src/charts/bar/index.ts
1126
+ var barRenderer = (spec, scales, chartArea, strategy, _theme) => {
1127
+ const marks = computeBarMarks(spec, scales, chartArea, strategy);
1128
+ const valueField = spec.encoding?.x && "field" in spec.encoding.x ? spec.encoding.x.field : void 0;
1129
+ const labels = computeBarLabels(
1130
+ marks,
1131
+ chartArea,
1132
+ spec.labels.density,
1133
+ spec.labels.format,
1134
+ spec.labels.prefix,
1135
+ valueField
1136
+ );
1137
+ for (let i = 0; i < marks.length && i < labels.length; i++) {
1138
+ marks[i].label = labels[i];
1139
+ }
1140
+ return marks;
1141
+ };
1142
+
1143
+ // src/charts/column/compute.ts
1144
+ import { isGradientDef as isGradientDef2 } from "@opendata-ai/openchart-core";
1145
+ var MIN_COLUMN_HEIGHT = 1;
1146
+ function computeColumnMarks(spec, scales, _chartArea, _strategy) {
1147
+ const encoding = spec.encoding;
1148
+ const xChannel = encoding.x;
1149
+ const yChannel = encoding.y;
1150
+ if (!xChannel || !yChannel || !scales.x || !scales.y) {
1151
+ return [];
1152
+ }
1153
+ const xScale = scales.x.scale;
1154
+ const yScale = scales.y.scale;
1155
+ if (typeof xScale.bandwidth !== "function") {
1156
+ return [];
1157
+ }
1158
+ const bandwidth = xScale.bandwidth();
1159
+ const baseline = yScale(0);
1160
+ const colorEnc = encoding.color && "field" in encoding.color ? encoding.color : void 0;
1161
+ const conditionalColor = encoding.color && isConditionalValueDef(encoding.color) ? encoding.color : void 0;
1162
+ const colorField = colorEnc?.field;
1163
+ const isSequentialColor = colorEnc?.type === "quantitative";
1164
+ if (colorField && !isSequentialColor) {
1165
+ const categoryGroups = groupByField(spec.data, xChannel.field);
1166
+ const needsStacking = Array.from(categoryGroups.values()).some((rows) => rows.length > 1);
1167
+ if (needsStacking) {
1168
+ const stackDisabled = yChannel.stack === null || yChannel.stack === false;
1169
+ if (stackDisabled) {
1170
+ return computeGroupedColumns(
1171
+ spec.data,
1172
+ xChannel.field,
1173
+ yChannel.field,
1174
+ colorField,
1175
+ xScale,
1176
+ yScale,
1177
+ bandwidth,
1178
+ baseline,
1179
+ scales
1180
+ );
1181
+ }
1182
+ const stackMode = yChannel.stack === "normalize" ? "normalize" : yChannel.stack === "center" ? "center" : "zero";
1183
+ return computeStackedColumns(
1184
+ spec.data,
1185
+ xChannel.field,
1186
+ yChannel.field,
1187
+ colorField,
1188
+ xScale,
1189
+ yScale,
1190
+ bandwidth,
1191
+ baseline,
1192
+ scales,
1193
+ stackMode
1194
+ );
1195
+ }
1196
+ return computeColoredColumns(
1197
+ spec.data,
1198
+ xChannel.field,
1199
+ yChannel.field,
1200
+ colorField,
1201
+ xScale,
1202
+ yScale,
1203
+ bandwidth,
1204
+ baseline,
1205
+ scales
1206
+ );
1207
+ }
1208
+ return computeSimpleColumns(
1209
+ spec.data,
1210
+ xChannel.field,
1211
+ yChannel.field,
1212
+ xScale,
1213
+ yScale,
1214
+ bandwidth,
1215
+ baseline,
1216
+ scales,
1217
+ isSequentialColor,
1218
+ conditionalColor
1219
+ );
1220
+ }
1221
+ function computeSimpleColumns(data, categoryField, valueField, xScale, yScale, bandwidth, baseline, scales, sequentialColor = false, conditionalColor) {
1222
+ const marks = [];
1223
+ for (const row of data) {
1224
+ const category = String(row[categoryField] ?? "");
1225
+ const value2 = Number(row[valueField] ?? 0);
1226
+ if (!Number.isFinite(value2)) continue;
1227
+ const bandX = xScale(category);
1228
+ if (bandX === void 0) continue;
1229
+ let color2;
1230
+ if (conditionalColor) {
1231
+ const resolved = resolveConditionalValue(row, conditionalColor);
1232
+ if (resolved != null) {
1233
+ color2 = isGradientDef2(resolved) ? resolved : String(resolved);
1234
+ } else {
1235
+ color2 = getColor(scales, "__default__");
1236
+ }
1237
+ } else if (sequentialColor) {
1238
+ color2 = getSequentialColor(scales, value2);
1239
+ } else {
1240
+ color2 = getColor(scales, "__default__");
1241
+ }
1242
+ const yPos = yScale(value2);
1243
+ const columnHeight = Math.max(Math.abs(baseline - yPos), MIN_COLUMN_HEIGHT);
1244
+ const y2 = value2 >= 0 ? yPos : baseline;
1245
+ const aria = {
1246
+ label: `${category}: ${formatLabelValue(value2)}`
1247
+ };
1248
+ marks.push({
1249
+ type: "rect",
1250
+ x: bandX,
1251
+ y: y2,
1252
+ width: bandwidth,
1253
+ height: columnHeight,
1254
+ fill: color2,
1255
+ cornerRadius: 2,
1256
+ data: row,
1257
+ aria,
1258
+ orient: "vertical"
1259
+ });
1260
+ }
1261
+ return marks;
1262
+ }
1263
+ function computeColoredColumns(data, categoryField, valueField, colorField, xScale, yScale, bandwidth, baseline, scales) {
1264
+ const marks = [];
1265
+ for (const row of data) {
1266
+ const category = String(row[categoryField] ?? "");
1267
+ const value2 = Number(row[valueField] ?? 0);
1268
+ if (!Number.isFinite(value2)) continue;
1269
+ const bandX = xScale(category);
1270
+ if (bandX === void 0) continue;
1271
+ const groupKey2 = String(row[colorField] ?? "");
1272
+ const color2 = getColor(scales, groupKey2);
1273
+ const yPos = yScale(value2);
1274
+ const columnHeight = Math.max(Math.abs(baseline - yPos), MIN_COLUMN_HEIGHT);
1275
+ const y2 = value2 >= 0 ? yPos : baseline;
1276
+ const aria = {
1277
+ label: `${category}, ${groupKey2}: ${formatLabelValue(value2)}`
1278
+ };
1279
+ marks.push({
1280
+ type: "rect",
1281
+ x: bandX,
1282
+ y: y2,
1283
+ width: bandwidth,
1284
+ height: columnHeight,
1285
+ fill: color2,
1286
+ cornerRadius: 2,
1287
+ data: row,
1288
+ aria,
1289
+ orient: "vertical"
1290
+ });
1291
+ }
1292
+ return marks;
1293
+ }
1294
+ function computeGroupedColumns(data, categoryField, valueField, colorField, xScale, yScale, bandwidth, baseline, scales) {
1295
+ const marks = [];
1296
+ const categoryGroups = groupByField(data, categoryField);
1297
+ const groupIndexMap = /* @__PURE__ */ new Map();
1298
+ for (const row of data) {
1299
+ const key = String(row[colorField] ?? "");
1300
+ if (!groupIndexMap.has(key)) {
1301
+ groupIndexMap.set(key, groupIndexMap.size);
1302
+ }
1303
+ }
1304
+ const groupCount = groupIndexMap.size;
1305
+ if (groupCount === 0) return marks;
1306
+ const gap = Math.min(1, bandwidth * 0.05);
1307
+ const subBandWidth = Math.max(
1308
+ (bandwidth - gap * (groupCount - 1)) / groupCount,
1309
+ MIN_COLUMN_HEIGHT
1310
+ );
1311
+ for (const [category, rows] of categoryGroups) {
1312
+ const bandX = xScale(category);
1313
+ if (bandX === void 0) continue;
1314
+ for (const row of rows) {
1315
+ const groupKey2 = String(row[colorField] ?? "");
1316
+ const value2 = Number(row[valueField] ?? 0);
1317
+ if (!Number.isFinite(value2)) continue;
1318
+ const groupIndex = groupIndexMap.get(groupKey2) ?? 0;
1319
+ const color2 = getColor(scales, groupKey2);
1320
+ const yPos = yScale(value2);
1321
+ const columnHeight = Math.max(Math.abs(baseline - yPos), MIN_COLUMN_HEIGHT);
1322
+ const y2 = value2 >= 0 ? yPos : baseline;
1323
+ const subX = bandX + groupIndex * (subBandWidth + gap);
1324
+ const aria = {
1325
+ label: `${category}, ${groupKey2}: ${formatLabelValue(value2)}`
1326
+ };
1327
+ marks.push({
1328
+ type: "rect",
1329
+ x: subX,
1330
+ y: y2,
1331
+ width: subBandWidth,
1332
+ height: columnHeight,
1333
+ fill: color2,
1334
+ cornerRadius: 2,
1335
+ data: row,
1336
+ aria,
1337
+ orient: "vertical"
1338
+ });
1339
+ }
1340
+ }
1341
+ return marks;
1342
+ }
1343
+ function computeStackedColumns(data, categoryField, valueField, colorField, xScale, yScale, bandwidth, _baseline, scales, stackMode = "zero") {
1344
+ const marks = [];
1345
+ const categoryGroups = groupByField(data, categoryField);
1346
+ for (const [category, rows] of categoryGroups) {
1347
+ const bandX = xScale(category);
1348
+ if (bandX === void 0) continue;
1349
+ let categoryTotal = 0;
1350
+ for (const row of rows) {
1351
+ const v = Number(row[valueField] ?? 0);
1352
+ if (Number.isFinite(v) && v > 0) categoryTotal += v;
1353
+ }
1354
+ let cumulativeValue = stackMode === "center" ? -categoryTotal / 2 : 0;
1355
+ for (const row of rows) {
1356
+ const groupKey2 = String(row[colorField] ?? "");
1357
+ const rawValue = Number(row[valueField] ?? 0);
1358
+ if (!Number.isFinite(rawValue) || rawValue <= 0) continue;
1359
+ const value2 = stackMode === "normalize" && categoryTotal > 0 ? rawValue / categoryTotal : rawValue;
1360
+ const color2 = getColor(scales, groupKey2);
1361
+ const yTop = yScale(cumulativeValue + value2);
1362
+ const yBottom = yScale(cumulativeValue);
1363
+ const columnHeight = Math.max(Math.abs(yBottom - yTop), MIN_COLUMN_HEIGHT);
1364
+ const aria = {
1365
+ label: `${category}, ${groupKey2}: ${formatLabelValue(rawValue)}`
1366
+ };
1367
+ marks.push({
1368
+ type: "rect",
1369
+ x: bandX,
1370
+ y: Math.min(yTop, yBottom),
1371
+ width: bandwidth,
1372
+ height: columnHeight,
1373
+ fill: color2,
1374
+ cornerRadius: 0,
1375
+ data: row,
1376
+ aria,
1377
+ orient: "vertical",
1378
+ stackGroup: category
1379
+ });
1380
+ cumulativeValue += value2;
1381
+ }
1382
+ }
1383
+ return marks;
1384
+ }
1385
+
1386
+ // src/charts/column/labels.ts
1387
+ import {
1388
+ buildD3Formatter as buildD3Formatter2,
1389
+ estimateTextWidth as estimateTextWidth3,
1390
+ getRepresentativeColor as getRepresentativeColor2,
1391
+ resolveCollisions as resolveCollisions2
1392
+ } from "@opendata-ai/openchart-core";
1393
+ var LABEL_FONT_SIZE2 = 10;
1394
+ var LABEL_FONT_WEIGHT2 = 600;
1395
+ var LABEL_OFFSET_Y = 6;
1396
+ function computeColumnLabels(marks, _chartArea, density = "auto", labelFormat, labelPrefix, valueField) {
1397
+ const targetMarks = filterByDensity(marks, density);
1398
+ const formatter = buildD3Formatter2(labelFormat);
1399
+ const candidates = [];
1400
+ for (const mark of targetMarks) {
1401
+ let valuePart;
1402
+ const rawNum = valueField != null ? Number(mark.data[valueField]) : NaN;
1403
+ if (formatter && Number.isFinite(rawNum)) {
1404
+ valuePart = formatter(rawNum);
1405
+ } else if (Number.isFinite(rawNum)) {
1406
+ valuePart = formatLabelValue(rawNum);
1407
+ } else {
1408
+ const ariaLabel = mark.aria.label;
1409
+ const lastColon = ariaLabel.lastIndexOf(":");
1410
+ const rawValue = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
1411
+ if (!rawValue) continue;
1412
+ if (formatter) {
1413
+ const num = Number(rawValue.replace(/[^0-9.-]/g, ""));
1414
+ valuePart = !Number.isNaN(num) ? formatter(num) : rawValue;
1415
+ } else {
1416
+ valuePart = rawValue;
1417
+ }
1418
+ }
1419
+ if (labelPrefix) valuePart = labelPrefix + valuePart;
1420
+ const numericValue = parseFloat(valuePart);
1421
+ const isNegative = Number.isFinite(numericValue) && numericValue < 0;
1422
+ const textWidth = estimateTextWidth3(valuePart, LABEL_FONT_SIZE2, LABEL_FONT_WEIGHT2);
1423
+ const textHeight = LABEL_FONT_SIZE2 * 1.2;
1424
+ const anchorX = mark.x + mark.width / 2;
1425
+ const anchorY = isNegative ? mark.y + mark.height + LABEL_OFFSET_Y : mark.y - LABEL_OFFSET_Y - textHeight;
1426
+ candidates.push({
1427
+ text: valuePart,
1428
+ anchorX,
1429
+ anchorY,
1430
+ width: textWidth,
1431
+ height: textHeight,
1432
+ priority: "data",
1433
+ style: {
1434
+ fontFamily: "system-ui, -apple-system, sans-serif",
1435
+ fontSize: LABEL_FONT_SIZE2,
1436
+ fontWeight: LABEL_FONT_WEIGHT2,
1437
+ fill: getRepresentativeColor2(mark.fill),
1438
+ lineHeight: 1.2,
1439
+ textAnchor: "middle",
1440
+ dominantBaseline: isNegative ? "hanging" : "auto"
1441
+ }
1442
+ });
1443
+ }
1444
+ if (candidates.length === 0) return [];
1445
+ if (density === "all") {
1446
+ return candidates.map((c) => ({
1447
+ text: c.text,
1448
+ x: c.anchorX,
1449
+ y: c.anchorY,
1450
+ style: c.style,
1451
+ visible: true
1452
+ }));
1453
+ }
1454
+ return resolveCollisions2(candidates);
1455
+ }
1456
+
1457
+ // src/charts/column/index.ts
1458
+ var columnRenderer = (spec, scales, chartArea, strategy, _theme) => {
1459
+ const marks = computeColumnMarks(spec, scales, chartArea, strategy);
1460
+ const valueField = spec.encoding?.y && "field" in spec.encoding.y ? spec.encoding.y.field : void 0;
1461
+ const labels = computeColumnLabels(
1462
+ marks,
1463
+ chartArea,
1464
+ spec.labels.density,
1465
+ spec.labels.format,
1466
+ spec.labels.prefix,
1467
+ valueField
1468
+ );
1469
+ for (let i = 0; i < marks.length && i < labels.length; i++) {
1470
+ marks[i].label = labels[i];
1471
+ }
1472
+ return marks;
1473
+ };
1474
+
1475
+ // src/charts/dot/compute.ts
1476
+ var DOT_RADIUS = 6;
1477
+ var STEM_WIDTH = 2;
1478
+ var STEM_COLOR = "#cccccc";
1479
+ function computeDotMarks(spec, scales, _chartArea, _strategy) {
1480
+ const encoding = spec.encoding;
1481
+ const xChannel = encoding.x;
1482
+ const yChannel = encoding.y;
1483
+ if (!xChannel || !yChannel || !scales.x || !scales.y) {
1484
+ return [];
1485
+ }
1486
+ const xScale = scales.x.scale;
1487
+ const yScale = scales.y.scale;
1488
+ if (typeof yScale.bandwidth !== "function") {
1489
+ return [];
1490
+ }
1491
+ const bandwidth = yScale.bandwidth();
1492
+ const [rangeStart, rangeEnd] = xScale.range();
1493
+ const rangeMin = Math.min(rangeStart, rangeEnd);
1494
+ const rangeMax = Math.max(rangeStart, rangeEnd);
1495
+ const baseline = Math.max(rangeMin, Math.min(rangeMax, xScale(0)));
1496
+ const colorEnc = encoding.color && "field" in encoding.color ? encoding.color : void 0;
1497
+ const isSequentialColor = colorEnc?.type === "quantitative";
1498
+ const colorField = isSequentialColor ? void 0 : colorEnc?.field;
1499
+ if (colorField) {
1500
+ return computeDumbbellMarks(
1501
+ spec.data,
1502
+ xChannel.field,
1503
+ yChannel.field,
1504
+ colorField,
1505
+ xScale,
1506
+ yScale,
1507
+ bandwidth,
1508
+ scales
1509
+ );
1510
+ }
1511
+ return computeLollipopMarks(
1512
+ spec.data,
1513
+ xChannel.field,
1514
+ yChannel.field,
1515
+ xScale,
1516
+ yScale,
1517
+ bandwidth,
1518
+ baseline,
1519
+ scales,
1520
+ isSequentialColor
1521
+ );
1522
+ }
1523
+ function computeDumbbellMarks(data, valueField, categoryField, colorField, xScale, yScale, bandwidth, scales) {
1524
+ const marks = [];
1525
+ const categoryGroups = groupByField([...data], categoryField);
1526
+ for (const [category, rows] of categoryGroups) {
1527
+ const bandY = yScale(category);
1528
+ if (bandY === void 0) continue;
1529
+ const cy = bandY + bandwidth / 2;
1530
+ const xValues = [];
1531
+ for (const row of rows) {
1532
+ const value2 = Number(row[valueField] ?? 0);
1533
+ if (Number.isFinite(value2)) xValues.push(value2);
1534
+ }
1535
+ if (xValues.length === 0) continue;
1536
+ const minVal = Math.min(...xValues);
1537
+ const maxVal = Math.max(...xValues);
1538
+ const xLeft = xScale(minVal);
1539
+ const xRight = xScale(maxVal);
1540
+ const barWidth = Math.abs(xRight - xLeft);
1541
+ if (barWidth > 0) {
1542
+ const stemAria = {
1543
+ label: `Range for ${category}: ${minVal} to ${maxVal}`
1544
+ };
1545
+ marks.push({
1546
+ type: "rect",
1547
+ x: Math.min(xLeft, xRight),
1548
+ y: cy - STEM_WIDTH / 2,
1549
+ width: barWidth,
1550
+ height: STEM_WIDTH,
1551
+ fill: STEM_COLOR,
1552
+ data: rows[0],
1553
+ aria: stemAria
1554
+ });
1555
+ }
1556
+ for (const row of rows) {
1557
+ const value2 = Number(row[valueField] ?? 0);
1558
+ if (!Number.isFinite(value2)) continue;
1559
+ const cx = xScale(value2);
1560
+ const colorCategory = String(row[colorField] ?? "");
1561
+ const color2 = getColor(scales, colorCategory);
1562
+ const dotAria = {
1563
+ label: `${category}, ${colorCategory}: ${value2}`
1564
+ };
1565
+ marks.push({
1566
+ type: "point",
1567
+ cx,
1568
+ cy,
1569
+ r: DOT_RADIUS,
1570
+ fill: color2,
1571
+ stroke: "#ffffff",
1572
+ strokeWidth: 2,
1573
+ data: row,
1574
+ aria: dotAria
1575
+ });
1576
+ }
1577
+ }
1578
+ return marks;
1579
+ }
1580
+ function computeLollipopMarks(data, valueField, categoryField, xScale, yScale, bandwidth, baseline, scales, isSequentialColor = false) {
1581
+ const marks = [];
1582
+ for (const row of data) {
1583
+ const category = String(row[categoryField] ?? "");
1584
+ const value2 = Number(row[valueField] ?? 0);
1585
+ if (!Number.isFinite(value2)) continue;
1586
+ const bandY = yScale(category);
1587
+ if (bandY === void 0) continue;
1588
+ const cx = xScale(value2);
1589
+ const cy = bandY + bandwidth / 2;
1590
+ const color2 = isSequentialColor ? getSequentialColor(scales, value2) : getColor(scales, "__default__");
1591
+ const stemX = Math.min(baseline, cx);
1592
+ const stemWidth = Math.abs(cx - baseline);
1593
+ if (stemWidth > 0) {
1594
+ const stemAria = {
1595
+ label: `Stem for ${category}`
1596
+ };
1597
+ marks.push({
1598
+ type: "rect",
1599
+ x: stemX,
1600
+ y: cy - STEM_WIDTH / 2,
1601
+ width: stemWidth,
1602
+ height: STEM_WIDTH,
1603
+ fill: STEM_COLOR,
1604
+ data: row,
1605
+ aria: stemAria
1606
+ });
1607
+ }
1608
+ const dotAria = {
1609
+ label: `${category}: ${value2}`
1610
+ };
1611
+ marks.push({
1612
+ type: "point",
1613
+ cx,
1614
+ cy,
1615
+ r: DOT_RADIUS,
1616
+ fill: color2,
1617
+ stroke: "#ffffff",
1618
+ strokeWidth: 2,
1619
+ data: row,
1620
+ aria: dotAria
1621
+ });
1622
+ }
1623
+ return marks;
1624
+ }
1625
+
1626
+ // src/charts/dot/labels.ts
1627
+ import {
1628
+ buildD3Formatter as buildD3Formatter3,
1629
+ estimateTextWidth as estimateTextWidth4,
1630
+ getRepresentativeColor as getRepresentativeColor3,
1631
+ resolveCollisions as resolveCollisions3
1632
+ } from "@opendata-ai/openchart-core";
1633
+ var LABEL_FONT_SIZE3 = 11;
1634
+ var LABEL_FONT_WEIGHT3 = 600;
1635
+ var LABEL_OFFSET_X = 10;
1636
+ function computeDotLabels(marks, _chartArea, density = "auto", labelPrefix, labelFormat, valueField) {
1637
+ const targetMarks = filterByDensity(marks, density);
1638
+ const formatter = buildD3Formatter3(labelFormat);
1639
+ const candidates = [];
1640
+ for (const mark of targetMarks) {
1641
+ let valuePart;
1642
+ const rawNum = valueField != null ? Number(mark.data[valueField]) : NaN;
1643
+ if (formatter && Number.isFinite(rawNum)) {
1644
+ valuePart = formatter(rawNum);
1645
+ } else if (Number.isFinite(rawNum)) {
1646
+ valuePart = formatLabelValue(rawNum);
1647
+ } else {
1648
+ const ariaLabel = mark.aria.label;
1649
+ const lastColon = ariaLabel.lastIndexOf(":");
1650
+ valuePart = lastColon >= 0 ? ariaLabel.slice(lastColon + 1).trim() : "";
1651
+ if (!valuePart) continue;
1652
+ if (formatter) {
1653
+ const num = Number(valuePart.replace(/[^0-9.-]/g, ""));
1654
+ if (!Number.isNaN(num)) valuePart = formatter(num);
1655
+ }
1656
+ }
1657
+ if (labelPrefix) valuePart = labelPrefix + valuePart;
1658
+ const textWidth = estimateTextWidth4(valuePart, LABEL_FONT_SIZE3, LABEL_FONT_WEIGHT3);
1659
+ const textHeight = LABEL_FONT_SIZE3 * 1.2;
1660
+ candidates.push({
1661
+ text: valuePart,
1662
+ anchorX: mark.cx + mark.r + LABEL_OFFSET_X,
1663
+ anchorY: mark.cy - textHeight / 2,
1664
+ width: textWidth,
1665
+ height: textHeight,
1666
+ priority: "data",
1667
+ style: {
1668
+ fontFamily: "system-ui, -apple-system, sans-serif",
1669
+ fontSize: LABEL_FONT_SIZE3,
1670
+ fontWeight: LABEL_FONT_WEIGHT3,
1671
+ fill: getRepresentativeColor3(mark.fill),
1672
+ lineHeight: 1.2,
1673
+ textAnchor: "start",
1674
+ dominantBaseline: "central"
1675
+ }
1676
+ });
1677
+ }
1678
+ if (candidates.length === 0) return [];
1679
+ if (density === "all") {
1680
+ return candidates.map((c) => ({
1681
+ text: c.text,
1682
+ x: c.anchorX,
1683
+ y: c.anchorY,
1684
+ style: c.style,
1685
+ visible: true
1686
+ }));
1687
+ }
1688
+ return resolveCollisions3(candidates);
1689
+ }
1690
+
1691
+ // src/charts/dot/index.ts
1692
+ var dotRenderer = (spec, scales, chartArea, strategy, _theme) => {
1693
+ const marks = computeDotMarks(spec, scales, chartArea, strategy);
1694
+ const pointMarks = marks.filter((m) => m.type === "point");
1695
+ const valueField = spec.encoding?.x && "field" in spec.encoding.x ? spec.encoding.x.field : void 0;
1696
+ const labels = computeDotLabels(
1697
+ pointMarks,
1698
+ chartArea,
1699
+ spec.labels.density,
1700
+ spec.labels.prefix,
1701
+ spec.labels.format,
1702
+ valueField
1703
+ );
1704
+ let labelIdx = 0;
1705
+ for (const mark of marks) {
1706
+ if (mark.type === "point" && labelIdx < labels.length) {
1707
+ mark.label = labels[labelIdx];
1708
+ labelIdx++;
1709
+ }
1710
+ }
1711
+ return marks;
1712
+ };
1713
+
1714
+ // src/charts/line/index.ts
1715
+ import { getRepresentativeColor as getRepresentativeColor6 } from "@opendata-ai/openchart-core";
1716
+
1717
+ // src/charts/line/area.ts
1718
+ import { getRepresentativeColor as getRepresentativeColor4 } from "@opendata-ai/openchart-core";
1719
+
1720
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/constant.js
1721
+ function constant_default(x2) {
1722
+ return function constant2() {
1723
+ return x2;
1724
+ };
1725
+ }
1726
+
1727
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/math.js
1728
+ var abs = Math.abs;
1729
+ var atan2 = Math.atan2;
1730
+ var cos = Math.cos;
1731
+ var max = Math.max;
1732
+ var min = Math.min;
1733
+ var sin = Math.sin;
1734
+ var sqrt = Math.sqrt;
1735
+ var epsilon = 1e-12;
1736
+ var pi = Math.PI;
1737
+ var halfPi = pi / 2;
1738
+ var tau = 2 * pi;
1739
+ function acos(x2) {
1740
+ return x2 > 1 ? 0 : x2 < -1 ? pi : Math.acos(x2);
1741
+ }
1742
+ function asin(x2) {
1743
+ return x2 >= 1 ? halfPi : x2 <= -1 ? -halfPi : Math.asin(x2);
1744
+ }
1745
+
1746
+ // ../../node_modules/.bun/d3-path@3.1.0/node_modules/d3-path/src/path.js
1747
+ var pi2 = Math.PI;
1748
+ var tau2 = 2 * pi2;
1749
+ var epsilon2 = 1e-6;
1750
+ var tauEpsilon = tau2 - epsilon2;
1751
+ function append(strings) {
1752
+ this._ += strings[0];
1753
+ for (let i = 1, n = strings.length; i < n; ++i) {
1754
+ this._ += arguments[i] + strings[i];
1755
+ }
1756
+ }
1757
+ function appendRound(digits) {
1758
+ let d = Math.floor(digits);
1759
+ if (!(d >= 0)) throw new Error(`invalid digits: ${digits}`);
1760
+ if (d > 15) return append;
1761
+ const k = 10 ** d;
1762
+ return function(strings) {
1763
+ this._ += strings[0];
1764
+ for (let i = 1, n = strings.length; i < n; ++i) {
1765
+ this._ += Math.round(arguments[i] * k) / k + strings[i];
1766
+ }
1767
+ };
1768
+ }
1769
+ var Path = class {
1770
+ constructor(digits) {
1771
+ this._x0 = this._y0 = // start of current subpath
1772
+ this._x1 = this._y1 = null;
1773
+ this._ = "";
1774
+ this._append = digits == null ? append : appendRound(digits);
1775
+ }
1776
+ moveTo(x2, y2) {
1777
+ this._append`M${this._x0 = this._x1 = +x2},${this._y0 = this._y1 = +y2}`;
1778
+ }
1779
+ closePath() {
1780
+ if (this._x1 !== null) {
1781
+ this._x1 = this._x0, this._y1 = this._y0;
1782
+ this._append`Z`;
1783
+ }
1784
+ }
1785
+ lineTo(x2, y2) {
1786
+ this._append`L${this._x1 = +x2},${this._y1 = +y2}`;
1787
+ }
1788
+ quadraticCurveTo(x1, y1, x2, y2) {
1789
+ this._append`Q${+x1},${+y1},${this._x1 = +x2},${this._y1 = +y2}`;
1790
+ }
1791
+ bezierCurveTo(x1, y1, x2, y2, x3, y3) {
1792
+ this._append`C${+x1},${+y1},${+x2},${+y2},${this._x1 = +x3},${this._y1 = +y3}`;
1793
+ }
1794
+ arcTo(x1, y1, x2, y2, r) {
1795
+ x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
1796
+ if (r < 0) throw new Error(`negative radius: ${r}`);
1797
+ let x0 = this._x1, y0 = this._y1, x21 = x2 - x1, y21 = y2 - y1, x01 = x0 - x1, y01 = y0 - y1, l01_2 = x01 * x01 + y01 * y01;
1798
+ if (this._x1 === null) {
1799
+ this._append`M${this._x1 = x1},${this._y1 = y1}`;
1800
+ } else if (!(l01_2 > epsilon2)) ;
1801
+ else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon2) || !r) {
1802
+ this._append`L${this._x1 = x1},${this._y1 = y1}`;
1803
+ } else {
1804
+ let x20 = x2 - x0, y20 = y2 - y0, l21_2 = x21 * x21 + y21 * y21, l20_2 = x20 * x20 + y20 * y20, l21 = Math.sqrt(l21_2), l01 = Math.sqrt(l01_2), l = r * Math.tan((pi2 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2), t01 = l / l01, t21 = l / l21;
1805
+ if (Math.abs(t01 - 1) > epsilon2) {
1806
+ this._append`L${x1 + t01 * x01},${y1 + t01 * y01}`;
1807
+ }
1808
+ this._append`A${r},${r},0,0,${+(y01 * x20 > x01 * y20)},${this._x1 = x1 + t21 * x21},${this._y1 = y1 + t21 * y21}`;
1809
+ }
1810
+ }
1811
+ arc(x2, y2, r, a0, a1, ccw) {
1812
+ x2 = +x2, y2 = +y2, r = +r, ccw = !!ccw;
1813
+ if (r < 0) throw new Error(`negative radius: ${r}`);
1814
+ let dx = r * Math.cos(a0), dy = r * Math.sin(a0), x0 = x2 + dx, y0 = y2 + dy, cw = 1 ^ ccw, da = ccw ? a0 - a1 : a1 - a0;
1815
+ if (this._x1 === null) {
1816
+ this._append`M${x0},${y0}`;
1817
+ } else if (Math.abs(this._x1 - x0) > epsilon2 || Math.abs(this._y1 - y0) > epsilon2) {
1818
+ this._append`L${x0},${y0}`;
1819
+ }
1820
+ if (!r) return;
1821
+ if (da < 0) da = da % tau2 + tau2;
1822
+ if (da > tauEpsilon) {
1823
+ this._append`A${r},${r},0,1,${cw},${x2 - dx},${y2 - dy}A${r},${r},0,1,${cw},${this._x1 = x0},${this._y1 = y0}`;
1824
+ } else if (da > epsilon2) {
1825
+ this._append`A${r},${r},0,${+(da >= pi2)},${cw},${this._x1 = x2 + r * Math.cos(a1)},${this._y1 = y2 + r * Math.sin(a1)}`;
1826
+ }
1827
+ }
1828
+ rect(x2, y2, w, h) {
1829
+ this._append`M${this._x0 = this._x1 = +x2},${this._y0 = this._y1 = +y2}h${w = +w}v${+h}h${-w}Z`;
1830
+ }
1831
+ toString() {
1832
+ return this._;
1833
+ }
1834
+ };
1835
+ function path() {
1836
+ return new Path();
1837
+ }
1838
+ path.prototype = Path.prototype;
1839
+
1840
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/path.js
1841
+ function withPath(shape) {
1842
+ let digits = 3;
1843
+ shape.digits = function(_) {
1844
+ if (!arguments.length) return digits;
1845
+ if (_ == null) {
1846
+ digits = null;
1847
+ } else {
1848
+ const d = Math.floor(_);
1849
+ if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);
1850
+ digits = d;
1851
+ }
1852
+ return shape;
1853
+ };
1854
+ return () => new Path(digits);
1855
+ }
1856
+
1857
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/arc.js
1858
+ function arcInnerRadius(d) {
1859
+ return d.innerRadius;
1860
+ }
1861
+ function arcOuterRadius(d) {
1862
+ return d.outerRadius;
1863
+ }
1864
+ function arcStartAngle(d) {
1865
+ return d.startAngle;
1866
+ }
1867
+ function arcEndAngle(d) {
1868
+ return d.endAngle;
1869
+ }
1870
+ function arcPadAngle(d) {
1871
+ return d && d.padAngle;
1872
+ }
1873
+ function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
1874
+ var x10 = x1 - x0, y10 = y1 - y0, x32 = x3 - x2, y32 = y3 - y2, t = y32 * x10 - x32 * y10;
1875
+ if (t * t < epsilon) return;
1876
+ t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
1877
+ return [x0 + t * x10, y0 + t * y10];
1878
+ }
1879
+ function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
1880
+ var x01 = x0 - x1, y01 = y0 - y1, lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01), ox = lo * y01, oy = -lo * x01, x11 = x0 + ox, y11 = y0 + oy, x10 = x1 + ox, y10 = y1 + oy, x00 = (x11 + x10) / 2, y00 = (y11 + y10) / 2, dx = x10 - x11, dy = y10 - y11, d2 = dx * dx + dy * dy, r = r1 - rc, D = x11 * y10 - x10 * y11, d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)), cx0 = (D * dy - dx * d) / d2, cy0 = (-D * dx - dy * d) / d2, cx1 = (D * dy + dx * d) / d2, cy1 = (-D * dx + dy * d) / d2, dx0 = cx0 - x00, dy0 = cy0 - y00, dx1 = cx1 - x00, dy1 = cy1 - y00;
1881
+ if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
1882
+ return {
1883
+ cx: cx0,
1884
+ cy: cy0,
1885
+ x01: -ox,
1886
+ y01: -oy,
1887
+ x11: cx0 * (r1 / r - 1),
1888
+ y11: cy0 * (r1 / r - 1)
1889
+ };
1890
+ }
1891
+ function arc_default() {
1892
+ var innerRadius = arcInnerRadius, outerRadius = arcOuterRadius, cornerRadius = constant_default(0), padRadius = null, startAngle = arcStartAngle, endAngle = arcEndAngle, padAngle = arcPadAngle, context = null, path2 = withPath(arc);
1893
+ function arc() {
1894
+ var buffer, r, r0 = +innerRadius.apply(this, arguments), r1 = +outerRadius.apply(this, arguments), a0 = startAngle.apply(this, arguments) - halfPi, a1 = endAngle.apply(this, arguments) - halfPi, da = abs(a1 - a0), cw = a1 > a0;
1895
+ if (!context) context = buffer = path2();
1896
+ if (r1 < r0) r = r1, r1 = r0, r0 = r;
1897
+ if (!(r1 > epsilon)) context.moveTo(0, 0);
1898
+ else if (da > tau - epsilon) {
1899
+ context.moveTo(r1 * cos(a0), r1 * sin(a0));
1900
+ context.arc(0, 0, r1, a0, a1, !cw);
1901
+ if (r0 > epsilon) {
1902
+ context.moveTo(r0 * cos(a1), r0 * sin(a1));
1903
+ context.arc(0, 0, r0, a1, a0, cw);
1904
+ }
1905
+ } else {
1906
+ var a01 = a0, a11 = a1, a00 = a0, a10 = a1, da0 = da, da1 = da, ap = padAngle.apply(this, arguments) / 2, rp = ap > epsilon && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)), rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)), rc0 = rc, rc1 = rc, t02, t12;
1907
+ if (rp > epsilon) {
1908
+ var p0 = asin(rp / r0 * sin(ap)), p1 = asin(rp / r1 * sin(ap));
1909
+ if ((da0 -= p0 * 2) > epsilon) p0 *= cw ? 1 : -1, a00 += p0, a10 -= p0;
1910
+ else da0 = 0, a00 = a10 = (a0 + a1) / 2;
1911
+ if ((da1 -= p1 * 2) > epsilon) p1 *= cw ? 1 : -1, a01 += p1, a11 -= p1;
1912
+ else da1 = 0, a01 = a11 = (a0 + a1) / 2;
1913
+ }
1914
+ var x01 = r1 * cos(a01), y01 = r1 * sin(a01), x10 = r0 * cos(a10), y10 = r0 * sin(a10);
1915
+ if (rc > epsilon) {
1916
+ var x11 = r1 * cos(a11), y11 = r1 * sin(a11), x00 = r0 * cos(a00), y00 = r0 * sin(a00), oc;
1917
+ if (da < pi) {
1918
+ if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {
1919
+ var ax = x01 - oc[0], ay = y01 - oc[1], bx = x11 - oc[0], by = y11 - oc[1], kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2), lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
1920
+ rc0 = min(rc, (r0 - lc) / (kc - 1));
1921
+ rc1 = min(rc, (r1 - lc) / (kc + 1));
1922
+ } else {
1923
+ rc0 = rc1 = 0;
1924
+ }
1925
+ }
1926
+ }
1927
+ if (!(da1 > epsilon)) context.moveTo(x01, y01);
1928
+ else if (rc1 > epsilon) {
1929
+ t02 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
1930
+ t12 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
1931
+ context.moveTo(t02.cx + t02.x01, t02.cy + t02.y01);
1932
+ if (rc1 < rc) context.arc(t02.cx, t02.cy, rc1, atan2(t02.y01, t02.x01), atan2(t12.y01, t12.x01), !cw);
1933
+ else {
1934
+ context.arc(t02.cx, t02.cy, rc1, atan2(t02.y01, t02.x01), atan2(t02.y11, t02.x11), !cw);
1935
+ context.arc(0, 0, r1, atan2(t02.cy + t02.y11, t02.cx + t02.x11), atan2(t12.cy + t12.y11, t12.cx + t12.x11), !cw);
1936
+ context.arc(t12.cx, t12.cy, rc1, atan2(t12.y11, t12.x11), atan2(t12.y01, t12.x01), !cw);
1937
+ }
1938
+ } else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
1939
+ if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);
1940
+ else if (rc0 > epsilon) {
1941
+ t02 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
1942
+ t12 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
1943
+ context.lineTo(t02.cx + t02.x01, t02.cy + t02.y01);
1944
+ if (rc0 < rc) context.arc(t02.cx, t02.cy, rc0, atan2(t02.y01, t02.x01), atan2(t12.y01, t12.x01), !cw);
1945
+ else {
1946
+ context.arc(t02.cx, t02.cy, rc0, atan2(t02.y01, t02.x01), atan2(t02.y11, t02.x11), !cw);
1947
+ context.arc(0, 0, r0, atan2(t02.cy + t02.y11, t02.cx + t02.x11), atan2(t12.cy + t12.y11, t12.cx + t12.x11), cw);
1948
+ context.arc(t12.cx, t12.cy, rc0, atan2(t12.y11, t12.x11), atan2(t12.y01, t12.x01), !cw);
1949
+ }
1950
+ } else context.arc(0, 0, r0, a10, a00, cw);
1951
+ }
1952
+ context.closePath();
1953
+ if (buffer) return context = null, buffer + "" || null;
1954
+ }
1955
+ arc.centroid = function() {
1956
+ var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2, a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;
1957
+ return [cos(a) * r, sin(a) * r];
1958
+ };
1959
+ arc.innerRadius = function(_) {
1960
+ return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant_default(+_), arc) : innerRadius;
1961
+ };
1962
+ arc.outerRadius = function(_) {
1963
+ return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant_default(+_), arc) : outerRadius;
1964
+ };
1965
+ arc.cornerRadius = function(_) {
1966
+ return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant_default(+_), arc) : cornerRadius;
1967
+ };
1968
+ arc.padRadius = function(_) {
1969
+ return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant_default(+_), arc) : padRadius;
1970
+ };
1971
+ arc.startAngle = function(_) {
1972
+ return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant_default(+_), arc) : startAngle;
1973
+ };
1974
+ arc.endAngle = function(_) {
1975
+ return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant_default(+_), arc) : endAngle;
1976
+ };
1977
+ arc.padAngle = function(_) {
1978
+ return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant_default(+_), arc) : padAngle;
1979
+ };
1980
+ arc.context = function(_) {
1981
+ return arguments.length ? (context = _ == null ? null : _, arc) : context;
1982
+ };
1983
+ return arc;
1984
+ }
1985
+
1986
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/array.js
1987
+ var slice = Array.prototype.slice;
1988
+ function array_default(x2) {
1989
+ return typeof x2 === "object" && "length" in x2 ? x2 : Array.from(x2);
1990
+ }
1991
+
1992
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/curve/linear.js
1993
+ function Linear(context) {
1994
+ this._context = context;
1995
+ }
1996
+ Linear.prototype = {
1997
+ areaStart: function() {
1998
+ this._line = 0;
1999
+ },
2000
+ areaEnd: function() {
2001
+ this._line = NaN;
2002
+ },
2003
+ lineStart: function() {
2004
+ this._point = 0;
2005
+ },
2006
+ lineEnd: function() {
2007
+ if (this._line || this._line !== 0 && this._point === 1) this._context.closePath();
2008
+ this._line = 1 - this._line;
2009
+ },
2010
+ point: function(x2, y2) {
2011
+ x2 = +x2, y2 = +y2;
2012
+ switch (this._point) {
2013
+ case 0:
2014
+ this._point = 1;
2015
+ this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2);
2016
+ break;
2017
+ case 1:
2018
+ this._point = 2;
2019
+ // falls through
2020
+ default:
2021
+ this._context.lineTo(x2, y2);
2022
+ break;
2023
+ }
2024
+ }
2025
+ };
2026
+ function linear_default(context) {
2027
+ return new Linear(context);
2028
+ }
2029
+
2030
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/point.js
2031
+ function x(p) {
2032
+ return p[0];
2033
+ }
2034
+ function y(p) {
2035
+ return p[1];
2036
+ }
2037
+
2038
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/line.js
2039
+ function line_default(x2, y2) {
2040
+ var defined = constant_default(true), context = null, curve = linear_default, output = null, path2 = withPath(line);
2041
+ x2 = typeof x2 === "function" ? x2 : x2 === void 0 ? x : constant_default(x2);
2042
+ y2 = typeof y2 === "function" ? y2 : y2 === void 0 ? y : constant_default(y2);
2043
+ function line(data) {
2044
+ var i, n = (data = array_default(data)).length, d, defined0 = false, buffer;
2045
+ if (context == null) output = curve(buffer = path2());
2046
+ for (i = 0; i <= n; ++i) {
2047
+ if (!(i < n && defined(d = data[i], i, data)) === defined0) {
2048
+ if (defined0 = !defined0) output.lineStart();
2049
+ else output.lineEnd();
2050
+ }
2051
+ if (defined0) output.point(+x2(d, i, data), +y2(d, i, data));
2052
+ }
2053
+ if (buffer) return output = null, buffer + "" || null;
2054
+ }
2055
+ line.x = function(_) {
2056
+ return arguments.length ? (x2 = typeof _ === "function" ? _ : constant_default(+_), line) : x2;
2057
+ };
2058
+ line.y = function(_) {
2059
+ return arguments.length ? (y2 = typeof _ === "function" ? _ : constant_default(+_), line) : y2;
2060
+ };
2061
+ line.defined = function(_) {
2062
+ return arguments.length ? (defined = typeof _ === "function" ? _ : constant_default(!!_), line) : defined;
2063
+ };
2064
+ line.curve = function(_) {
2065
+ return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
2066
+ };
2067
+ line.context = function(_) {
2068
+ return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
2069
+ };
2070
+ return line;
2071
+ }
2072
+
2073
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/area.js
2074
+ function area_default(x0, y0, y1) {
2075
+ var x1 = null, defined = constant_default(true), context = null, curve = linear_default, output = null, path2 = withPath(area);
2076
+ x0 = typeof x0 === "function" ? x0 : x0 === void 0 ? x : constant_default(+x0);
2077
+ y0 = typeof y0 === "function" ? y0 : y0 === void 0 ? constant_default(0) : constant_default(+y0);
2078
+ y1 = typeof y1 === "function" ? y1 : y1 === void 0 ? y : constant_default(+y1);
2079
+ function area(data) {
2080
+ var i, j, k, n = (data = array_default(data)).length, d, defined0 = false, buffer, x0z = new Array(n), y0z = new Array(n);
2081
+ if (context == null) output = curve(buffer = path2());
2082
+ for (i = 0; i <= n; ++i) {
2083
+ if (!(i < n && defined(d = data[i], i, data)) === defined0) {
2084
+ if (defined0 = !defined0) {
2085
+ j = i;
2086
+ output.areaStart();
2087
+ output.lineStart();
2088
+ } else {
2089
+ output.lineEnd();
2090
+ output.lineStart();
2091
+ for (k = i - 1; k >= j; --k) {
2092
+ output.point(x0z[k], y0z[k]);
2093
+ }
2094
+ output.lineEnd();
2095
+ output.areaEnd();
2096
+ }
2097
+ }
2098
+ if (defined0) {
2099
+ x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
2100
+ output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
2101
+ }
2102
+ }
2103
+ if (buffer) return output = null, buffer + "" || null;
2104
+ }
2105
+ function arealine() {
2106
+ return line_default().defined(defined).curve(curve).context(context);
2107
+ }
2108
+ area.x = function(_) {
2109
+ return arguments.length ? (x0 = typeof _ === "function" ? _ : constant_default(+_), x1 = null, area) : x0;
2110
+ };
2111
+ area.x0 = function(_) {
2112
+ return arguments.length ? (x0 = typeof _ === "function" ? _ : constant_default(+_), area) : x0;
2113
+ };
2114
+ area.x1 = function(_) {
2115
+ return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant_default(+_), area) : x1;
2116
+ };
2117
+ area.y = function(_) {
2118
+ return arguments.length ? (y0 = typeof _ === "function" ? _ : constant_default(+_), y1 = null, area) : y0;
2119
+ };
2120
+ area.y0 = function(_) {
2121
+ return arguments.length ? (y0 = typeof _ === "function" ? _ : constant_default(+_), area) : y0;
2122
+ };
2123
+ area.y1 = function(_) {
2124
+ return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant_default(+_), area) : y1;
2125
+ };
2126
+ area.lineX0 = area.lineY0 = function() {
2127
+ return arealine().x(x0).y(y0);
2128
+ };
2129
+ area.lineY1 = function() {
2130
+ return arealine().x(x0).y(y1);
2131
+ };
2132
+ area.lineX1 = function() {
2133
+ return arealine().x(x1).y(y0);
2134
+ };
2135
+ area.defined = function(_) {
2136
+ return arguments.length ? (defined = typeof _ === "function" ? _ : constant_default(!!_), area) : defined;
2137
+ };
2138
+ area.curve = function(_) {
2139
+ return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
2140
+ };
2141
+ area.context = function(_) {
2142
+ return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
2143
+ };
2144
+ return area;
2145
+ }
2146
+
2147
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/descending.js
2148
+ function descending_default(a, b) {
2149
+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
2150
+ }
2151
+
2152
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/identity.js
2153
+ function identity_default(d) {
2154
+ return d;
2155
+ }
2156
+
2157
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/pie.js
2158
+ function pie_default() {
2159
+ var value2 = identity_default, sortValues = descending_default, sort = null, startAngle = constant_default(0), endAngle = constant_default(tau), padAngle = constant_default(0);
2160
+ function pie(data) {
2161
+ var i, n = (data = array_default(data)).length, j, k, sum2 = 0, index = new Array(n), arcs = new Array(n), a0 = +startAngle.apply(this, arguments), da = Math.min(tau, Math.max(-tau, endAngle.apply(this, arguments) - a0)), a1, p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)), pa = p * (da < 0 ? -1 : 1), v;
2162
+ for (i = 0; i < n; ++i) {
2163
+ if ((v = arcs[index[i] = i] = +value2(data[i], i, data)) > 0) {
2164
+ sum2 += v;
2165
+ }
2166
+ }
2167
+ if (sortValues != null) index.sort(function(i2, j2) {
2168
+ return sortValues(arcs[i2], arcs[j2]);
2169
+ });
2170
+ else if (sort != null) index.sort(function(i2, j2) {
2171
+ return sort(data[i2], data[j2]);
2172
+ });
2173
+ for (i = 0, k = sum2 ? (da - n * pa) / sum2 : 0; i < n; ++i, a0 = a1) {
2174
+ j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
2175
+ data: data[j],
2176
+ index: i,
2177
+ value: v,
2178
+ startAngle: a0,
2179
+ endAngle: a1,
2180
+ padAngle: p
2181
+ };
2182
+ }
2183
+ return arcs;
2184
+ }
2185
+ pie.value = function(_) {
2186
+ return arguments.length ? (value2 = typeof _ === "function" ? _ : constant_default(+_), pie) : value2;
2187
+ };
2188
+ pie.sortValues = function(_) {
2189
+ return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
2190
+ };
2191
+ pie.sort = function(_) {
2192
+ return arguments.length ? (sort = _, sortValues = null, pie) : sort;
2193
+ };
2194
+ pie.startAngle = function(_) {
2195
+ return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant_default(+_), pie) : startAngle;
2196
+ };
2197
+ pie.endAngle = function(_) {
2198
+ return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant_default(+_), pie) : endAngle;
2199
+ };
2200
+ pie.padAngle = function(_) {
2201
+ return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant_default(+_), pie) : padAngle;
2202
+ };
2203
+ return pie;
2204
+ }
2205
+
2206
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/curve/basis.js
2207
+ function point(that, x2, y2) {
2208
+ that._context.bezierCurveTo(
2209
+ (2 * that._x0 + that._x1) / 3,
2210
+ (2 * that._y0 + that._y1) / 3,
2211
+ (that._x0 + 2 * that._x1) / 3,
2212
+ (that._y0 + 2 * that._y1) / 3,
2213
+ (that._x0 + 4 * that._x1 + x2) / 6,
2214
+ (that._y0 + 4 * that._y1 + y2) / 6
2215
+ );
2216
+ }
2217
+ function Basis(context) {
2218
+ this._context = context;
2219
+ }
2220
+ Basis.prototype = {
2221
+ areaStart: function() {
2222
+ this._line = 0;
2223
+ },
2224
+ areaEnd: function() {
2225
+ this._line = NaN;
2226
+ },
2227
+ lineStart: function() {
2228
+ this._x0 = this._x1 = this._y0 = this._y1 = NaN;
2229
+ this._point = 0;
2230
+ },
2231
+ lineEnd: function() {
2232
+ switch (this._point) {
2233
+ case 3:
2234
+ point(this, this._x1, this._y1);
2235
+ // falls through
2236
+ case 2:
2237
+ this._context.lineTo(this._x1, this._y1);
2238
+ break;
2239
+ }
2240
+ if (this._line || this._line !== 0 && this._point === 1) this._context.closePath();
2241
+ this._line = 1 - this._line;
2242
+ },
2243
+ point: function(x2, y2) {
2244
+ x2 = +x2, y2 = +y2;
2245
+ switch (this._point) {
2246
+ case 0:
2247
+ this._point = 1;
2248
+ this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2);
2249
+ break;
2250
+ case 1:
2251
+ this._point = 2;
2252
+ break;
2253
+ case 2:
2254
+ this._point = 3;
2255
+ this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6);
2256
+ // falls through
2257
+ default:
2258
+ point(this, x2, y2);
2259
+ break;
2260
+ }
2261
+ this._x0 = this._x1, this._x1 = x2;
2262
+ this._y0 = this._y1, this._y1 = y2;
2263
+ }
2264
+ };
2265
+ function basis_default(context) {
2266
+ return new Basis(context);
2267
+ }
2268
+
2269
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/curve/cardinal.js
2270
+ function point2(that, x2, y2) {
2271
+ that._context.bezierCurveTo(
2272
+ that._x1 + that._k * (that._x2 - that._x0),
2273
+ that._y1 + that._k * (that._y2 - that._y0),
2274
+ that._x2 + that._k * (that._x1 - x2),
2275
+ that._y2 + that._k * (that._y1 - y2),
2276
+ that._x2,
2277
+ that._y2
2278
+ );
2279
+ }
2280
+ function Cardinal(context, tension) {
2281
+ this._context = context;
2282
+ this._k = (1 - tension) / 6;
2283
+ }
2284
+ Cardinal.prototype = {
2285
+ areaStart: function() {
2286
+ this._line = 0;
2287
+ },
2288
+ areaEnd: function() {
2289
+ this._line = NaN;
2290
+ },
2291
+ lineStart: function() {
2292
+ this._x0 = this._x1 = this._x2 = this._y0 = this._y1 = this._y2 = NaN;
2293
+ this._point = 0;
2294
+ },
2295
+ lineEnd: function() {
2296
+ switch (this._point) {
2297
+ case 2:
2298
+ this._context.lineTo(this._x2, this._y2);
2299
+ break;
2300
+ case 3:
2301
+ point2(this, this._x1, this._y1);
2302
+ break;
2303
+ }
2304
+ if (this._line || this._line !== 0 && this._point === 1) this._context.closePath();
2305
+ this._line = 1 - this._line;
2306
+ },
2307
+ point: function(x2, y2) {
2308
+ x2 = +x2, y2 = +y2;
2309
+ switch (this._point) {
2310
+ case 0:
2311
+ this._point = 1;
2312
+ this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2);
2313
+ break;
2314
+ case 1:
2315
+ this._point = 2;
2316
+ this._x1 = x2, this._y1 = y2;
2317
+ break;
2318
+ case 2:
2319
+ this._point = 3;
2320
+ // falls through
2321
+ default:
2322
+ point2(this, x2, y2);
2323
+ break;
2324
+ }
2325
+ this._x0 = this._x1, this._x1 = this._x2, this._x2 = x2;
2326
+ this._y0 = this._y1, this._y1 = this._y2, this._y2 = y2;
2327
+ }
2328
+ };
2329
+ var cardinal_default = (function custom(tension) {
2330
+ function cardinal(context) {
2331
+ return new Cardinal(context, tension);
2332
+ }
2333
+ cardinal.tension = function(tension2) {
2334
+ return custom(+tension2);
2335
+ };
2336
+ return cardinal;
2337
+ })(0);
2338
+
2339
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/curve/monotone.js
2340
+ function sign(x2) {
2341
+ return x2 < 0 ? -1 : 1;
2342
+ }
2343
+ function slope3(that, x2, y2) {
2344
+ var h0 = that._x1 - that._x0, h1 = x2 - that._x1, s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0), s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0), p = (s0 * h1 + s1 * h0) / (h0 + h1);
2345
+ return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
2346
+ }
2347
+ function slope2(that, t) {
2348
+ var h = that._x1 - that._x0;
2349
+ return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
2350
+ }
2351
+ function point3(that, t02, t12) {
2352
+ var x0 = that._x0, y0 = that._y0, x1 = that._x1, y1 = that._y1, dx = (x1 - x0) / 3;
2353
+ that._context.bezierCurveTo(x0 + dx, y0 + dx * t02, x1 - dx, y1 - dx * t12, x1, y1);
2354
+ }
2355
+ function MonotoneX(context) {
2356
+ this._context = context;
2357
+ }
2358
+ MonotoneX.prototype = {
2359
+ areaStart: function() {
2360
+ this._line = 0;
2361
+ },
2362
+ areaEnd: function() {
2363
+ this._line = NaN;
2364
+ },
2365
+ lineStart: function() {
2366
+ this._x0 = this._x1 = this._y0 = this._y1 = this._t0 = NaN;
2367
+ this._point = 0;
2368
+ },
2369
+ lineEnd: function() {
2370
+ switch (this._point) {
2371
+ case 2:
2372
+ this._context.lineTo(this._x1, this._y1);
2373
+ break;
2374
+ case 3:
2375
+ point3(this, this._t0, slope2(this, this._t0));
2376
+ break;
2377
+ }
2378
+ if (this._line || this._line !== 0 && this._point === 1) this._context.closePath();
2379
+ this._line = 1 - this._line;
2380
+ },
2381
+ point: function(x2, y2) {
2382
+ var t12 = NaN;
2383
+ x2 = +x2, y2 = +y2;
2384
+ if (x2 === this._x1 && y2 === this._y1) return;
2385
+ switch (this._point) {
2386
+ case 0:
2387
+ this._point = 1;
2388
+ this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2);
2389
+ break;
2390
+ case 1:
2391
+ this._point = 2;
2392
+ break;
2393
+ case 2:
2394
+ this._point = 3;
2395
+ point3(this, slope2(this, t12 = slope3(this, x2, y2)), t12);
2396
+ break;
2397
+ default:
2398
+ point3(this, this._t0, t12 = slope3(this, x2, y2));
2399
+ break;
2400
+ }
2401
+ this._x0 = this._x1, this._x1 = x2;
2402
+ this._y0 = this._y1, this._y1 = y2;
2403
+ this._t0 = t12;
2404
+ }
2405
+ };
2406
+ function MonotoneY(context) {
2407
+ this._context = new ReflectContext(context);
2408
+ }
2409
+ (MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x2, y2) {
2410
+ MonotoneX.prototype.point.call(this, y2, x2);
2411
+ };
2412
+ function ReflectContext(context) {
2413
+ this._context = context;
2414
+ }
2415
+ ReflectContext.prototype = {
2416
+ moveTo: function(x2, y2) {
2417
+ this._context.moveTo(y2, x2);
2418
+ },
2419
+ closePath: function() {
2420
+ this._context.closePath();
2421
+ },
2422
+ lineTo: function(x2, y2) {
2423
+ this._context.lineTo(y2, x2);
2424
+ },
2425
+ bezierCurveTo: function(x1, y1, x2, y2, x3, y3) {
2426
+ this._context.bezierCurveTo(y1, x1, y2, x2, y3, x3);
2427
+ }
2428
+ };
2429
+ function monotoneX(context) {
2430
+ return new MonotoneX(context);
2431
+ }
2432
+
2433
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/curve/natural.js
2434
+ function Natural(context) {
2435
+ this._context = context;
2436
+ }
2437
+ Natural.prototype = {
2438
+ areaStart: function() {
2439
+ this._line = 0;
2440
+ },
2441
+ areaEnd: function() {
2442
+ this._line = NaN;
2443
+ },
2444
+ lineStart: function() {
2445
+ this._x = [];
2446
+ this._y = [];
2447
+ },
2448
+ lineEnd: function() {
2449
+ var x2 = this._x, y2 = this._y, n = x2.length;
2450
+ if (n) {
2451
+ this._line ? this._context.lineTo(x2[0], y2[0]) : this._context.moveTo(x2[0], y2[0]);
2452
+ if (n === 2) {
2453
+ this._context.lineTo(x2[1], y2[1]);
2454
+ } else {
2455
+ var px = controlPoints(x2), py = controlPoints(y2);
2456
+ for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
2457
+ this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x2[i1], y2[i1]);
2458
+ }
2459
+ }
2460
+ }
2461
+ if (this._line || this._line !== 0 && n === 1) this._context.closePath();
2462
+ this._line = 1 - this._line;
2463
+ this._x = this._y = null;
2464
+ },
2465
+ point: function(x2, y2) {
2466
+ this._x.push(+x2);
2467
+ this._y.push(+y2);
2468
+ }
2469
+ };
2470
+ function controlPoints(x2) {
2471
+ var i, n = x2.length - 1, m, a = new Array(n), b = new Array(n), r = new Array(n);
2472
+ a[0] = 0, b[0] = 2, r[0] = x2[0] + 2 * x2[1];
2473
+ for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x2[i] + 2 * x2[i + 1];
2474
+ a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x2[n - 1] + x2[n];
2475
+ for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
2476
+ a[n - 1] = r[n - 1] / b[n - 1];
2477
+ for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
2478
+ b[n - 1] = (x2[n] + a[n - 1]) / 2;
2479
+ for (i = 0; i < n - 1; ++i) b[i] = 2 * x2[i + 1] - a[i + 1];
2480
+ return [a, b];
2481
+ }
2482
+ function natural_default(context) {
2483
+ return new Natural(context);
2484
+ }
2485
+
2486
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/curve/step.js
2487
+ function Step(context, t) {
2488
+ this._context = context;
2489
+ this._t = t;
2490
+ }
2491
+ Step.prototype = {
2492
+ areaStart: function() {
2493
+ this._line = 0;
2494
+ },
2495
+ areaEnd: function() {
2496
+ this._line = NaN;
2497
+ },
2498
+ lineStart: function() {
2499
+ this._x = this._y = NaN;
2500
+ this._point = 0;
2501
+ },
2502
+ lineEnd: function() {
2503
+ if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
2504
+ if (this._line || this._line !== 0 && this._point === 1) this._context.closePath();
2505
+ if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
2506
+ },
2507
+ point: function(x2, y2) {
2508
+ x2 = +x2, y2 = +y2;
2509
+ switch (this._point) {
2510
+ case 0:
2511
+ this._point = 1;
2512
+ this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2);
2513
+ break;
2514
+ case 1:
2515
+ this._point = 2;
2516
+ // falls through
2517
+ default: {
2518
+ if (this._t <= 0) {
2519
+ this._context.lineTo(this._x, y2);
2520
+ this._context.lineTo(x2, y2);
2521
+ } else {
2522
+ var x1 = this._x * (1 - this._t) + x2 * this._t;
2523
+ this._context.lineTo(x1, this._y);
2524
+ this._context.lineTo(x1, y2);
2525
+ }
2526
+ break;
2527
+ }
2528
+ }
2529
+ this._x = x2, this._y = y2;
2530
+ }
2531
+ };
2532
+ function step_default(context) {
2533
+ return new Step(context, 0.5);
2534
+ }
2535
+ function stepBefore(context) {
2536
+ return new Step(context, 0);
2537
+ }
2538
+ function stepAfter(context) {
2539
+ return new Step(context, 1);
2540
+ }
2541
+
2542
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/offset/none.js
2543
+ function none_default(series, order) {
2544
+ if (!((n = series.length) > 1)) return;
2545
+ for (var i = 1, j, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
2546
+ s0 = s1, s1 = series[order[i]];
2547
+ for (j = 0; j < m; ++j) {
2548
+ s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
2549
+ }
2550
+ }
2551
+ }
2552
+
2553
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/order/none.js
2554
+ function none_default2(series) {
2555
+ var n = series.length, o = new Array(n);
2556
+ while (--n >= 0) o[n] = n;
2557
+ return o;
2558
+ }
2559
+
2560
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/stack.js
2561
+ function stackValue(d, key) {
2562
+ return d[key];
2563
+ }
2564
+ function stackSeries(key) {
2565
+ const series = [];
2566
+ series.key = key;
2567
+ return series;
2568
+ }
2569
+ function stack_default() {
2570
+ var keys = constant_default([]), order = none_default2, offset = none_default, value2 = stackValue;
2571
+ function stack(data) {
2572
+ var sz = Array.from(keys.apply(this, arguments), stackSeries), i, n = sz.length, j = -1, oz;
2573
+ for (const d of data) {
2574
+ for (i = 0, ++j; i < n; ++i) {
2575
+ (sz[i][j] = [0, +value2(d, sz[i].key, j, data)]).data = d;
2576
+ }
2577
+ }
2578
+ for (i = 0, oz = array_default(order(sz)); i < n; ++i) {
2579
+ sz[oz[i]].index = i;
2580
+ }
2581
+ offset(sz, oz);
2582
+ return sz;
2583
+ }
2584
+ stack.keys = function(_) {
2585
+ return arguments.length ? (keys = typeof _ === "function" ? _ : constant_default(Array.from(_)), stack) : keys;
2586
+ };
2587
+ stack.value = function(_) {
2588
+ return arguments.length ? (value2 = typeof _ === "function" ? _ : constant_default(+_), stack) : value2;
2589
+ };
2590
+ stack.order = function(_) {
2591
+ return arguments.length ? (order = _ == null ? none_default2 : typeof _ === "function" ? _ : constant_default(Array.from(_)), stack) : order;
2592
+ };
2593
+ stack.offset = function(_) {
2594
+ return arguments.length ? (offset = _ == null ? none_default : _, stack) : offset;
2595
+ };
2596
+ return stack;
2597
+ }
2598
+
2599
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/offset/expand.js
2600
+ function expand_default(series, order) {
2601
+ if (!((n = series.length) > 0)) return;
2602
+ for (var i, n, j = 0, m = series[0].length, y2; j < m; ++j) {
2603
+ for (y2 = i = 0; i < n; ++i) y2 += series[i][j][1] || 0;
2604
+ if (y2) for (i = 0; i < n; ++i) series[i][j][1] /= y2;
2605
+ }
2606
+ none_default(series, order);
2607
+ }
2608
+
2609
+ // ../../node_modules/.bun/d3-shape@3.2.0/node_modules/d3-shape/src/offset/silhouette.js
2610
+ function silhouette_default(series, order) {
2611
+ if (!((n = series.length) > 0)) return;
2612
+ for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
2613
+ for (var i = 0, y2 = 0; i < n; ++i) y2 += series[i][j][1] || 0;
2614
+ s0[j][1] += s0[j][0] = -y2 / 2;
2615
+ }
2616
+ none_default(series, order);
2617
+ }
2618
+
2619
+ // src/charts/line/curves.ts
2620
+ var CURVE_MAP = {
2621
+ linear: linear_default,
2622
+ monotone: monotoneX,
2623
+ step: step_default,
2624
+ "step-before": stepBefore,
2625
+ "step-after": stepAfter,
2626
+ basis: basis_default,
2627
+ cardinal: cardinal_default,
2628
+ natural: natural_default
2629
+ };
2630
+ function resolveCurve(interpolate) {
2631
+ if (!interpolate) return monotoneX;
2632
+ return CURVE_MAP[interpolate] ?? monotoneX;
2633
+ }
2634
+
2635
+ // src/charts/line/area.ts
2636
+ var DEFAULT_FILL_OPACITY = 0.15;
2637
+ function computeSingleArea(spec, scales, _chartArea) {
2638
+ const encoding = spec.encoding;
2639
+ const xChannel = encoding.x;
2640
+ const yChannel = encoding.y;
2641
+ if (!xChannel || !yChannel || !scales.x || !scales.y) return [];
2642
+ const yScale = scales.y.scale;
2643
+ const domain = yScale.domain();
2644
+ const baselineY = yScale(Math.min(domain[0], domain[1]));
2645
+ const colorField = encoding.color && "field" in encoding.color ? encoding.color.field : void 0;
2646
+ const groups = /* @__PURE__ */ new Map();
2647
+ if (!colorField) {
2648
+ groups.set("__default__", spec.data);
2649
+ } else {
2650
+ for (const row of spec.data) {
2651
+ const key = String(row[colorField] ?? "__default__");
2652
+ const existing = groups.get(key);
2653
+ if (existing) {
2654
+ existing.push(row);
2655
+ } else {
2656
+ groups.set(key, [row]);
2657
+ }
2658
+ }
2659
+ }
2660
+ const marks = [];
2661
+ for (const [seriesKey, rows] of groups) {
2662
+ const color2 = getColor(scales, seriesKey);
2663
+ const sortedRows = xChannel.type === "nominal" || xChannel.type === "ordinal" ? rows : sortByField(rows, xChannel.field);
2664
+ const validPoints = [];
2665
+ for (const row of sortedRows) {
2666
+ const xVal = scaleValue(scales.x.scale, scales.x.type, row[xChannel.field]);
2667
+ const yVal = scaleValue(scales.y.scale, scales.y.type, row[yChannel.field]);
2668
+ if (xVal === null || yVal === null) continue;
2669
+ validPoints.push({
2670
+ x: xVal,
2671
+ yTop: yVal,
2672
+ yBottom: baselineY,
2673
+ row
2674
+ });
2675
+ }
2676
+ if (validPoints.length === 0) continue;
2677
+ const curve = resolveCurve(spec.markDef.interpolate);
2678
+ const areaGenerator = area_default().x((d) => d.x).y0((d) => d.yBottom).y1((d) => d.yTop).curve(curve);
2679
+ const pathStr = areaGenerator(validPoints) ?? "";
2680
+ const topLineGenerator = line_default().x((d) => d.x).y((d) => d.yTop).curve(curve);
2681
+ const topPathStr = topLineGenerator(validPoints) ?? "";
2682
+ const topPoints = validPoints.map((p) => ({ x: p.x, y: p.yTop }));
2683
+ const bottomPoints = validPoints.map((p) => ({ x: p.x, y: p.yBottom }));
2684
+ const ariaLabel = seriesKey === "__default__" ? `Area with ${validPoints.length} data points` : `${seriesKey}: area with ${validPoints.length} data points`;
2685
+ const aria = { label: ariaLabel };
2686
+ marks.push({
2687
+ type: "area",
2688
+ topPoints,
2689
+ bottomPoints,
2690
+ path: pathStr,
2691
+ topPath: topPathStr,
2692
+ fill: color2,
2693
+ fillOpacity: DEFAULT_FILL_OPACITY,
2694
+ stroke: getRepresentativeColor4(color2),
2695
+ strokeWidth: 2,
2696
+ seriesKey: seriesKey === "__default__" ? void 0 : seriesKey,
2697
+ data: validPoints.map((p) => p.row),
2698
+ dataPoints: validPoints.map((p) => ({ x: p.x, y: p.yTop, datum: p.row })),
2699
+ aria
2700
+ });
2701
+ }
2702
+ return marks;
2703
+ }
2704
+ function computeStackedArea(spec, scales, chartArea) {
2705
+ const encoding = spec.encoding;
2706
+ const xChannel = encoding.x;
2707
+ const yChannel = encoding.y;
2708
+ const colorField = encoding.color && "field" in encoding.color ? encoding.color.field : void 0;
2709
+ if (!xChannel || !yChannel || !scales.x || !scales.y || !colorField) {
2710
+ return computeSingleArea(spec, scales, chartArea);
2711
+ }
2712
+ const sortedData = xChannel.type === "nominal" || xChannel.type === "ordinal" ? spec.data : sortByField(spec.data, xChannel.field);
2713
+ const seriesKeys = /* @__PURE__ */ new Set();
2714
+ const xValueSet = /* @__PURE__ */ new Set();
2715
+ const rowsByXSeries = /* @__PURE__ */ new Map();
2716
+ const rowsByX = /* @__PURE__ */ new Map();
2717
+ for (const row of sortedData) {
2718
+ const xStr = String(row[xChannel.field]);
2719
+ const series = String(row[colorField]);
2720
+ seriesKeys.add(series);
2721
+ xValueSet.add(xStr);
2722
+ rowsByXSeries.set(`${xStr}::${series}`, row);
2723
+ const existing = rowsByX.get(xStr);
2724
+ if (existing) {
2725
+ existing.push(row);
2726
+ } else {
2727
+ rowsByX.set(xStr, [row]);
2728
+ }
2729
+ }
2730
+ const keys = Array.from(seriesKeys);
2731
+ const xValues = Array.from(xValueSet);
2732
+ const pivotData = xValues.map((xVal) => {
2733
+ const pivot = { __x__: xVal };
2734
+ for (const key of keys) {
2735
+ pivot[key] = 0;
2736
+ }
2737
+ const xRows = rowsByX.get(xVal);
2738
+ if (xRows) {
2739
+ for (const row of xRows) {
2740
+ const series = String(row[colorField]);
2741
+ pivot[series] = row[yChannel.field] ?? 0;
2742
+ }
2743
+ }
2744
+ return pivot;
2745
+ });
2746
+ const stackProp = yChannel.stack;
2747
+ const offsetFn = stackProp === "normalize" ? expand_default : stackProp === "center" ? silhouette_default : none_default;
2748
+ const stackGenerator = stack_default().keys(keys).order(none_default2).offset(offsetFn);
2749
+ const stackedData = stackGenerator(pivotData);
2750
+ const yScale = scales.y.scale;
2751
+ const marks = [];
2752
+ for (const layer of stackedData) {
2753
+ const seriesKey = layer.key;
2754
+ const color2 = getColor(scales, seriesKey);
2755
+ const validPoints = [];
2756
+ for (const d of layer) {
2757
+ const xVal = scaleValue(scales.x.scale, scales.x.type, d.data.__x__);
2758
+ if (xVal === null) continue;
2759
+ const yTop = yScale(d[1]);
2760
+ const yBottom = yScale(d[0]);
2761
+ validPoints.push({ x: xVal, yTop, yBottom });
2762
+ }
2763
+ if (validPoints.length === 0) continue;
2764
+ const stackCurve = resolveCurve(spec.markDef.interpolate);
2765
+ const areaGenerator = area_default().x((p) => p.x).y0((p) => p.yBottom).y1((p) => p.yTop).curve(stackCurve);
2766
+ const pathStr = areaGenerator(validPoints) ?? "";
2767
+ const topLineGenerator = line_default().x((p) => p.x).y((p) => p.yTop).curve(stackCurve);
2768
+ const topPathStr = topLineGenerator(validPoints) ?? "";
2769
+ const topPoints = validPoints.map((p) => ({ x: p.x, y: p.yTop }));
2770
+ const bottomPoints = validPoints.map((p) => ({ x: p.x, y: p.yBottom }));
2771
+ const aria = {
2772
+ label: `${seriesKey}: stacked area with ${validPoints.length} data points`
2773
+ };
2774
+ marks.push({
2775
+ type: "area",
2776
+ topPoints,
2777
+ bottomPoints,
2778
+ path: pathStr,
2779
+ topPath: topPathStr,
2780
+ fill: color2,
2781
+ fillOpacity: 0.7,
2782
+ // Higher opacity for stacked so layers are visible
2783
+ stroke: getRepresentativeColor4(color2),
2784
+ strokeWidth: 1,
2785
+ seriesKey,
2786
+ data: layer.map((d) => {
2787
+ const xStr = String(d.data.__x__);
2788
+ return rowsByXSeries.get(`${xStr}::${seriesKey}`) ?? d.data;
2789
+ }),
2790
+ dataPoints: validPoints.map((p, idx) => {
2791
+ const xStr = String(layer[idx]?.data.__x__);
2792
+ const datum = rowsByXSeries.get(`${xStr}::${seriesKey}`) ?? layer[idx]?.data ?? {};
2793
+ return { x: p.x, y: p.yTop, datum };
2794
+ }),
2795
+ aria
2796
+ });
2797
+ }
2798
+ return marks;
2799
+ }
2800
+ function computeAreaMarks(spec, scales, chartArea) {
2801
+ const encoding = spec.encoding;
2802
+ const hasColor = !!encoding.color;
2803
+ if (hasColor) {
2804
+ return computeStackedArea(spec, scales, chartArea);
2805
+ }
2806
+ return computeSingleArea(spec, scales, chartArea);
2807
+ }
2808
+
2809
+ // src/charts/line/compute.ts
2810
+ import { getRepresentativeColor as getRepresentativeColor5 } from "@opendata-ai/openchart-core";
2811
+ var DEFAULT_STROKE_WIDTH = 2.5;
2812
+ var DEFAULT_POINT_RADIUS = 3;
2813
+ function computeLineMarks(spec, scales, _chartArea, _strategy) {
2814
+ const encoding = spec.encoding;
2815
+ const xChannel = encoding.x;
2816
+ const yChannel = encoding.y;
2817
+ if (!xChannel || !yChannel || !scales.x || !scales.y) {
2818
+ return [];
603
2819
  }
604
- if (pred.gt !== void 0) {
605
- return numValue > pred.gt;
2820
+ const colorEnc = encoding.color && "field" in encoding.color ? encoding.color : void 0;
2821
+ const isSequentialColor = colorEnc?.type === "quantitative";
2822
+ const colorField = isSequentialColor ? void 0 : colorEnc?.field;
2823
+ const sequentialColorField = isSequentialColor ? colorEnc.field : void 0;
2824
+ const groups = groupByField(spec.data, colorField);
2825
+ const marks = [];
2826
+ for (const [seriesKey, rows] of groups) {
2827
+ const color2 = isSequentialColor ? getSequentialColor(scales, _getMidValue(rows, sequentialColorField)) : getColor(scales, seriesKey);
2828
+ const strokeColor = getRepresentativeColor5(color2);
2829
+ const sortedRows = xChannel.type === "nominal" || xChannel.type === "ordinal" ? rows : sortByField(rows, xChannel.field);
2830
+ const pointsWithData = [];
2831
+ const segments = [];
2832
+ let currentSegment = [];
2833
+ for (const row of sortedRows) {
2834
+ const xVal = scaleValue(scales.x.scale, scales.x.type, row[xChannel.field]);
2835
+ const yVal = scaleValue(scales.y.scale, scales.y.type, row[yChannel.field]);
2836
+ if (xVal === null || yVal === null) {
2837
+ if (currentSegment.length > 0) {
2838
+ segments.push(currentSegment);
2839
+ currentSegment = [];
2840
+ }
2841
+ continue;
2842
+ }
2843
+ const point5 = { x: xVal, y: yVal };
2844
+ currentSegment.push(point5);
2845
+ pointsWithData.push({ ...point5, row });
2846
+ }
2847
+ if (currentSegment.length > 0) {
2848
+ segments.push(currentSegment);
2849
+ }
2850
+ const curve = resolveCurve(spec.markDef.interpolate);
2851
+ const lineGenerator = line_default().x((d) => d.x).y((d) => d.y).curve(curve);
2852
+ const allPoints = [];
2853
+ const pathParts = [];
2854
+ for (const segment of segments) {
2855
+ if (segment.length === 0) continue;
2856
+ const pathStr = lineGenerator(segment);
2857
+ if (pathStr) {
2858
+ pathParts.push(pathStr);
2859
+ }
2860
+ allPoints.push(...segment);
2861
+ }
2862
+ if (allPoints.length === 0) continue;
2863
+ const ariaLabel = seriesKey === "__default__" ? `Line with ${allPoints.length} data points` : `${seriesKey}: line with ${allPoints.length} data points`;
2864
+ const aria = {
2865
+ label: ariaLabel
2866
+ };
2867
+ const combinedPath = pathParts.join(" ");
2868
+ const seriesStyleKey = seriesKey === "__default__" ? void 0 : seriesKey;
2869
+ const styleOverride = seriesStyleKey ? spec.seriesStyles?.[seriesStyleKey] : void 0;
2870
+ let strokeDasharray;
2871
+ if (styleOverride?.lineStyle === "dashed") strokeDasharray = "6 4";
2872
+ else if (styleOverride?.lineStyle === "dotted") strokeDasharray = "2 3";
2873
+ const lineMark = {
2874
+ type: "line",
2875
+ points: allPoints,
2876
+ path: combinedPath,
2877
+ stroke: strokeColor,
2878
+ strokeWidth: styleOverride?.strokeWidth ?? DEFAULT_STROKE_WIDTH,
2879
+ strokeDasharray,
2880
+ opacity: styleOverride?.opacity,
2881
+ seriesKey: seriesStyleKey,
2882
+ data: pointsWithData.map((p) => p.row),
2883
+ dataPoints: pointsWithData.map((p) => ({ x: p.x, y: p.y, datum: p.row })),
2884
+ aria
2885
+ };
2886
+ marks.push(lineMark);
2887
+ const markPoint = spec.markDef.point;
2888
+ const showPoints = markPoint === true || markPoint === "transparent" || isSequentialColor;
2889
+ if (showPoints) {
2890
+ const isTransparent = markPoint === "transparent";
2891
+ const seriesShowPoints = styleOverride?.showPoints !== false;
2892
+ for (let i = 0; i < pointsWithData.length; i++) {
2893
+ const p = pointsWithData[i];
2894
+ const visible = seriesShowPoints && !isTransparent;
2895
+ let pointColor = color2;
2896
+ if (isSequentialColor) {
2897
+ const val = Number(p.row[sequentialColorField]);
2898
+ pointColor = Number.isFinite(val) ? getSequentialColor(scales, val) : color2;
2899
+ }
2900
+ const pointMark = {
2901
+ type: "point",
2902
+ cx: p.x,
2903
+ cy: p.y,
2904
+ r: visible ? DEFAULT_POINT_RADIUS : 0,
2905
+ fill: pointColor,
2906
+ stroke: visible ? "#ffffff" : "transparent",
2907
+ strokeWidth: visible ? 1.5 : 0,
2908
+ fillOpacity: isTransparent ? 0 : 1,
2909
+ data: p.row,
2910
+ aria: {
2911
+ label: `Data point: ${xChannel.field}=${String(p.row[xChannel.field])}, ${yChannel.field}=${String(p.row[yChannel.field])}`
2912
+ }
2913
+ };
2914
+ marks.push(pointMark);
2915
+ }
2916
+ }
606
2917
  }
607
- if (pred.gte !== void 0) {
608
- return numValue >= pred.gte;
2918
+ return marks;
2919
+ }
2920
+ function _getMidValue(rows, field) {
2921
+ const values = rows.map((r) => Number(r[field])).filter(Number.isFinite);
2922
+ if (values.length === 0) return 0;
2923
+ const sorted = values.sort((a, b) => a - b);
2924
+ return sorted[Math.floor(sorted.length / 2)];
2925
+ }
2926
+
2927
+ // src/charts/line/labels.ts
2928
+ import {
2929
+ EXTENDED_OFFSET_STRATEGIES,
2930
+ estimateTextWidth as estimateTextWidth5,
2931
+ resolveCollisions as resolveCollisions4
2932
+ } from "@opendata-ai/openchart-core";
2933
+ var LABEL_FONT_SIZE4 = 11;
2934
+ var LABEL_FONT_WEIGHT4 = 600;
2935
+ var LABEL_OFFSET_X2 = 6;
2936
+ function computeLineLabels(marks, strategy, density = "auto", labelOffsets) {
2937
+ const result = /* @__PURE__ */ new Map();
2938
+ if (density === "none") return result;
2939
+ if (strategy.labelMode === "none") {
2940
+ return result;
609
2941
  }
610
- if (pred.range !== void 0) {
611
- const [min3, max3] = pred.range;
612
- return numValue >= min3 && numValue <= max3;
2942
+ const candidates = [];
2943
+ const seriesOrder = [];
2944
+ for (const mark of marks) {
2945
+ if (mark.points.length === 0) continue;
2946
+ const labelText = mark.seriesKey ?? "";
2947
+ if (!labelText) continue;
2948
+ const lastPoint = mark.points[mark.points.length - 1];
2949
+ const textWidth = estimateTextWidth5(labelText, LABEL_FONT_SIZE4, LABEL_FONT_WEIGHT4);
2950
+ const textHeight = LABEL_FONT_SIZE4 * 1.2;
2951
+ candidates.push({
2952
+ text: labelText,
2953
+ anchorX: lastPoint.x + LABEL_OFFSET_X2,
2954
+ anchorY: lastPoint.y - textHeight / 2,
2955
+ width: textWidth,
2956
+ height: textHeight,
2957
+ priority: "data",
2958
+ style: {
2959
+ fontFamily: "system-ui, -apple-system, sans-serif",
2960
+ fontSize: LABEL_FONT_SIZE4,
2961
+ fontWeight: LABEL_FONT_WEIGHT4,
2962
+ fill: mark.stroke,
2963
+ lineHeight: 1.2,
2964
+ textAnchor: "start",
2965
+ dominantBaseline: "central"
2966
+ }
2967
+ });
2968
+ seriesOrder.push(labelText);
2969
+ }
2970
+ if (candidates.length === 0) return result;
2971
+ if (density === "all") {
2972
+ for (let i = 0; i < candidates.length; i++) {
2973
+ const c = candidates[i];
2974
+ const seriesKey = seriesOrder[i];
2975
+ const userOffset = labelOffsets?.[seriesKey];
2976
+ result.set(seriesKey, {
2977
+ text: c.text,
2978
+ x: c.anchorX + (userOffset?.dx ?? 0),
2979
+ y: c.anchorY + (userOffset?.dy ?? 0),
2980
+ style: c.style,
2981
+ visible: true
2982
+ });
2983
+ }
2984
+ return result;
613
2985
  }
614
- if (pred.oneOf !== void 0) {
615
- return pred.oneOf.some((v) => v == value2);
2986
+ const resolved = resolveCollisions4(candidates, EXTENDED_OFFSET_STRATEGIES);
2987
+ for (let i = 0; i < resolved.length; i++) {
2988
+ const seriesKey = seriesOrder[i];
2989
+ const label = resolved[i];
2990
+ const userOffset = labelOffsets?.[seriesKey];
2991
+ if (userOffset) {
2992
+ label.x += userOffset.dx ?? 0;
2993
+ label.y += userOffset.dy ?? 0;
2994
+ }
2995
+ result.set(seriesKey, label);
616
2996
  }
617
- return true;
2997
+ return result;
618
2998
  }
619
- function evaluatePredicate(datum, predicate) {
620
- if (isFieldPredicate(predicate)) {
621
- return evaluateFieldPredicate(datum, predicate);
2999
+
3000
+ // src/charts/line/index.ts
3001
+ var lineRenderer = (spec, scales, chartArea, strategy, _theme) => {
3002
+ const marks = computeLineMarks(spec, scales, chartArea, strategy);
3003
+ const lineMarks = marks.filter((m) => m.type === "line");
3004
+ const labelMap = computeLineLabels(lineMarks, strategy, spec.labels.density, spec.labels.offsets);
3005
+ for (const mark of marks) {
3006
+ if (mark.type === "line" && mark.seriesKey) {
3007
+ const label = labelMap.get(mark.seriesKey);
3008
+ if (label) {
3009
+ mark.label = label;
3010
+ }
3011
+ }
622
3012
  }
623
- if ("and" in predicate) {
624
- return predicate.and.every((p) => evaluatePredicate(datum, p));
3013
+ return marks;
3014
+ };
3015
+ var areaRenderer = (spec, scales, chartArea, strategy, _theme) => {
3016
+ const areas = computeAreaMarks(spec, scales, chartArea);
3017
+ const encoding = spec.encoding;
3018
+ const hasColor = !!(encoding.color && "field" in encoding.color);
3019
+ const lines = hasColor ? linesFromAreas(areas) : computeLineMarks(spec, scales, chartArea, strategy);
3020
+ return [...areas, ...lines];
3021
+ };
3022
+ function linesFromAreas(areas) {
3023
+ return areas.map((a) => ({
3024
+ type: "line",
3025
+ points: a.topPoints,
3026
+ path: a.topPath,
3027
+ stroke: getRepresentativeColor6(a.fill),
3028
+ strokeWidth: a.strokeWidth ?? 1,
3029
+ seriesKey: a.seriesKey,
3030
+ data: a.data,
3031
+ dataPoints: a.dataPoints,
3032
+ aria: { label: `${a.seriesKey ?? "Series"}: line with ${a.topPoints.length} data points` }
3033
+ }));
3034
+ }
3035
+
3036
+ // src/charts/pie/compute.ts
3037
+ import { isConditionalDef, isGradientDef as isGradientDef3 } from "@opendata-ai/openchart-core";
3038
+ var SMALL_SLICE_THRESHOLD = 0.03;
3039
+ var DEFAULT_PALETTE = [
3040
+ "#1b7fa3",
3041
+ "#c44e52",
3042
+ "#6a9f58",
3043
+ "#d47215",
3044
+ "#507e79",
3045
+ "#9a6a8d",
3046
+ "#c4636b",
3047
+ "#9c755f",
3048
+ "#a88f22",
3049
+ "#858078"
3050
+ ];
3051
+ function groupSmallSlices(slices, threshold2) {
3052
+ const total = slices.reduce((sum2, s) => sum2 + s.value, 0);
3053
+ if (total === 0) return slices;
3054
+ const big = [];
3055
+ let otherValue = 0;
3056
+ for (const slice2 of slices) {
3057
+ if (slice2.value / total < threshold2) {
3058
+ otherValue += slice2.value;
3059
+ } else {
3060
+ big.push(slice2);
3061
+ }
625
3062
  }
626
- if ("or" in predicate) {
627
- return predicate.or.some((p) => evaluatePredicate(datum, p));
3063
+ if (otherValue > 0) {
3064
+ big.push({
3065
+ label: "Other",
3066
+ value: otherValue,
3067
+ originalRow: { label: "Other", value: otherValue }
3068
+ });
628
3069
  }
629
- if ("not" in predicate) {
630
- return !evaluatePredicate(datum, predicate.not);
3070
+ return big;
3071
+ }
3072
+ function computePieMarks(spec, scales, chartArea, _strategy, isDonut = false) {
3073
+ const encoding = spec.encoding;
3074
+ const valueChannel = encoding.y ?? encoding.x;
3075
+ const categoryField = encoding.color && "field" in encoding.color ? encoding.color.field : void 0;
3076
+ const conditionalColor = encoding.color && isConditionalDef(encoding.color) ? encoding.color : void 0;
3077
+ if (!valueChannel) return [];
3078
+ let slices = [];
3079
+ if (categoryField) {
3080
+ const categoryTotals = /* @__PURE__ */ new Map();
3081
+ const categoryRows = /* @__PURE__ */ new Map();
3082
+ for (const row of spec.data) {
3083
+ const cat = String(row[categoryField] ?? "");
3084
+ const val = Number(row[valueChannel.field] ?? 0);
3085
+ if (!Number.isFinite(val) || val < 0) continue;
3086
+ categoryTotals.set(cat, (categoryTotals.get(cat) ?? 0) + val);
3087
+ if (!categoryRows.has(cat)) {
3088
+ categoryRows.set(cat, row);
3089
+ }
3090
+ }
3091
+ for (const [label, value2] of categoryTotals) {
3092
+ slices.push({
3093
+ label,
3094
+ value: value2,
3095
+ originalRow: categoryRows.get(label) ?? {
3096
+ [categoryField]: label,
3097
+ [valueChannel.field]: value2
3098
+ }
3099
+ });
3100
+ }
3101
+ } else {
3102
+ for (let i = 0; i < spec.data.length; i++) {
3103
+ const row = spec.data[i];
3104
+ const val = Number(row[valueChannel.field] ?? 0);
3105
+ if (!Number.isFinite(val) || val < 0) continue;
3106
+ const label = String(row.label ?? row.name ?? row.category ?? `Slice ${i + 1}`);
3107
+ slices.push({ label, value: val, originalRow: row });
3108
+ }
3109
+ }
3110
+ if (slices.length === 0) return [];
3111
+ slices.sort((a, b) => b.value - a.value);
3112
+ slices = groupSmallSlices(slices, SMALL_SLICE_THRESHOLD);
3113
+ const pieGenerator = pie_default().value((d) => d.value).sort(null).padAngle(0.01);
3114
+ const arcs = pieGenerator(slices);
3115
+ const centerX = chartArea.x + chartArea.width / 2;
3116
+ const centerY = chartArea.y + chartArea.height / 2;
3117
+ const outerRadius = Math.min(chartArea.width, chartArea.height) / 2 * 0.85;
3118
+ const innerRadius = isDonut ? outerRadius * 0.6 : 0;
3119
+ const arcGenerator = arc_default().innerRadius(innerRadius).outerRadius(outerRadius);
3120
+ const marks = [];
3121
+ const center2 = { x: centerX, y: centerY };
3122
+ const total = slices.reduce((sum2, s) => sum2 + s.value, 0);
3123
+ for (let i = 0; i < arcs.length; i++) {
3124
+ const arcDatum = arcs[i];
3125
+ const slice2 = arcDatum.data;
3126
+ let color2;
3127
+ if (conditionalColor) {
3128
+ const resolved = resolveConditionalValue(
3129
+ slice2.originalRow,
3130
+ conditionalColor
3131
+ );
3132
+ if (resolved != null) {
3133
+ color2 = isGradientDef3(resolved) ? resolved : String(resolved);
3134
+ } else if (scales.color && categoryField) {
3135
+ const colorScale = scales.color.scale;
3136
+ color2 = colorScale(slice2.label);
3137
+ } else {
3138
+ color2 = DEFAULT_PALETTE[i % DEFAULT_PALETTE.length];
3139
+ }
3140
+ } else if (scales.color && categoryField) {
3141
+ const colorScale = scales.color.scale;
3142
+ color2 = colorScale(slice2.label);
3143
+ } else {
3144
+ color2 = DEFAULT_PALETTE[i % DEFAULT_PALETTE.length];
3145
+ }
3146
+ const path2 = arcGenerator(arcDatum) ?? "";
3147
+ const centroidResult = arcGenerator.centroid(arcDatum);
3148
+ const percentage = total > 0 ? (slice2.value / total * 100).toFixed(1) : "0";
3149
+ const aria = {
3150
+ label: `${slice2.label}: ${slice2.value} (${percentage}%)`
3151
+ };
3152
+ marks.push({
3153
+ type: "arc",
3154
+ path: path2,
3155
+ centroid: {
3156
+ x: centroidResult[0] + centerX,
3157
+ y: centroidResult[1] + centerY
3158
+ },
3159
+ center: center2,
3160
+ innerRadius,
3161
+ outerRadius,
3162
+ startAngle: arcDatum.startAngle,
3163
+ endAngle: arcDatum.endAngle,
3164
+ fill: color2,
3165
+ stroke: "#ffffff",
3166
+ strokeWidth: 2,
3167
+ data: slice2.originalRow,
3168
+ aria
3169
+ });
631
3170
  }
632
- return true;
3171
+ return marks;
633
3172
  }
634
3173
 
635
- // src/transforms/conditional.ts
636
- function resolveConditionalValue(datum, channelDef) {
637
- const conditions = Array.isArray(channelDef.condition) ? channelDef.condition : [channelDef.condition];
638
- for (const cond of conditions) {
639
- if (evaluatePredicate(datum, cond.test)) {
640
- if (cond.field !== void 0) {
641
- return datum[cond.field];
3174
+ // src/charts/pie/labels.ts
3175
+ import { estimateTextWidth as estimateTextWidth6, resolveCollisions as resolveCollisions5 } from "@opendata-ai/openchart-core";
3176
+ var LABEL_FONT_SIZE5 = 10;
3177
+ var LABEL_FONT_WEIGHT5 = 500;
3178
+ var LEADER_LINE_OFFSET = 12;
3179
+ function computePieLabels(marks, _chartArea, density = "auto", _textFill = "#333333") {
3180
+ if (marks.length === 0) return [];
3181
+ const centerX = marks[0].center.x;
3182
+ const centerY = marks[0].center.y;
3183
+ const targetMarks = filterByDensity(marks, density);
3184
+ if (targetMarks.length === 0) return [];
3185
+ const candidates = [];
3186
+ const targetMarkIndices = [];
3187
+ for (let mi = 0; mi < targetMarks.length; mi++) {
3188
+ const mark = targetMarks[mi];
3189
+ const ariaLabel = mark.aria.label;
3190
+ const firstColon = ariaLabel.indexOf(":");
3191
+ const labelText = firstColon >= 0 ? ariaLabel.slice(0, firstColon).trim() : "";
3192
+ if (!labelText) continue;
3193
+ const textWidth = estimateTextWidth6(labelText, LABEL_FONT_SIZE5, LABEL_FONT_WEIGHT5);
3194
+ const textHeight = LABEL_FONT_SIZE5 * 1.2;
3195
+ const midAngle = (mark.startAngle + mark.endAngle) / 2;
3196
+ const labelRadius = mark.outerRadius + LEADER_LINE_OFFSET;
3197
+ const labelX = centerX + Math.sin(midAngle) * labelRadius;
3198
+ const labelY = centerY - Math.cos(midAngle) * labelRadius;
3199
+ const isRight = Math.sin(midAngle) > 0;
3200
+ candidates.push({
3201
+ text: labelText,
3202
+ anchorX: isRight ? labelX : labelX - textWidth,
3203
+ anchorY: labelY - textHeight / 2,
3204
+ width: textWidth,
3205
+ height: textHeight,
3206
+ priority: "data",
3207
+ style: {
3208
+ fontFamily: "system-ui, -apple-system, sans-serif",
3209
+ fontSize: LABEL_FONT_SIZE5,
3210
+ fontWeight: LABEL_FONT_WEIGHT5,
3211
+ fill: _textFill,
3212
+ lineHeight: 1.2,
3213
+ textAnchor: isRight ? "start" : "end",
3214
+ dominantBaseline: "central"
642
3215
  }
643
- return cond.value;
3216
+ });
3217
+ targetMarkIndices.push(mi);
3218
+ }
3219
+ if (candidates.length === 0) return [];
3220
+ let resolved;
3221
+ if (density === "all") {
3222
+ resolved = candidates.map((c) => ({
3223
+ text: c.text,
3224
+ x: c.anchorX,
3225
+ y: c.anchorY,
3226
+ style: c.style,
3227
+ visible: true
3228
+ }));
3229
+ } else {
3230
+ resolved = resolveCollisions5(candidates);
3231
+ }
3232
+ for (let i = 0; i < resolved.length && i < targetMarks.length; i++) {
3233
+ const label = resolved[i];
3234
+ const mark = targetMarks[i];
3235
+ if (label.visible) {
3236
+ label.connector = {
3237
+ from: { x: label.x, y: label.y },
3238
+ to: { x: mark.centroid.x, y: mark.centroid.y },
3239
+ stroke: _textFill,
3240
+ style: "straight"
3241
+ };
644
3242
  }
645
3243
  }
646
- return channelDef.value;
647
- }
648
- function isConditionalValueDef(def) {
649
- return def !== null && typeof def === "object" && "condition" in def;
3244
+ return resolved;
650
3245
  }
651
3246
 
3247
+ // src/charts/pie/index.ts
3248
+ var pieRenderer = (spec, scales, chartArea, strategy, theme) => {
3249
+ const marks = computePieMarks(spec, scales, chartArea, strategy, false);
3250
+ const labels = computePieLabels(marks, chartArea, spec.labels.density, theme.colors.text);
3251
+ for (let i = 0; i < marks.length && i < labels.length; i++) {
3252
+ marks[i].label = labels[i];
3253
+ }
3254
+ return marks;
3255
+ };
3256
+ var donutRenderer = (spec, scales, chartArea, strategy, theme) => {
3257
+ const marks = computePieMarks(spec, scales, chartArea, strategy, true);
3258
+ const labels = computePieLabels(marks, chartArea, spec.labels.density, theme.colors.text);
3259
+ for (let i = 0; i < marks.length && i < labels.length; i++) {
3260
+ marks[i].label = labels[i];
3261
+ }
3262
+ return marks;
3263
+ };
3264
+
652
3265
  // src/charts/registry.ts
653
3266
  var renderers = /* @__PURE__ */ new Map();
654
3267
  function registerChartRenderer(type, renderer) {
@@ -661,6 +3274,78 @@ function clearRenderers() {
661
3274
  renderers.clear();
662
3275
  }
663
3276
 
3277
+ // src/charts/rule/index.ts
3278
+ import { getRepresentativeColor as getRepresentativeColor7 } from "@opendata-ai/openchart-core";
3279
+ function computeRuleMarks(spec, scales, chartArea) {
3280
+ const encoding = spec.encoding;
3281
+ const xChannel = encoding.x;
3282
+ const yChannel = encoding.y;
3283
+ const x2Channel = encoding.x2;
3284
+ const y2Channel = encoding.y2;
3285
+ const colorEncoding = encoding.color && "field" in encoding.color ? encoding.color : void 0;
3286
+ const colorField = colorEncoding?.field;
3287
+ const marks = [];
3288
+ for (const row of spec.data) {
3289
+ let x1 = chartArea.x;
3290
+ let y1 = chartArea.y;
3291
+ let x2 = chartArea.x + chartArea.width;
3292
+ let y2 = chartArea.y + chartArea.height;
3293
+ if (xChannel && scales.x) {
3294
+ const xVal = scaleValue(scales.x.scale, scales.x.type, row[xChannel.field]);
3295
+ if (xVal == null) continue;
3296
+ x1 = xVal;
3297
+ x2 = xVal;
3298
+ }
3299
+ if (yChannel && scales.y) {
3300
+ const yVal = scaleValue(scales.y.scale, scales.y.type, row[yChannel.field]);
3301
+ if (yVal == null) continue;
3302
+ y1 = yVal;
3303
+ y2 = yVal;
3304
+ }
3305
+ if (xChannel && !yChannel) {
3306
+ y1 = chartArea.y;
3307
+ y2 = chartArea.y + chartArea.height;
3308
+ }
3309
+ if (yChannel && !xChannel) {
3310
+ x1 = chartArea.x;
3311
+ x2 = chartArea.x + chartArea.width;
3312
+ }
3313
+ if (x2Channel && scales.x) {
3314
+ const x2Val = scaleValue(scales.x.scale, scales.x.type, row[x2Channel.field]);
3315
+ if (x2Val != null) x2 = x2Val;
3316
+ }
3317
+ if (y2Channel && scales.y) {
3318
+ const y2Val = scaleValue(scales.y.scale, scales.y.type, row[y2Channel.field]);
3319
+ if (y2Val != null) y2 = y2Val;
3320
+ }
3321
+ const color2 = getRepresentativeColor7(
3322
+ colorField ? getColor(scales, String(row[colorField] ?? "__default__")) : getColor(scales, "__default__")
3323
+ );
3324
+ const strokeDashEncoding = encoding.strokeDash && "field" in encoding.strokeDash ? encoding.strokeDash : void 0;
3325
+ const strokeDasharray = strokeDashEncoding ? String(row[strokeDashEncoding.field] ?? "") : void 0;
3326
+ const aria = {
3327
+ label: `Rule from (${Math.round(x1)}, ${Math.round(y1)}) to (${Math.round(x2)}, ${Math.round(y2)})`
3328
+ };
3329
+ marks.push({
3330
+ type: "rule",
3331
+ x1,
3332
+ y1,
3333
+ x2,
3334
+ y2,
3335
+ stroke: color2,
3336
+ strokeWidth: 1,
3337
+ strokeDasharray: strokeDasharray || void 0,
3338
+ opacity: encoding.opacity && "field" in encoding.opacity ? Math.max(0, Math.min(1, Number(row[encoding.opacity.field]) || 1)) : void 0,
3339
+ data: row,
3340
+ aria
3341
+ });
3342
+ }
3343
+ return marks;
3344
+ }
3345
+ var ruleRenderer = (spec, scales, chartArea, _strategy, _theme) => {
3346
+ return computeRuleMarks(spec, scales, chartArea);
3347
+ };
3348
+
664
3349
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/ascending.js
665
3350
  function ascending(a, b) {
666
3351
  return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
@@ -676,38 +3361,38 @@ function bisector(f) {
676
3361
  let compare1, compare2, delta;
677
3362
  if (f.length !== 2) {
678
3363
  compare1 = ascending;
679
- compare2 = (d, x) => ascending(f(d), x);
680
- delta = (d, x) => f(d) - x;
3364
+ compare2 = (d, x2) => ascending(f(d), x2);
3365
+ delta = (d, x2) => f(d) - x2;
681
3366
  } else {
682
3367
  compare1 = f === ascending || f === descending ? f : zero;
683
3368
  compare2 = f;
684
3369
  delta = f;
685
3370
  }
686
- function left2(a, x, lo = 0, hi = a.length) {
3371
+ function left2(a, x2, lo = 0, hi = a.length) {
687
3372
  if (lo < hi) {
688
- if (compare1(x, x) !== 0) return hi;
3373
+ if (compare1(x2, x2) !== 0) return hi;
689
3374
  do {
690
3375
  const mid = lo + hi >>> 1;
691
- if (compare2(a[mid], x) < 0) lo = mid + 1;
3376
+ if (compare2(a[mid], x2) < 0) lo = mid + 1;
692
3377
  else hi = mid;
693
3378
  } while (lo < hi);
694
3379
  }
695
3380
  return lo;
696
3381
  }
697
- function right2(a, x, lo = 0, hi = a.length) {
3382
+ function right2(a, x2, lo = 0, hi = a.length) {
698
3383
  if (lo < hi) {
699
- if (compare1(x, x) !== 0) return hi;
3384
+ if (compare1(x2, x2) !== 0) return hi;
700
3385
  do {
701
3386
  const mid = lo + hi >>> 1;
702
- if (compare2(a[mid], x) <= 0) lo = mid + 1;
3387
+ if (compare2(a[mid], x2) <= 0) lo = mid + 1;
703
3388
  else hi = mid;
704
3389
  } while (lo < hi);
705
3390
  }
706
3391
  return lo;
707
3392
  }
708
- function center2(a, x, lo = 0, hi = a.length) {
709
- const i = left2(a, x, lo, hi - 1);
710
- return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
3393
+ function center2(a, x2, lo = 0, hi = a.length) {
3394
+ const i = left2(a, x2, lo, hi - 1);
3395
+ return i > lo && delta(a[i - 1], x2) > -delta(a[i], x2) ? i - 1 : i;
711
3396
  }
712
3397
  return { left: left2, center: center2, right: right2 };
713
3398
  }
@@ -716,8 +3401,8 @@ function zero() {
716
3401
  }
717
3402
 
718
3403
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/number.js
719
- function number(x) {
720
- return x === null ? NaN : +x;
3404
+ function number(x2) {
3405
+ return x2 === null ? NaN : +x2;
721
3406
  }
722
3407
 
723
3408
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/bisect.js
@@ -729,16 +3414,16 @@ var bisect_default = bisectRight;
729
3414
 
730
3415
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/extent.js
731
3416
  function extent(values, valueof) {
732
- let min3;
733
- let max3;
3417
+ let min4;
3418
+ let max4;
734
3419
  if (valueof === void 0) {
735
3420
  for (const value2 of values) {
736
3421
  if (value2 != null) {
737
- if (min3 === void 0) {
738
- if (value2 >= value2) min3 = max3 = value2;
3422
+ if (min4 === void 0) {
3423
+ if (value2 >= value2) min4 = max4 = value2;
739
3424
  } else {
740
- if (min3 > value2) min3 = value2;
741
- if (max3 < value2) max3 = value2;
3425
+ if (min4 > value2) min4 = value2;
3426
+ if (max4 < value2) max4 = value2;
742
3427
  }
743
3428
  }
744
3429
  }
@@ -746,16 +3431,16 @@ function extent(values, valueof) {
746
3431
  let index = -1;
747
3432
  for (let value2 of values) {
748
3433
  if ((value2 = valueof(value2, ++index, values)) != null) {
749
- if (min3 === void 0) {
750
- if (value2 >= value2) min3 = max3 = value2;
3434
+ if (min4 === void 0) {
3435
+ if (value2 >= value2) min4 = max4 = value2;
751
3436
  } else {
752
- if (min3 > value2) min3 = value2;
753
- if (max3 < value2) max3 = value2;
3437
+ if (min4 > value2) min4 = value2;
3438
+ if (max4 < value2) max4 = value2;
754
3439
  }
755
3440
  }
756
3441
  }
757
3442
  }
758
- return [min3, max3];
3443
+ return [min4, max4];
759
3444
  }
760
3445
 
761
3446
  // ../../node_modules/.bun/internmap@2.0.3/node_modules/internmap/src/index.js
@@ -851,43 +3536,43 @@ function tickStep(start, stop, count) {
851
3536
  }
852
3537
 
853
3538
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/max.js
854
- function max(values, valueof) {
855
- let max3;
3539
+ function max2(values, valueof) {
3540
+ let max4;
856
3541
  if (valueof === void 0) {
857
3542
  for (const value2 of values) {
858
- if (value2 != null && (max3 < value2 || max3 === void 0 && value2 >= value2)) {
859
- max3 = value2;
3543
+ if (value2 != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
3544
+ max4 = value2;
860
3545
  }
861
3546
  }
862
3547
  } else {
863
3548
  let index = -1;
864
3549
  for (let value2 of values) {
865
- if ((value2 = valueof(value2, ++index, values)) != null && (max3 < value2 || max3 === void 0 && value2 >= value2)) {
866
- max3 = value2;
3550
+ if ((value2 = valueof(value2, ++index, values)) != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
3551
+ max4 = value2;
867
3552
  }
868
3553
  }
869
3554
  }
870
- return max3;
3555
+ return max4;
871
3556
  }
872
3557
 
873
3558
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/min.js
874
- function min(values, valueof) {
875
- let min3;
3559
+ function min2(values, valueof) {
3560
+ let min4;
876
3561
  if (valueof === void 0) {
877
3562
  for (const value2 of values) {
878
- if (value2 != null && (min3 > value2 || min3 === void 0 && value2 >= value2)) {
879
- min3 = value2;
3563
+ if (value2 != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
3564
+ min4 = value2;
880
3565
  }
881
3566
  }
882
3567
  } else {
883
3568
  let index = -1;
884
3569
  for (let value2 of values) {
885
- if ((value2 = valueof(value2, ++index, values)) != null && (min3 > value2 || min3 === void 0 && value2 >= value2)) {
886
- min3 = value2;
3570
+ if ((value2 = valueof(value2, ++index, values)) != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
3571
+ min4 = value2;
887
3572
  }
888
3573
  }
889
3574
  }
890
- return min3;
3575
+ return min4;
891
3576
  }
892
3577
 
893
3578
  // ../../node_modules/.bun/d3-array@3.2.4/node_modules/d3-array/src/quantile.js
@@ -1037,7 +3722,7 @@ function pointish(scale) {
1037
3722
  };
1038
3723
  return scale;
1039
3724
  }
1040
- function point() {
3725
+ function point4() {
1041
3726
  return pointish(band.apply(null, arguments).paddingInner(1));
1042
3727
  }
1043
3728
 
@@ -1328,12 +4013,12 @@ function hslConvert(o) {
1328
4013
  if (!o) return new Hsl();
1329
4014
  if (o instanceof Hsl) return o;
1330
4015
  o = o.rgb();
1331
- var r = o.r / 255, g = o.g / 255, b = o.b / 255, min3 = Math.min(r, g, b), max3 = Math.max(r, g, b), h = NaN, s = max3 - min3, l = (max3 + min3) / 2;
4016
+ var r = o.r / 255, g = o.g / 255, b = o.b / 255, min4 = Math.min(r, g, b), max4 = Math.max(r, g, b), h = NaN, s = max4 - min4, l = (max4 + min4) / 2;
1332
4017
  if (s) {
1333
- if (r === max3) h = (g - b) / s + (g < b) * 6;
1334
- else if (g === max3) h = (b - r) / s + 2;
4018
+ if (r === max4) h = (g - b) / s + (g < b) * 6;
4019
+ else if (g === max4) h = (b - r) / s + 2;
1335
4020
  else h = (r - g) / s + 4;
1336
- s /= l < 0.5 ? max3 + min3 : 2 - max3 - min3;
4021
+ s /= l < 0.5 ? max4 + min4 : 2 - max4 - min4;
1337
4022
  h *= 60;
1338
4023
  } else {
1339
4024
  s = l > 0 && l < 1 ? 0 : h;
@@ -1394,7 +4079,7 @@ function basis(t12, v0, v1, v2, v3) {
1394
4079
  var t2 = t12 * t12, t3 = t2 * t12;
1395
4080
  return ((1 - 3 * t12 + 3 * t2 - t3) * v0 + (4 - 6 * t2 + 3 * t3) * v1 + (1 + 3 * t12 + 3 * t2 - 3 * t3) * v2 + t3 * v3) / 6;
1396
4081
  }
1397
- function basis_default(values) {
4082
+ function basis_default2(values) {
1398
4083
  var n = values.length - 1;
1399
4084
  return function(t) {
1400
4085
  var i = t <= 0 ? t = 0 : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n), v1 = values[i], v2 = values[i + 1], v0 = i > 0 ? values[i - 1] : 2 * v1 - v2, v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
@@ -1412,7 +4097,7 @@ function basisClosed_default(values) {
1412
4097
  }
1413
4098
 
1414
4099
  // ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/constant.js
1415
- var constant_default = (x) => () => x;
4100
+ var constant_default2 = (x2) => () => x2;
1416
4101
 
1417
4102
  // ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/color.js
1418
4103
  function linear(a, d) {
@@ -1420,24 +4105,24 @@ function linear(a, d) {
1420
4105
  return a + t * d;
1421
4106
  };
1422
4107
  }
1423
- function exponential(a, b, y) {
1424
- return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
1425
- return Math.pow(a + t * b, y);
4108
+ function exponential(a, b, y2) {
4109
+ return a = Math.pow(a, y2), b = Math.pow(b, y2) - a, y2 = 1 / y2, function(t) {
4110
+ return Math.pow(a + t * b, y2);
1426
4111
  };
1427
4112
  }
1428
- function gamma(y) {
1429
- return (y = +y) === 1 ? nogamma : function(a, b) {
1430
- return b - a ? exponential(a, b, y) : constant_default(isNaN(a) ? b : a);
4113
+ function gamma(y2) {
4114
+ return (y2 = +y2) === 1 ? nogamma : function(a, b) {
4115
+ return b - a ? exponential(a, b, y2) : constant_default2(isNaN(a) ? b : a);
1431
4116
  };
1432
4117
  }
1433
4118
  function nogamma(a, b) {
1434
4119
  var d = b - a;
1435
- return d ? linear(a, d) : constant_default(isNaN(a) ? b : a);
4120
+ return d ? linear(a, d) : constant_default2(isNaN(a) ? b : a);
1436
4121
  }
1437
4122
 
1438
4123
  // ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/rgb.js
1439
- var rgb_default = (function rgbGamma(y) {
1440
- var color2 = gamma(y);
4124
+ var rgb_default = (function rgbGamma(y2) {
4125
+ var color2 = gamma(y2);
1441
4126
  function rgb2(start, end) {
1442
4127
  var r = color2((start = rgb(start)).r, (end = rgb(end)).r), g = color2(start.g, end.g), b = color2(start.b, end.b), opacity = nogamma(start.opacity, end.opacity);
1443
4128
  return function(t) {
@@ -1472,7 +4157,7 @@ function rgbSpline(spline) {
1472
4157
  };
1473
4158
  };
1474
4159
  }
1475
- var rgbBasis = rgbSpline(basis_default);
4160
+ var rgbBasis = rgbSpline(basis_default2);
1476
4161
  var rgbBasisClosed = rgbSpline(basisClosed_default);
1477
4162
 
1478
4163
  // ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/numberArray.js
@@ -1484,17 +4169,17 @@ function numberArray_default(a, b) {
1484
4169
  return c;
1485
4170
  };
1486
4171
  }
1487
- function isNumberArray(x) {
1488
- return ArrayBuffer.isView(x) && !(x instanceof DataView);
4172
+ function isNumberArray(x2) {
4173
+ return ArrayBuffer.isView(x2) && !(x2 instanceof DataView);
1489
4174
  }
1490
4175
 
1491
4176
  // ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/array.js
1492
4177
  function genericArray(a, b) {
1493
- var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x = new Array(na), c = new Array(nb), i;
1494
- for (i = 0; i < na; ++i) x[i] = value_default(a[i], b[i]);
4178
+ var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x2 = new Array(na), c = new Array(nb), i;
4179
+ for (i = 0; i < na; ++i) x2[i] = value_default(a[i], b[i]);
1495
4180
  for (; i < nb; ++i) c[i] = b[i];
1496
4181
  return function(t) {
1497
- for (i = 0; i < na; ++i) c[i] = x[i](t);
4182
+ for (i = 0; i < na; ++i) c[i] = x2[i](t);
1498
4183
  return c;
1499
4184
  };
1500
4185
  }
@@ -1577,7 +4262,7 @@ function string_default(a, b) {
1577
4262
  // ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/value.js
1578
4263
  function value_default(a, b) {
1579
4264
  var t = typeof b, c;
1580
- return b == null || t === "boolean" ? constant_default(b) : (t === "number" ? number_default : t === "string" ? (c = color(b)) ? (b = c, rgb_default) : string_default : b instanceof color ? rgb_default : b instanceof Date ? date_default : isNumberArray(b) ? numberArray_default : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object_default : number_default)(a, b);
4265
+ return b == null || t === "boolean" ? constant_default2(b) : (t === "number" ? number_default : t === "string" ? (c = color(b)) ? (b = c, rgb_default) : string_default : b instanceof color ? rgb_default : b instanceof Date ? date_default : isNumberArray(b) ? numberArray_default : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object_default : number_default)(a, b);
1581
4266
  }
1582
4267
 
1583
4268
  // ../../node_modules/.bun/d3-interpolate@3.0.1/node_modules/d3-interpolate/src/round.js
@@ -1588,40 +4273,40 @@ function round_default(a, b) {
1588
4273
  }
1589
4274
 
1590
4275
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/constant.js
1591
- function constants(x) {
4276
+ function constants(x2) {
1592
4277
  return function() {
1593
- return x;
4278
+ return x2;
1594
4279
  };
1595
4280
  }
1596
4281
 
1597
4282
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/number.js
1598
- function number2(x) {
1599
- return +x;
4283
+ function number2(x2) {
4284
+ return +x2;
1600
4285
  }
1601
4286
 
1602
4287
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/continuous.js
1603
4288
  var unit = [0, 1];
1604
- function identity(x) {
1605
- return x;
4289
+ function identity(x2) {
4290
+ return x2;
1606
4291
  }
1607
4292
  function normalize(a, b) {
1608
- return (b -= a = +a) ? function(x) {
1609
- return (x - a) / b;
4293
+ return (b -= a = +a) ? function(x2) {
4294
+ return (x2 - a) / b;
1610
4295
  } : constants(isNaN(b) ? NaN : 0.5);
1611
4296
  }
1612
4297
  function clamper(a, b) {
1613
4298
  var t;
1614
4299
  if (a > b) t = a, a = b, b = t;
1615
- return function(x) {
1616
- return Math.max(a, Math.min(b, x));
4300
+ return function(x2) {
4301
+ return Math.max(a, Math.min(b, x2));
1617
4302
  };
1618
4303
  }
1619
4304
  function bimap(domain, range2, interpolate) {
1620
4305
  var d0 = domain[0], d1 = domain[1], r0 = range2[0], r1 = range2[1];
1621
4306
  if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);
1622
4307
  else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
1623
- return function(x) {
1624
- return r0(d0(x));
4308
+ return function(x2) {
4309
+ return r0(d0(x2));
1625
4310
  };
1626
4311
  }
1627
4312
  function polymap(domain, range2, interpolate) {
@@ -1634,9 +4319,9 @@ function polymap(domain, range2, interpolate) {
1634
4319
  d[i] = normalize(domain[i], domain[i + 1]);
1635
4320
  r[i] = interpolate(range2[i], range2[i + 1]);
1636
4321
  }
1637
- return function(x) {
1638
- var i2 = bisect_default(domain, x, 1, j) - 1;
1639
- return r[i2](d[i2](x));
4322
+ return function(x2) {
4323
+ var i2 = bisect_default(domain, x2, 1, j) - 1;
4324
+ return r[i2](d[i2](x2));
1640
4325
  };
1641
4326
  }
1642
4327
  function copy(source, target) {
@@ -1651,11 +4336,11 @@ function transformer() {
1651
4336
  output = input = null;
1652
4337
  return scale;
1653
4338
  }
1654
- function scale(x) {
1655
- return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range2, interpolate)))(transform(clamp(x)));
4339
+ function scale(x2) {
4340
+ return x2 == null || isNaN(x2 = +x2) ? unknown : (output || (output = piecewise(domain.map(transform), range2, interpolate)))(transform(clamp(x2)));
1656
4341
  }
1657
- scale.invert = function(y) {
1658
- return clamp(untransform((input || (input = piecewise(range2, domain.map(transform), number_default)))(y)));
4342
+ scale.invert = function(y2) {
4343
+ return clamp(untransform((input || (input = piecewise(range2, domain.map(transform), number_default)))(y2)));
1659
4344
  };
1660
4345
  scale.domain = function(_) {
1661
4346
  return arguments.length ? (domain = Array.from(_, number2), rescale()) : domain.slice();
@@ -1685,21 +4370,21 @@ function continuous() {
1685
4370
  }
1686
4371
 
1687
4372
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatDecimal.js
1688
- function formatDecimal_default(x) {
1689
- return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
4373
+ function formatDecimal_default(x2) {
4374
+ return Math.abs(x2 = Math.round(x2)) >= 1e21 ? x2.toLocaleString("en").replace(/,/g, "") : x2.toString(10);
1690
4375
  }
1691
- function formatDecimalParts(x, p) {
1692
- if (!isFinite(x) || x === 0) return null;
1693
- var i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e"), coefficient = x.slice(0, i);
4376
+ function formatDecimalParts(x2, p) {
4377
+ if (!isFinite(x2) || x2 === 0) return null;
4378
+ var i = (x2 = p ? x2.toExponential(p - 1) : x2.toExponential()).indexOf("e"), coefficient = x2.slice(0, i);
1694
4379
  return [
1695
4380
  coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
1696
- +x.slice(i + 1)
4381
+ +x2.slice(i + 1)
1697
4382
  ];
1698
4383
  }
1699
4384
 
1700
4385
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/exponent.js
1701
- function exponent_default(x) {
1702
- return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
4386
+ function exponent_default(x2) {
4387
+ return x2 = formatDecimalParts(Math.abs(x2)), x2 ? x2[1] : NaN;
1703
4388
  }
1704
4389
 
1705
4390
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatGroup.js
@@ -1782,51 +4467,51 @@ function formatTrim_default(s) {
1782
4467
 
1783
4468
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatPrefixAuto.js
1784
4469
  var prefixExponent;
1785
- function formatPrefixAuto_default(x, p) {
1786
- var d = formatDecimalParts(x, p);
1787
- if (!d) return prefixExponent = void 0, x.toPrecision(p);
4470
+ function formatPrefixAuto_default(x2, p) {
4471
+ var d = formatDecimalParts(x2, p);
4472
+ if (!d) return prefixExponent = void 0, x2.toPrecision(p);
1788
4473
  var coefficient = d[0], exponent = d[1], i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1, n = coefficient.length;
1789
- return i === n ? coefficient : i > n ? coefficient + new Array(i - n + 1).join("0") : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i) : "0." + new Array(1 - i).join("0") + formatDecimalParts(x, Math.max(0, p + i - 1))[0];
4474
+ return i === n ? coefficient : i > n ? coefficient + new Array(i - n + 1).join("0") : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i) : "0." + new Array(1 - i).join("0") + formatDecimalParts(x2, Math.max(0, p + i - 1))[0];
1790
4475
  }
1791
4476
 
1792
4477
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatRounded.js
1793
- function formatRounded_default(x, p) {
1794
- var d = formatDecimalParts(x, p);
1795
- if (!d) return x + "";
4478
+ function formatRounded_default(x2, p) {
4479
+ var d = formatDecimalParts(x2, p);
4480
+ if (!d) return x2 + "";
1796
4481
  var coefficient = d[0], exponent = d[1];
1797
4482
  return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1) : coefficient + new Array(exponent - coefficient.length + 2).join("0");
1798
4483
  }
1799
4484
 
1800
4485
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatTypes.js
1801
4486
  var formatTypes_default = {
1802
- "%": (x, p) => (x * 100).toFixed(p),
1803
- "b": (x) => Math.round(x).toString(2),
1804
- "c": (x) => x + "",
4487
+ "%": (x2, p) => (x2 * 100).toFixed(p),
4488
+ "b": (x2) => Math.round(x2).toString(2),
4489
+ "c": (x2) => x2 + "",
1805
4490
  "d": formatDecimal_default,
1806
- "e": (x, p) => x.toExponential(p),
1807
- "f": (x, p) => x.toFixed(p),
1808
- "g": (x, p) => x.toPrecision(p),
1809
- "o": (x) => Math.round(x).toString(8),
1810
- "p": (x, p) => formatRounded_default(x * 100, p),
4491
+ "e": (x2, p) => x2.toExponential(p),
4492
+ "f": (x2, p) => x2.toFixed(p),
4493
+ "g": (x2, p) => x2.toPrecision(p),
4494
+ "o": (x2) => Math.round(x2).toString(8),
4495
+ "p": (x2, p) => formatRounded_default(x2 * 100, p),
1811
4496
  "r": formatRounded_default,
1812
4497
  "s": formatPrefixAuto_default,
1813
- "X": (x) => Math.round(x).toString(16).toUpperCase(),
1814
- "x": (x) => Math.round(x).toString(16)
4498
+ "X": (x2) => Math.round(x2).toString(16).toUpperCase(),
4499
+ "x": (x2) => Math.round(x2).toString(16)
1815
4500
  };
1816
4501
 
1817
4502
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/identity.js
1818
- function identity_default(x) {
1819
- return x;
4503
+ function identity_default2(x2) {
4504
+ return x2;
1820
4505
  }
1821
4506
 
1822
4507
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/locale.js
1823
4508
  var map = Array.prototype.map;
1824
4509
  var prefixes = ["y", "z", "a", "f", "p", "n", "\xB5", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
1825
4510
  function locale_default(locale3) {
1826
- var group = locale3.grouping === void 0 || locale3.thousands === void 0 ? identity_default : formatGroup_default(map.call(locale3.grouping, Number), locale3.thousands + ""), currencyPrefix = locale3.currency === void 0 ? "" : locale3.currency[0] + "", currencySuffix = locale3.currency === void 0 ? "" : locale3.currency[1] + "", decimal = locale3.decimal === void 0 ? "." : locale3.decimal + "", numerals = locale3.numerals === void 0 ? identity_default : formatNumerals_default(map.call(locale3.numerals, String)), percent = locale3.percent === void 0 ? "%" : locale3.percent + "", minus = locale3.minus === void 0 ? "\u2212" : locale3.minus + "", nan = locale3.nan === void 0 ? "NaN" : locale3.nan + "";
4511
+ var group = locale3.grouping === void 0 || locale3.thousands === void 0 ? identity_default2 : formatGroup_default(map.call(locale3.grouping, Number), locale3.thousands + ""), currencyPrefix = locale3.currency === void 0 ? "" : locale3.currency[0] + "", currencySuffix = locale3.currency === void 0 ? "" : locale3.currency[1] + "", decimal = locale3.decimal === void 0 ? "." : locale3.decimal + "", numerals = locale3.numerals === void 0 ? identity_default2 : formatNumerals_default(map.call(locale3.numerals, String)), percent = locale3.percent === void 0 ? "%" : locale3.percent + "", minus = locale3.minus === void 0 ? "\u2212" : locale3.minus + "", nan = locale3.nan === void 0 ? "NaN" : locale3.nan + "";
1827
4512
  function newFormat(specifier, options) {
1828
4513
  specifier = formatSpecifier(specifier);
1829
- var fill = specifier.fill, align = specifier.align, sign = specifier.sign, symbol = specifier.symbol, zero3 = specifier.zero, width = specifier.width, comma = specifier.comma, precision = specifier.precision, trim = specifier.trim, type = specifier.type;
4514
+ var fill = specifier.fill, align = specifier.align, sign2 = specifier.sign, symbol = specifier.symbol, zero3 = specifier.zero, width = specifier.width, comma = specifier.comma, precision = specifier.precision, trim = specifier.trim, type = specifier.type;
1830
4515
  if (type === "n") comma = true, type = "g";
1831
4516
  else if (!formatTypes_default[type]) precision === void 0 && (precision = 12), trim = true, type = "g";
1832
4517
  if (zero3 || fill === "0" && align === "=") zero3 = true, fill = "0", align = "=";
@@ -1843,9 +4528,9 @@ function locale_default(locale3) {
1843
4528
  var valueNegative = value2 < 0 || 1 / value2 < 0;
1844
4529
  value2 = isNaN(value2) ? nan : formatType(Math.abs(value2), precision);
1845
4530
  if (trim) value2 = formatTrim_default(value2);
1846
- if (valueNegative && +value2 === 0 && sign !== "+") valueNegative = false;
1847
- valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
1848
- valueSuffix = (type === "s" && !isNaN(value2) && prefixExponent !== void 0 ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : "");
4531
+ if (valueNegative && +value2 === 0 && sign2 !== "+") valueNegative = false;
4532
+ valuePrefix = (valueNegative ? sign2 === "(" ? sign2 : minus : sign2 === "-" || sign2 === "(" ? "" : sign2) + valuePrefix;
4533
+ valueSuffix = (type === "s" && !isNaN(value2) && prefixExponent !== void 0 ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign2 === "(" ? ")" : "");
1849
4534
  if (maybeSuffix) {
1850
4535
  i = -1, n = value2.length;
1851
4536
  while (++i < n) {
@@ -1920,9 +4605,9 @@ function precisionPrefix_default(step, value2) {
1920
4605
  }
1921
4606
 
1922
4607
  // ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/precisionRound.js
1923
- function precisionRound_default(step, max3) {
1924
- step = Math.abs(step), max3 = Math.abs(max3) - step;
1925
- return Math.max(0, exponent_default(max3) - exponent_default(step)) + 1;
4608
+ function precisionRound_default(step, max4) {
4609
+ step = Math.abs(step), max4 = Math.abs(max4) - step;
4610
+ return Math.max(0, exponent_default(max4) - exponent_default(step)) + 1;
1926
4611
  }
1927
4612
 
1928
4613
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/tickFormat.js
@@ -2021,29 +4706,29 @@ function nice(domain, interval) {
2021
4706
  }
2022
4707
 
2023
4708
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/log.js
2024
- function transformLog(x) {
2025
- return Math.log(x);
4709
+ function transformLog(x2) {
4710
+ return Math.log(x2);
2026
4711
  }
2027
- function transformExp(x) {
2028
- return Math.exp(x);
4712
+ function transformExp(x2) {
4713
+ return Math.exp(x2);
2029
4714
  }
2030
- function transformLogn(x) {
2031
- return -Math.log(-x);
4715
+ function transformLogn(x2) {
4716
+ return -Math.log(-x2);
2032
4717
  }
2033
- function transformExpn(x) {
2034
- return -Math.exp(-x);
4718
+ function transformExpn(x2) {
4719
+ return -Math.exp(-x2);
2035
4720
  }
2036
- function pow10(x) {
2037
- return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
4721
+ function pow10(x2) {
4722
+ return isFinite(x2) ? +("1e" + x2) : x2 < 0 ? 0 : x2;
2038
4723
  }
2039
4724
  function powp(base) {
2040
- return base === 10 ? pow10 : base === Math.E ? Math.exp : (x) => Math.pow(base, x);
4725
+ return base === 10 ? pow10 : base === Math.E ? Math.exp : (x2) => Math.pow(base, x2);
2041
4726
  }
2042
4727
  function logp(base) {
2043
- return base === Math.E ? Math.log : base === 10 && Math.log10 || base === 2 && Math.log2 || (base = Math.log(base), (x) => Math.log(x) / base);
4728
+ return base === Math.E ? Math.log : base === 10 && Math.log10 || base === 2 && Math.log2 || (base = Math.log(base), (x2) => Math.log(x2) / base);
2044
4729
  }
2045
4730
  function reflect(f) {
2046
- return (x, k) => -f(-x, k);
4731
+ return (x2, k) => -f(-x2, k);
2047
4732
  }
2048
4733
  function loggish(transform) {
2049
4734
  const scale = transform(transformLog, transformExp);
@@ -2120,8 +4805,8 @@ function loggish(transform) {
2120
4805
  };
2121
4806
  scale.nice = () => {
2122
4807
  return domain(nice(domain(), {
2123
- floor: (x) => pows(Math.floor(logs(x))),
2124
- ceil: (x) => pows(Math.ceil(logs(x)))
4808
+ floor: (x2) => pows(Math.floor(logs(x2))),
4809
+ ceil: (x2) => pows(Math.ceil(logs(x2)))
2125
4810
  }));
2126
4811
  };
2127
4812
  return scale;
@@ -2135,13 +4820,13 @@ function log() {
2135
4820
 
2136
4821
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/symlog.js
2137
4822
  function transformSymlog(c) {
2138
- return function(x) {
2139
- return Math.sign(x) * Math.log1p(Math.abs(x / c));
4823
+ return function(x2) {
4824
+ return Math.sign(x2) * Math.log1p(Math.abs(x2 / c));
2140
4825
  };
2141
4826
  }
2142
4827
  function transformSymexp(c) {
2143
- return function(x) {
2144
- return Math.sign(x) * Math.expm1(Math.abs(x)) * c;
4828
+ return function(x2) {
4829
+ return Math.sign(x2) * Math.expm1(Math.abs(x2)) * c;
2145
4830
  };
2146
4831
  }
2147
4832
  function symlogish(transform) {
@@ -2161,15 +4846,15 @@ function symlog() {
2161
4846
 
2162
4847
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/pow.js
2163
4848
  function transformPow(exponent) {
2164
- return function(x) {
2165
- return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
4849
+ return function(x2) {
4850
+ return x2 < 0 ? -Math.pow(-x2, exponent) : Math.pow(x2, exponent);
2166
4851
  };
2167
4852
  }
2168
- function transformSqrt(x) {
2169
- return x < 0 ? -Math.sqrt(-x) : Math.sqrt(x);
4853
+ function transformSqrt(x2) {
4854
+ return x2 < 0 ? -Math.sqrt(-x2) : Math.sqrt(x2);
2170
4855
  }
2171
- function transformSquare(x) {
2172
- return x < 0 ? -x * x : x * x;
4856
+ function transformSquare(x2) {
4857
+ return x2 < 0 ? -x2 * x2 : x2 * x2;
2173
4858
  }
2174
4859
  function powish(transform) {
2175
4860
  var scale = transform(identity, identity), exponent = 1;
@@ -2189,7 +4874,7 @@ function pow() {
2189
4874
  initRange.apply(scale, arguments);
2190
4875
  return scale;
2191
4876
  }
2192
- function sqrt() {
4877
+ function sqrt2() {
2193
4878
  return pow.apply(null, arguments).exponent(0.5);
2194
4879
  }
2195
4880
 
@@ -2202,11 +4887,11 @@ function quantile2() {
2202
4887
  while (++i < n) thresholds[i - 1] = quantileSorted(domain, i / n);
2203
4888
  return scale;
2204
4889
  }
2205
- function scale(x) {
2206
- return x == null || isNaN(x = +x) ? unknown : range2[bisect_default(thresholds, x)];
4890
+ function scale(x2) {
4891
+ return x2 == null || isNaN(x2 = +x2) ? unknown : range2[bisect_default(thresholds, x2)];
2207
4892
  }
2208
- scale.invertExtent = function(y) {
2209
- var i = range2.indexOf(y);
4893
+ scale.invertExtent = function(y2) {
4894
+ var i = range2.indexOf(y2);
2210
4895
  return i < 0 ? [NaN, NaN] : [
2211
4896
  i > 0 ? thresholds[i - 1] : domain[0],
2212
4897
  i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
@@ -2237,8 +4922,8 @@ function quantile2() {
2237
4922
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/quantize.js
2238
4923
  function quantize() {
2239
4924
  var x0 = 0, x1 = 1, n = 1, domain = [0.5], range2 = [0, 1], unknown;
2240
- function scale(x) {
2241
- return x != null && x <= x ? range2[bisect_default(domain, x, 0, n)] : unknown;
4925
+ function scale(x2) {
4926
+ return x2 != null && x2 <= x2 ? range2[bisect_default(domain, x2, 0, n)] : unknown;
2242
4927
  }
2243
4928
  function rescale() {
2244
4929
  var i = -1;
@@ -2252,8 +4937,8 @@ function quantize() {
2252
4937
  scale.range = function(_) {
2253
4938
  return arguments.length ? (n = (range2 = Array.from(_)).length - 1, rescale()) : range2.slice();
2254
4939
  };
2255
- scale.invertExtent = function(y) {
2256
- var i = range2.indexOf(y);
4940
+ scale.invertExtent = function(y2) {
4941
+ var i = range2.indexOf(y2);
2257
4942
  return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
2258
4943
  };
2259
4944
  scale.unknown = function(_) {
@@ -2271,8 +4956,8 @@ function quantize() {
2271
4956
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/threshold.js
2272
4957
  function threshold() {
2273
4958
  var domain = [0.5], range2 = [0, 1], unknown, n = 1;
2274
- function scale(x) {
2275
- return x != null && x <= x ? range2[bisect_default(domain, x, 0, n)] : unknown;
4959
+ function scale(x2) {
4960
+ return x2 != null && x2 <= x2 ? range2[bisect_default(domain, x2, 0, n)] : unknown;
2276
4961
  }
2277
4962
  scale.domain = function(_) {
2278
4963
  return arguments.length ? (domain = Array.from(_), n = Math.min(domain.length, range2.length - 1), scale) : domain.slice();
@@ -2280,8 +4965,8 @@ function threshold() {
2280
4965
  scale.range = function(_) {
2281
4966
  return arguments.length ? (range2 = Array.from(_), n = Math.min(domain.length, range2.length - 1), scale) : range2.slice();
2282
4967
  };
2283
- scale.invertExtent = function(y) {
2284
- var i = range2.indexOf(y);
4968
+ scale.invertExtent = function(y2) {
4969
+ var i = range2.indexOf(y2);
2285
4970
  return [domain[i - 1], domain[i]];
2286
4971
  };
2287
4972
  scale.unknown = function(_) {
@@ -2644,8 +5329,8 @@ function utcDate(d) {
2644
5329
  }
2645
5330
  return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
2646
5331
  }
2647
- function newDate(y, m, d) {
2648
- return { y, m, d, H: 0, M: 0, S: 0, L: 0 };
5332
+ function newDate(y2, m, d) {
5333
+ return { y: y2, m, d, H: 0, M: 0, S: 0, L: 0 };
2649
5334
  }
2650
5335
  function formatLocale(locale3) {
2651
5336
  var locale_dateTime = locale3.dateTime, locale_date = locale3.date, locale_time = locale3.time, locale_periods = locale3.periods, locale_weekdays = locale3.days, locale_shortWeekdays = locale3.shortDays, locale_months = locale3.months, locale_shortMonths = locale3.shortMonths;
@@ -2933,8 +5618,8 @@ var numberRe = /^\s*\d+/;
2933
5618
  var percentRe = /^%/;
2934
5619
  var requoteRe = /[\\^$*+?|[\]().{}]/g;
2935
5620
  function pad(value2, fill, width) {
2936
- var sign = value2 < 0 ? "-" : "", string = (sign ? -value2 : value2) + "", length = string.length;
2937
- return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
5621
+ var sign2 = value2 < 0 ? "-" : "", string = (sign2 ? -value2 : value2) + "", length = string.length;
5622
+ return sign2 + (length < width ? new Array(width - length + 1).join(fill) + string : string);
2938
5623
  }
2939
5624
  function requote(s) {
2940
5625
  return s.replace(requoteRe, "\\$&");
@@ -3206,8 +5891,8 @@ function calendar(ticks2, tickInterval, year, month, week, day, hour, minute, se
3206
5891
  function tickFormat2(date2) {
3207
5892
  return (second2(date2) < date2 ? formatMillisecond : minute(date2) < date2 ? formatSecond : hour(date2) < date2 ? formatMinute : day(date2) < date2 ? formatHour : month(date2) < date2 ? week(date2) < date2 ? formatDay : formatWeek : year(date2) < date2 ? formatMonth : formatYear2)(date2);
3208
5893
  }
3209
- scale.invert = function(y) {
3210
- return new Date(invert(y));
5894
+ scale.invert = function(y2) {
5895
+ return new Date(invert(y2));
3211
5896
  };
3212
5897
  scale.domain = function(_) {
3213
5898
  return arguments.length ? domain(Array.from(_, number3)) : domain().map(date);
@@ -3241,8 +5926,8 @@ function utcTime() {
3241
5926
  // ../../node_modules/.bun/d3-scale@4.0.2/node_modules/d3-scale/src/sequential.js
3242
5927
  function transformer2() {
3243
5928
  var x0 = 0, x1 = 1, t02, t12, k10, transform, interpolator = identity, clamp = false, unknown;
3244
- function scale(x) {
3245
- return x == null || isNaN(x = +x) ? unknown : interpolator(k10 === 0 ? 0.5 : (x = (transform(x) - t02) * k10, clamp ? Math.max(0, Math.min(1, x)) : x));
5929
+ function scale(x2) {
5930
+ return x2 == null || isNaN(x2 = +x2) ? unknown : interpolator(k10 === 0 ? 0.5 : (x2 = (transform(x2) - t02) * k10, clamp ? Math.max(0, Math.min(1, x2)) : x2));
3246
5931
  }
3247
5932
  scale.domain = function(_) {
3248
5933
  return arguments.length ? ([x0, x1] = _, t02 = transform(x0 = +x0), t12 = transform(x1 = +x1), k10 = t02 === t12 ? 0 : 1 / (t12 - t02), scale) : [x0, x1];
@@ -3280,6 +5965,293 @@ function sequential() {
3280
5965
  return initInterpolator.apply(scale, arguments);
3281
5966
  }
3282
5967
 
5968
+ // src/charts/scatter/compute.ts
5969
+ var DEFAULT_POINT_RADIUS2 = 5;
5970
+ var MIN_BUBBLE_RADIUS = 3;
5971
+ var MAX_BUBBLE_RADIUS = 30;
5972
+ function resolvePosition2(value2, channelType, scale) {
5973
+ switch (channelType) {
5974
+ case "nominal":
5975
+ case "ordinal": {
5976
+ const s = String(value2);
5977
+ if ("bandwidth" in scale && typeof scale.bandwidth === "function") {
5978
+ const bw = scale.bandwidth();
5979
+ const pos = scale(s);
5980
+ if (pos === void 0) return void 0;
5981
+ return bw > 0 ? pos + bw / 2 : pos;
5982
+ }
5983
+ return scale(s);
5984
+ }
5985
+ case "temporal": {
5986
+ const px = scale(new Date(value2));
5987
+ return Number.isNaN(px) ? void 0 : px;
5988
+ }
5989
+ default: {
5990
+ const num = Number(value2);
5991
+ if (!Number.isFinite(num)) return void 0;
5992
+ return scale(num);
5993
+ }
5994
+ }
5995
+ }
5996
+ function computeScatterMarks(spec, scales, _chartArea, _strategy) {
5997
+ const encoding = spec.encoding;
5998
+ const xChannel = encoding.x;
5999
+ const yChannel = encoding.y;
6000
+ if (!xChannel || !yChannel || !scales.x || !scales.y) {
6001
+ return [];
6002
+ }
6003
+ const xScale = scales.x.scale;
6004
+ const yScale = scales.y.scale;
6005
+ const xType = xChannel.type;
6006
+ const yType = yChannel.type;
6007
+ const colorEnc = encoding.color && "field" in encoding.color ? encoding.color : void 0;
6008
+ const isSequentialColor = colorEnc?.type === "quantitative";
6009
+ const colorField = colorEnc?.field;
6010
+ const sizeField = encoding.size && "field" in encoding.size ? encoding.size.field : void 0;
6011
+ let sizeScale;
6012
+ if (sizeField) {
6013
+ const sizeValues = spec.data.map((d) => Number(d[sizeField])).filter((v) => Number.isFinite(v));
6014
+ const sizeMin = min2(sizeValues) ?? 0;
6015
+ const sizeMax = max2(sizeValues) ?? 1;
6016
+ sizeScale = sqrt2().domain([sizeMin, sizeMax]).range([MIN_BUBBLE_RADIUS, MAX_BUBBLE_RADIUS]);
6017
+ }
6018
+ const marks = [];
6019
+ for (const row of spec.data) {
6020
+ const rawX = row[xChannel.field];
6021
+ const rawY = row[yChannel.field];
6022
+ const cx = resolvePosition2(rawX, xType, xScale);
6023
+ const cy = resolvePosition2(rawY, yType, yScale);
6024
+ if (cx === void 0 || cy === void 0) continue;
6025
+ const category = colorField && !isSequentialColor ? String(row[colorField] ?? "") : void 0;
6026
+ let color2;
6027
+ if (isSequentialColor && colorField) {
6028
+ const val = Number(row[colorField]);
6029
+ color2 = Number.isFinite(val) ? getSequentialColor(scales, val) : getColor(scales, "__default__");
6030
+ } else {
6031
+ color2 = getColor(scales, category ?? "__default__");
6032
+ }
6033
+ let radius = DEFAULT_POINT_RADIUS2;
6034
+ if (sizeScale && sizeField) {
6035
+ const sizeVal = Number(row[sizeField]);
6036
+ if (Number.isFinite(sizeVal)) {
6037
+ radius = sizeScale(sizeVal);
6038
+ }
6039
+ }
6040
+ const labelParts = [`${xChannel.field}=${rawX}`, `${yChannel.field}=${rawY}`];
6041
+ if (category) labelParts.push(`${colorField}=${category}`);
6042
+ if (sizeField && row[sizeField] != null) {
6043
+ labelParts.push(`${sizeField}=${row[sizeField]}`);
6044
+ }
6045
+ const aria = {
6046
+ label: `Data point: ${labelParts.join(", ")}`
6047
+ };
6048
+ marks.push({
6049
+ type: "point",
6050
+ cx,
6051
+ cy,
6052
+ r: radius,
6053
+ fill: color2,
6054
+ stroke: "#ffffff",
6055
+ strokeWidth: 1,
6056
+ fillOpacity: 0.7,
6057
+ data: row,
6058
+ aria
6059
+ });
6060
+ }
6061
+ return marks;
6062
+ }
6063
+
6064
+ // src/charts/scatter/trendline.ts
6065
+ var TRENDLINE_COLOR = "#666666";
6066
+ var TRENDLINE_STROKE_WIDTH = 1.5;
6067
+ var TRENDLINE_DASH = "6 4";
6068
+ function linearRegression(points) {
6069
+ const n = points.length;
6070
+ if (n < 2) return null;
6071
+ let sumX = 0;
6072
+ let sumY = 0;
6073
+ let sumXY = 0;
6074
+ let sumXX = 0;
6075
+ for (const p of points) {
6076
+ sumX += p.x;
6077
+ sumY += p.y;
6078
+ sumXY += p.x * p.y;
6079
+ sumXX += p.x * p.x;
6080
+ }
6081
+ const denominator = n * sumXX - sumX * sumX;
6082
+ if (denominator === 0) return null;
6083
+ const slope = (n * sumXY - sumX * sumY) / denominator;
6084
+ const intercept = (sumY - slope * sumX) / n;
6085
+ return { slope, intercept };
6086
+ }
6087
+ function computeTrendLine(marks) {
6088
+ if (marks.length < 2) return null;
6089
+ const points = marks.map((m) => ({ x: m.cx, y: m.cy }));
6090
+ const result = linearRegression(points);
6091
+ if (!result) return null;
6092
+ const { slope, intercept } = result;
6093
+ let minX = Infinity;
6094
+ let maxX = -Infinity;
6095
+ for (const m of marks) {
6096
+ if (m.cx < minX) minX = m.cx;
6097
+ if (m.cx > maxX) maxX = m.cx;
6098
+ }
6099
+ const y1 = slope * minX + intercept;
6100
+ const y2 = slope * maxX + intercept;
6101
+ const aria = {
6102
+ label: `Trend line: linear regression`
6103
+ };
6104
+ return {
6105
+ type: "line",
6106
+ points: [
6107
+ { x: minX, y: y1 },
6108
+ { x: maxX, y: y2 }
6109
+ ],
6110
+ stroke: TRENDLINE_COLOR,
6111
+ strokeWidth: TRENDLINE_STROKE_WIDTH,
6112
+ strokeDasharray: TRENDLINE_DASH,
6113
+ data: [],
6114
+ aria
6115
+ };
6116
+ }
6117
+
6118
+ // src/charts/scatter/index.ts
6119
+ var scatterRenderer = (spec, scales, chartArea, strategy, _theme) => {
6120
+ const pointMarks = computeScatterMarks(spec, scales, chartArea, strategy);
6121
+ const marks = [...pointMarks];
6122
+ const trendLine = computeTrendLine(pointMarks);
6123
+ if (trendLine) {
6124
+ marks.unshift(trendLine);
6125
+ }
6126
+ return marks;
6127
+ };
6128
+
6129
+ // src/charts/text/index.ts
6130
+ import { getRepresentativeColor as getRepresentativeColor8 } from "@opendata-ai/openchart-core";
6131
+ function computeTextMarks(spec, scales) {
6132
+ const encoding = spec.encoding;
6133
+ const xChannel = encoding.x;
6134
+ const yChannel = encoding.y;
6135
+ const textChannel = encoding.text;
6136
+ if (!textChannel || !("field" in textChannel)) return [];
6137
+ const marks = [];
6138
+ const colorEncoding = encoding.color && "field" in encoding.color ? encoding.color : void 0;
6139
+ const colorField = colorEncoding?.field;
6140
+ const sizeEncoding = encoding.size && "field" in encoding.size ? encoding.size : void 0;
6141
+ for (const row of spec.data) {
6142
+ let x2 = 0;
6143
+ if (xChannel && scales.x) {
6144
+ const xVal = scaleValue(scales.x.scale, scales.x.type, row[xChannel.field]);
6145
+ if (xVal == null) continue;
6146
+ x2 = xVal;
6147
+ }
6148
+ let y2 = 0;
6149
+ if (yChannel && scales.y) {
6150
+ const yVal = scaleValue(scales.y.scale, scales.y.type, row[yChannel.field]);
6151
+ if (yVal == null) continue;
6152
+ y2 = yVal;
6153
+ }
6154
+ const text = String(row[textChannel.field] ?? "");
6155
+ if (!text) continue;
6156
+ const color2 = getRepresentativeColor8(
6157
+ colorField ? getColor(scales, String(row[colorField] ?? "__default__")) : getColor(scales, "__default__")
6158
+ );
6159
+ const fontSize = sizeEncoding ? Math.max(8, Math.min(48, Number(row[sizeEncoding.field]) || 12)) : 12;
6160
+ const aria = {
6161
+ label: text
6162
+ };
6163
+ marks.push({
6164
+ type: "textMark",
6165
+ x: x2,
6166
+ y: y2,
6167
+ text,
6168
+ fill: color2,
6169
+ fontSize,
6170
+ textAnchor: "middle",
6171
+ angle: encoding.angle && "field" in encoding.angle ? Number(row[encoding.angle.field]) || 0 : void 0,
6172
+ data: row,
6173
+ aria
6174
+ });
6175
+ }
6176
+ return marks;
6177
+ }
6178
+ var textRenderer = (spec, scales, _chartArea, _strategy, _theme) => {
6179
+ return computeTextMarks(spec, scales);
6180
+ };
6181
+
6182
+ // src/charts/tick/index.ts
6183
+ import { getRepresentativeColor as getRepresentativeColor9 } from "@opendata-ai/openchart-core";
6184
+ var DEFAULT_TICK_LENGTH = 18;
6185
+ function computeTickMarks(spec, scales, _chartArea) {
6186
+ const encoding = spec.encoding;
6187
+ const xChannel = encoding.x;
6188
+ const yChannel = encoding.y;
6189
+ if (!xChannel || !yChannel || !scales.x || !scales.y) return [];
6190
+ const colorEncoding = encoding.color && "field" in encoding.color ? encoding.color : void 0;
6191
+ const colorField = colorEncoding?.field;
6192
+ const marks = [];
6193
+ const isHorizontal = xChannel.type === "quantitative" && yChannel.type !== "quantitative";
6194
+ const orient = isHorizontal ? "horizontal" : "vertical";
6195
+ for (const row of spec.data) {
6196
+ const xVal = scaleValue(scales.x.scale, scales.x.type, row[xChannel.field]);
6197
+ const yVal = scaleValue(scales.y.scale, scales.y.type, row[yChannel.field]);
6198
+ if (xVal == null || yVal == null) continue;
6199
+ const color2 = getRepresentativeColor9(
6200
+ colorField ? getColor(scales, String(row[colorField] ?? "__default__")) : getColor(scales, "__default__")
6201
+ );
6202
+ const aria = {
6203
+ label: `${row[xChannel.field]}, ${row[yChannel.field]}`
6204
+ };
6205
+ marks.push({
6206
+ type: "tick",
6207
+ x: xVal,
6208
+ y: yVal,
6209
+ length: DEFAULT_TICK_LENGTH,
6210
+ orient,
6211
+ stroke: color2,
6212
+ strokeWidth: 1,
6213
+ opacity: encoding.opacity && "field" in encoding.opacity ? Math.max(0, Math.min(1, Number(row[encoding.opacity.field]) || 1)) : void 0,
6214
+ data: row,
6215
+ aria
6216
+ });
6217
+ }
6218
+ return marks;
6219
+ }
6220
+ var tickRenderer = (spec, scales, chartArea, _strategy, _theme) => {
6221
+ return computeTickMarks(spec, scales, chartArea);
6222
+ };
6223
+
6224
+ // src/charts/builtin.ts
6225
+ var builtinRenderers = {
6226
+ line: lineRenderer,
6227
+ area: areaRenderer,
6228
+ bar: barRenderer,
6229
+ // horizontal bars
6230
+ "bar:vertical": columnRenderer,
6231
+ // vertical bars (old 'column')
6232
+ point: scatterRenderer,
6233
+ // old 'scatter'
6234
+ arc: pieRenderer,
6235
+ // old 'pie' (donut handled via innerRadius)
6236
+ "arc:donut": donutRenderer,
6237
+ // old 'donut'
6238
+ circle: dotRenderer,
6239
+ // old 'dot'
6240
+ lollipop: dotRenderer,
6241
+ // semantic alias for dot/circle
6242
+ text: textRenderer,
6243
+ rule: ruleRenderer,
6244
+ tick: tickRenderer,
6245
+ rect: columnRenderer
6246
+ // rect uses column renderer (RectMark output) as baseline for heatmaps
6247
+ };
6248
+ function registerBuiltinRenderers() {
6249
+ for (const [type, renderer] of Object.entries(builtinRenderers)) {
6250
+ registerChartRenderer(type, renderer);
6251
+ }
6252
+ }
6253
+ registerBuiltinRenderers();
6254
+
3283
6255
  // src/charts/post-process.ts
3284
6256
  function computeMarkObstacles(marks, scales) {
3285
6257
  if (scales.y?.type === "band") {
@@ -4484,7 +7456,7 @@ var MAX_NODE_RADIUS = 12;
4484
7456
  var DEFAULT_EDGE_WIDTH = 1;
4485
7457
  var MIN_EDGE_WIDTH = 0.5;
4486
7458
  var MAX_EDGE_WIDTH = 4;
4487
- var DEFAULT_STROKE_WIDTH = 1;
7459
+ var DEFAULT_STROKE_WIDTH2 = 1;
4488
7460
  function darkenColor(hex2, amount = 0.2) {
4489
7461
  const clean = hex2.replace(/^#/, "");
4490
7462
  if (clean.length !== 6 && clean.length !== 3) return hex2;
@@ -4523,9 +7495,9 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
4523
7495
  if (encoding.nodeSize?.field) {
4524
7496
  const field = encoding.nodeSize.field;
4525
7497
  const values = nodes.map((n) => Number(n[field])).filter((v) => Number.isFinite(v));
4526
- const sizeMin = min(values) ?? 0;
4527
- const sizeMax = max(values) ?? 1;
4528
- sizeScale = sqrt().domain([sizeMin, sizeMax]).range([MIN_NODE_RADIUS, MAX_NODE_RADIUS]);
7498
+ const sizeMin = min2(values) ?? 0;
7499
+ const sizeMax = max2(values) ?? 1;
7500
+ sizeScale = sqrt2().domain([sizeMin, sizeMax]).range([MIN_NODE_RADIUS, MAX_NODE_RADIUS]);
4529
7501
  }
4530
7502
  let colorFn;
4531
7503
  if (encoding.nodeColor?.field) {
@@ -4534,8 +7506,8 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
4534
7506
  const scaleConfig = encoding.nodeColor.scale;
4535
7507
  if (fieldType === "quantitative") {
4536
7508
  const values = nodes.map((n) => Number(n[field])).filter((v) => Number.isFinite(v));
4537
- const colorMin = min(values) ?? 0;
4538
- const colorMax = max(values) ?? 1;
7509
+ const colorMin = min2(values) ?? 0;
7510
+ const colorMax = max2(values) ?? 1;
4539
7511
  const seqPalettes = Object.values(theme.colors.sequential);
4540
7512
  const palette = seqPalettes.length > 0 ? seqPalettes[0] : ["#ccc", "#333"];
4541
7513
  const domain = scaleConfig?.domain && scaleConfig.domain.length === 2 ? scaleConfig.domain : [colorMin, colorMax];
@@ -4577,7 +7549,7 @@ function resolveNodeVisuals(nodes, encoding, edges, theme, nodeOverrides) {
4577
7549
  const override = nodeOverrides?.[node.id];
4578
7550
  const finalFill = override?.fill ?? fill;
4579
7551
  const finalRadius = override?.radius ?? radius;
4580
- const finalStrokeWidth = override?.strokeWidth ?? DEFAULT_STROKE_WIDTH;
7552
+ const finalStrokeWidth = override?.strokeWidth ?? DEFAULT_STROKE_WIDTH2;
4581
7553
  const finalStroke = override?.stroke ?? stroke;
4582
7554
  const finalLabelPriority = override?.alwaysShowLabel ? Infinity : labelPriority;
4583
7555
  return {
@@ -4598,8 +7570,8 @@ function resolveEdgeVisuals(edges, encoding, theme) {
4598
7570
  if (encoding.edgeWidth?.field) {
4599
7571
  const field = encoding.edgeWidth.field;
4600
7572
  const values = edges.map((e) => Number(e[field])).filter((v) => Number.isFinite(v));
4601
- const widthMin = min(values) ?? 0;
4602
- const widthMax = max(values) ?? 1;
7573
+ const widthMin = min2(values) ?? 0;
7574
+ const widthMax = max2(values) ?? 1;
4603
7575
  widthScale = linear2().domain([widthMin, widthMax]).range([MIN_EDGE_WIDTH, MAX_EDGE_WIDTH]);
4604
7576
  }
4605
7577
  let edgeColorFn;
@@ -4609,8 +7581,8 @@ function resolveEdgeVisuals(edges, encoding, theme) {
4609
7581
  const scaleConfig = encoding.edgeColor.scale;
4610
7582
  if (fieldType === "quantitative") {
4611
7583
  const values = edges.map((e) => Number(e[field])).filter((v) => Number.isFinite(v));
4612
- const colorMin = min(values) ?? 0;
4613
- const colorMax = max(values) ?? 1;
7584
+ const colorMin = min2(values) ?? 0;
7585
+ const colorMax = max2(values) ?? 1;
4614
7586
  const seqPalettes = Object.values(theme.colors.sequential);
4615
7587
  const palette = seqPalettes.length > 0 ? seqPalettes[0] : ["#ccc", "#333"];
4616
7588
  const domain = scaleConfig?.domain && scaleConfig.domain.length === 2 ? scaleConfig.domain : [colorMin, colorMax];
@@ -4869,11 +7841,11 @@ function compileGraph(spec, options) {
4869
7841
  var DEFAULT_COLLISION_PADDING = 5;
4870
7842
 
4871
7843
  // src/layout/axes/thinning.ts
4872
- import { estimateTextWidth as estimateTextWidth2 } from "@opendata-ai/openchart-core";
7844
+ import { estimateTextWidth as estimateTextWidth7 } from "@opendata-ai/openchart-core";
4873
7845
  var MIN_TICK_GAP_FACTOR = 1;
4874
7846
  var MIN_TICK_COUNT = 2;
4875
7847
  function measureLabel(text, fontSize, fontWeight, measureText) {
4876
- return measureText ? measureText(text, fontSize, fontWeight).width : estimateTextWidth2(text, fontSize, fontWeight);
7848
+ return measureText ? measureText(text, fontSize, fontWeight).width : estimateTextWidth7(text, fontSize, fontWeight);
4877
7849
  }
4878
7850
  function ticksOverlap(ticks2, fontSize, fontWeight, measureText, orientation = "horizontal") {
4879
7851
  if (ticks2.length < 2) return false;
@@ -4914,11 +7886,11 @@ function thinTicksUntilFit(ticks2, fontSize, fontWeight, measureText, orientatio
4914
7886
 
4915
7887
  // src/layout/axes/ticks.ts
4916
7888
  import {
4917
- abbreviateNumber,
4918
- buildD3Formatter,
7889
+ abbreviateNumber as abbreviateNumber2,
7890
+ buildD3Formatter as buildD3Formatter4,
4919
7891
  buildTemporalFormatter,
4920
7892
  formatDate,
4921
- formatNumber
7893
+ formatNumber as formatNumber2
4922
7894
  } from "@opendata-ai/openchart-core";
4923
7895
  var Y_PX_PER_TICK = {
4924
7896
  full: 55,
@@ -4947,9 +7919,9 @@ var TICK_COUNTS = {
4947
7919
  };
4948
7920
  function targetTickCount(axisLength, density, orientation) {
4949
7921
  const pxPerTick = orientation === "y" ? Y_PX_PER_TICK[density] : X_PX_PER_TICK[density];
4950
- const [min3, max3] = orientation === "y" ? Y_TICK_COUNT_RANGE[density] : X_TICK_COUNT_RANGE[density];
7922
+ const [min4, max4] = orientation === "y" ? Y_TICK_COUNT_RANGE[density] : X_TICK_COUNT_RANGE[density];
4951
7923
  const raw = Math.round(axisLength / pxPerTick);
4952
- return Math.max(min3, Math.min(max3, raw));
7924
+ return Math.max(min4, Math.min(max4, raw));
4953
7925
  }
4954
7926
  var NUMERIC_SCALE_TYPES = /* @__PURE__ */ new Set([
4955
7927
  "linear",
@@ -4973,11 +7945,11 @@ function formatTickLabel(value2, resolvedScale) {
4973
7945
  if (NUMERIC_SCALE_TYPES.has(resolvedScale.type)) {
4974
7946
  const num = value2;
4975
7947
  if (formatStr) {
4976
- const fmt = buildD3Formatter(formatStr);
7948
+ const fmt = buildD3Formatter4(formatStr);
4977
7949
  if (fmt) return fmt(num);
4978
7950
  }
4979
- if (Math.abs(num) >= 1e3) return abbreviateNumber(num);
4980
- return formatNumber(num);
7951
+ if (Math.abs(num) >= 1e3) return abbreviateNumber2(num);
7952
+ return formatNumber2(num);
4981
7953
  }
4982
7954
  return String(value2);
4983
7955
  }
@@ -5148,7 +8120,8 @@ function computeAxes(scales, chartArea, strategy, theme, measureText) {
5148
8120
  position: t.position,
5149
8121
  major: true
5150
8122
  }));
5151
- const shouldThin = scales.x.type !== "band" && !axisConfig?.tickCount && !axisConfig?.values;
8123
+ const hasExplicitValues = !!axisConfig?.values;
8124
+ const shouldThin = scales.x.type !== "band" && !hasExplicitValues;
5152
8125
  let ticks2;
5153
8126
  if (!shouldThin) {
5154
8127
  ticks2 = allTicks;
@@ -5210,9 +8183,9 @@ function computeAxes(scales, chartArea, strategy, theme, measureText) {
5210
8183
  } else {
5211
8184
  allTicks = continuousTicks(scales.y, yDensity, yTargetCount);
5212
8185
  }
5213
- const shouldThin = scales.y.type !== "band" && !axisConfig?.tickCount && !axisConfig?.values;
8186
+ const shouldThinY = scales.y.type !== "band" && !axisConfig?.values;
5214
8187
  let ticks2;
5215
- if (!shouldThin) {
8188
+ if (!shouldThinY) {
5216
8189
  ticks2 = allTicks;
5217
8190
  } else if (isContinuousY) {
5218
8191
  ticks2 = fitContinuousTicks(
@@ -5258,7 +8231,51 @@ function computeAxes(scales, chartArea, strategy, theme, measureText) {
5258
8231
  }
5259
8232
 
5260
8233
  // src/layout/dimensions.ts
5261
- import { computeChrome as computeChrome2, estimateTextWidth as estimateTextWidth3 } from "@opendata-ai/openchart-core";
8234
+ import { computeChrome as computeChrome2, estimateTextWidth as estimateTextWidth9 } from "@opendata-ai/openchart-core";
8235
+
8236
+ // src/legend/wrap.ts
8237
+ import { COMPACT_WIDTH, estimateTextWidth as estimateTextWidth8 } from "@opendata-ai/openchart-core";
8238
+ var SWATCH_SIZE2 = 12;
8239
+ var SWATCH_GAP2 = 6;
8240
+ var ENTRY_GAP2 = 16;
8241
+ var ENTRY_GAP_COMPACT = 10;
8242
+ var LEGEND_GAP = 4;
8243
+ function legendGap(width) {
8244
+ return width < COMPACT_WIDTH ? 0 : LEGEND_GAP;
8245
+ }
8246
+ function measureLegendWrap(entries, maxWidth, labelStyle, maxRows, entryGap = ENTRY_GAP2) {
8247
+ if (entries.length === 0) {
8248
+ return { rowCount: 0, fittingCount: 0, rowWidths: [] };
8249
+ }
8250
+ let rowCount = 1;
8251
+ let rowWidth = 0;
8252
+ const rowWidths = [];
8253
+ let fittingCount = entries.length;
8254
+ let fittingCountLocked = false;
8255
+ for (let i = 0; i < entries.length; i++) {
8256
+ const labelWidth = estimateTextWidth8(
8257
+ entries[i].label,
8258
+ labelStyle.fontSize,
8259
+ labelStyle.fontWeight
8260
+ );
8261
+ const entryWidth = SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + entryGap;
8262
+ if (rowWidth + entryWidth > maxWidth && rowWidth > 0) {
8263
+ rowWidths.push(rowWidth);
8264
+ rowCount++;
8265
+ rowWidth = entryWidth;
8266
+ if (!fittingCountLocked && maxRows != null && rowCount > maxRows) {
8267
+ fittingCount = i;
8268
+ fittingCountLocked = true;
8269
+ }
8270
+ } else {
8271
+ rowWidth += entryWidth;
8272
+ }
8273
+ }
8274
+ rowWidths.push(rowWidth);
8275
+ return { rowCount, fittingCount, rowWidths };
8276
+ }
8277
+
8278
+ // src/layout/dimensions.ts
5262
8279
  function chromeToInput(chrome) {
5263
8280
  return {
5264
8281
  title: chrome.title,
@@ -5307,7 +8324,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
5307
8324
  if (xField) {
5308
8325
  for (const row of spec.data) {
5309
8326
  const label = String(row[xField] ?? "");
5310
- const w = estimateTextWidth3(label, theme.fonts.sizes.axisTick, theme.fonts.weights.normal);
8327
+ const w = estimateTextWidth9(label, theme.fonts.sizes.axisTick, theme.fonts.weights.normal);
5311
8328
  if (w > maxLabelWidth) maxLabelWidth = w;
5312
8329
  }
5313
8330
  }
@@ -5335,7 +8352,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
5335
8352
  const label = String(row[colorField] ?? "");
5336
8353
  if (!seen.has(label)) {
5337
8354
  seen.add(label);
5338
- const w = estimateTextWidth3(label, 11, 600);
8355
+ const w = estimateTextWidth9(label, 11, 600);
5339
8356
  if (w > maxLabelWidth) maxLabelWidth = w;
5340
8357
  }
5341
8358
  }
@@ -5355,7 +8372,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
5355
8372
  const maxXStr = String(maxX);
5356
8373
  for (const ann of spec.annotations) {
5357
8374
  if (ann.type === "text" && String(ann.x) === maxXStr) {
5358
- const textWidth = estimateTextWidth3(ann.text, ann.fontSize ?? 11, ann.fontWeight ?? 600);
8375
+ const textWidth = estimateTextWidth9(ann.text, ann.fontSize ?? 11, ann.fontWeight ?? 600);
5359
8376
  const dx = ann.offset?.dx ?? 0;
5360
8377
  const anchor = ann.anchor ?? "auto";
5361
8378
  const baseRightExtent = anchor === "left" ? textWidth : (
@@ -5379,11 +8396,15 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
5379
8396
  let maxLabelWidth = 0;
5380
8397
  for (const row of spec.data) {
5381
8398
  const label = String(row[yField] ?? "");
5382
- const w = estimateTextWidth3(label, theme.fonts.sizes.axisTick, theme.fonts.weights.normal);
8399
+ const w = estimateTextWidth9(label, theme.fonts.sizes.axisTick, theme.fonts.weights.normal);
5383
8400
  if (w > maxLabelWidth) maxLabelWidth = w;
5384
8401
  }
5385
8402
  if (maxLabelWidth > 0) {
5386
- margins.left = Math.max(margins.left, padding + maxLabelWidth + 12);
8403
+ const labelGap = width < 500 ? 8 : 12;
8404
+ const maxLeftFraction = width < 400 ? 0.45 : width < 600 ? 0.55 : 1;
8405
+ const maxLeftReserved = Math.floor(width * maxLeftFraction);
8406
+ const reserved = Math.min(padding + maxLabelWidth + labelGap, maxLeftReserved);
8407
+ margins.left = Math.max(margins.left, reserved);
5387
8408
  }
5388
8409
  } else if (encoding.y.type === "quantitative" || encoding.y.type === "temporal") {
5389
8410
  const yField = encoding.y.field;
@@ -5411,7 +8432,7 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
5411
8432
  }
5412
8433
  const negPrefix = spec.data.some((r) => Number(r[yField]) < 0) ? "-" : "";
5413
8434
  const labelEst = negPrefix + sampleLabel;
5414
- const labelWidth = estimateTextWidth3(
8435
+ const labelWidth = estimateTextWidth9(
5415
8436
  labelEst,
5416
8437
  theme.fonts.sizes.axisTick,
5417
8438
  theme.fonts.weights.normal
@@ -5425,12 +8446,13 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
5425
8446
  margins.left = Math.max(margins.left, padding + rotatedLabelMargin);
5426
8447
  }
5427
8448
  if (legendLayout.entries.length > 0) {
8449
+ const gap = legendGap(width);
5428
8450
  if (legendLayout.position === "right" || legendLayout.position === "bottom-right") {
5429
8451
  margins.right += legendLayout.bounds.width + 8;
5430
8452
  } else if (legendLayout.position === "top") {
5431
- margins.top += legendLayout.bounds.height + 4;
8453
+ margins.top += legendLayout.bounds.height + gap;
5432
8454
  } else if (legendLayout.position === "bottom") {
5433
- margins.bottom += legendLayout.bounds.height + 4;
8455
+ margins.bottom += legendLayout.bounds.height + gap;
5434
8456
  }
5435
8457
  }
5436
8458
  let chartArea = {
@@ -5456,7 +8478,8 @@ function computeDimensions(spec, options, legendLayout, theme, strategy, waterma
5456
8478
  const newBottom = padding + fallbackChrome.bottomHeight + xAxisHeight;
5457
8479
  const bottomDelta = margins.bottom - newBottom;
5458
8480
  if (topDelta > 0 || bottomDelta > 0) {
5459
- margins.top = newTop + (legendLayout.entries.length > 0 && legendLayout.position === "top" ? legendLayout.bounds.height + 4 : 0);
8481
+ const gap = legendGap(width);
8482
+ margins.top = newTop + (legendLayout.entries.length > 0 && legendLayout.position === "top" ? legendLayout.bounds.height + gap : 0);
5460
8483
  margins.bottom = newBottom;
5461
8484
  chartArea = {
5462
8485
  x: margins.left,
@@ -5565,8 +8588,8 @@ function buildLinearScale(channel, data, rangeStart, rangeEnd) {
5565
8588
  domainMin = d0;
5566
8589
  domainMax = d1;
5567
8590
  } else {
5568
- domainMin = min(values) ?? 0;
5569
- domainMax = max(values) ?? 1;
8591
+ domainMin = min2(values) ?? 0;
8592
+ domainMax = max2(values) ?? 1;
5570
8593
  if (channel.scale?.zero !== false) {
5571
8594
  domainMin = Math.min(0, domainMin);
5572
8595
  domainMax = Math.max(0, domainMax);
@@ -5581,8 +8604,8 @@ function buildLinearScale(channel, data, rangeStart, rangeEnd) {
5581
8604
  }
5582
8605
  function buildLogScale(channel, data, rangeStart, rangeEnd) {
5583
8606
  const values = parseNumbers(fieldValues(data, channel.field)).filter((v) => v > 0);
5584
- const domainMin = channel.scale?.domain ? channel.scale.domain[0] : min(values) ?? 1;
5585
- const domainMax = channel.scale?.domain ? channel.scale.domain[1] : max(values) ?? 10;
8607
+ const domainMin = channel.scale?.domain ? channel.scale.domain[0] : min2(values) ?? 1;
8608
+ const domainMax = channel.scale?.domain ? channel.scale.domain[1] : max2(values) ?? 10;
5586
8609
  const scale = log().domain([domainMin, domainMax]).range([rangeStart, rangeEnd]);
5587
8610
  if (channel.scale?.base !== void 0) {
5588
8611
  scale.base(channel.scale.base);
@@ -5600,8 +8623,8 @@ function buildPowScale(channel, data, rangeStart, rangeEnd) {
5600
8623
  if (channel.scale?.domain) {
5601
8624
  [domainMin, domainMax] = channel.scale.domain;
5602
8625
  } else {
5603
- domainMin = min(values) ?? 0;
5604
- domainMax = max(values) ?? 1;
8626
+ domainMin = min2(values) ?? 0;
8627
+ domainMax = max2(values) ?? 1;
5605
8628
  if (channel.scale?.zero !== false) {
5606
8629
  domainMin = Math.min(0, domainMin);
5607
8630
  domainMax = Math.max(0, domainMax);
@@ -5624,14 +8647,14 @@ function buildSqrtScale(channel, data, rangeStart, rangeEnd) {
5624
8647
  if (channel.scale?.domain) {
5625
8648
  [domainMin, domainMax] = channel.scale.domain;
5626
8649
  } else {
5627
- domainMin = min(values) ?? 0;
5628
- domainMax = max(values) ?? 1;
8650
+ domainMin = min2(values) ?? 0;
8651
+ domainMax = max2(values) ?? 1;
5629
8652
  if (channel.scale?.zero !== false) {
5630
8653
  domainMin = Math.min(0, domainMin);
5631
8654
  domainMax = Math.max(0, domainMax);
5632
8655
  }
5633
8656
  }
5634
- const scale = sqrt().domain([domainMin, domainMax]).range([rangeStart, rangeEnd]);
8657
+ const scale = sqrt2().domain([domainMin, domainMax]).range([rangeStart, rangeEnd]);
5635
8658
  if (!channel.scale?.domain && channel.scale?.nice !== false) {
5636
8659
  scale.nice();
5637
8660
  }
@@ -5645,8 +8668,8 @@ function buildSymlogScale(channel, data, rangeStart, rangeEnd) {
5645
8668
  if (channel.scale?.domain) {
5646
8669
  [domainMin, domainMax] = channel.scale.domain;
5647
8670
  } else {
5648
- domainMin = min(values) ?? 0;
5649
- domainMax = max(values) ?? 1;
8671
+ domainMin = min2(values) ?? 0;
8672
+ domainMax = max2(values) ?? 1;
5650
8673
  if (channel.scale?.zero !== false) {
5651
8674
  domainMin = Math.min(0, domainMin);
5652
8675
  domainMax = Math.max(0, domainMax);
@@ -5670,8 +8693,8 @@ function buildQuantileScale(channel, data, rangeStart, rangeEnd) {
5670
8693
  }
5671
8694
  function buildQuantizeScale(channel, data, rangeStart, rangeEnd) {
5672
8695
  const values = parseNumbers(fieldValues(data, channel.field));
5673
- const domainMin = channel.scale?.domain ? channel.scale.domain[0] : min(values) ?? 0;
5674
- const domainMax = channel.scale?.domain ? channel.scale.domain[1] : max(values) ?? 1;
8696
+ const domainMin = channel.scale?.domain ? channel.scale.domain[0] : min2(values) ?? 0;
8697
+ const domainMax = channel.scale?.domain ? channel.scale.domain[1] : max2(values) ?? 1;
5675
8698
  const range2 = channel.scale?.range ? channel.scale.range : evenRange(rangeStart, rangeEnd, 4);
5676
8699
  const scale = quantize().domain([domainMin, domainMax]).range(range2);
5677
8700
  return { scale, type: "quantize", channel };
@@ -5706,7 +8729,7 @@ function buildBandScale(channel, data, rangeStart, rangeEnd) {
5706
8729
  function buildPointScale(channel, data, rangeStart, rangeEnd) {
5707
8730
  const values = channel.scale?.domain ? channel.scale.domain : applyCategoricalSort(uniqueStrings(fieldValues(data, channel.field)), channel.sort);
5708
8731
  const padding = channel.scale?.padding ?? 0.5;
5709
- const scale = point().domain(values).range([rangeStart, rangeEnd]).padding(padding);
8732
+ const scale = point4().domain(values).range([rangeStart, rangeEnd]).padding(padding);
5710
8733
  if (channel.scale?.reverse) {
5711
8734
  const [r0, r1] = scale.range();
5712
8735
  scale.range([r1, r0]);
@@ -5723,8 +8746,8 @@ function buildOrdinalColorScale(channel, data, palette) {
5723
8746
  }
5724
8747
  function buildSequentialColorScale(channel, data, palette) {
5725
8748
  const values = parseNumbers(fieldValues(data, channel.field));
5726
- const domainMin = min(values) ?? 0;
5727
- const domainMax = max(values) ?? 1;
8749
+ const domainMin = min2(values) ?? 0;
8750
+ const domainMax = max2(values) ?? 1;
5728
8751
  const explicitRange = channel.scale?.range;
5729
8752
  const colors = explicitRange ?? palette;
5730
8753
  const scale = linear2().domain([domainMin, domainMax]).range([colors[0], colors[colors.length - 1]]).clamp(true);
@@ -5925,46 +8948,7 @@ function computeScales(spec, chartArea, data) {
5925
8948
  }
5926
8949
 
5927
8950
  // src/legend/compute.ts
5928
- import { BRAND_RESERVE_WIDTH as BRAND_RESERVE_WIDTH2, estimateTextWidth as estimateTextWidth5 } from "@opendata-ai/openchart-core";
5929
-
5930
- // src/legend/wrap.ts
5931
- import { estimateTextWidth as estimateTextWidth4 } from "@opendata-ai/openchart-core";
5932
- var SWATCH_SIZE2 = 12;
5933
- var SWATCH_GAP2 = 6;
5934
- var ENTRY_GAP2 = 16;
5935
- function measureLegendWrap(entries, maxWidth, labelStyle, maxRows) {
5936
- if (entries.length === 0) {
5937
- return { rowCount: 0, fittingCount: 0, rowWidths: [] };
5938
- }
5939
- let rowCount = 1;
5940
- let rowWidth = 0;
5941
- const rowWidths = [];
5942
- let fittingCount = entries.length;
5943
- let fittingCountLocked = false;
5944
- for (let i = 0; i < entries.length; i++) {
5945
- const labelWidth = estimateTextWidth4(
5946
- entries[i].label,
5947
- labelStyle.fontSize,
5948
- labelStyle.fontWeight
5949
- );
5950
- const entryWidth = SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + ENTRY_GAP2;
5951
- if (rowWidth + entryWidth > maxWidth && rowWidth > 0) {
5952
- rowWidths.push(rowWidth);
5953
- rowCount++;
5954
- rowWidth = entryWidth;
5955
- if (!fittingCountLocked && maxRows != null && rowCount > maxRows) {
5956
- fittingCount = i;
5957
- fittingCountLocked = true;
5958
- }
5959
- } else {
5960
- rowWidth += entryWidth;
5961
- }
5962
- }
5963
- rowWidths.push(rowWidth);
5964
- return { rowCount, fittingCount, rowWidths };
5965
- }
5966
-
5967
- // src/legend/compute.ts
8951
+ import { BRAND_RESERVE_WIDTH as BRAND_RESERVE_WIDTH2, COMPACT_WIDTH as COMPACT_WIDTH2, estimateTextWidth as estimateTextWidth10 } from "@opendata-ai/openchart-core";
5968
8952
  var LEGEND_PADDING = 8;
5969
8953
  var LEGEND_RIGHT_WIDTH = 120;
5970
8954
  var RIGHT_LEGEND_MAX_HEIGHT_RATIO = 0.4;
@@ -5986,11 +8970,15 @@ function extractColorEntries(spec, theme) {
5986
8970
  if (!colorEnc) return [];
5987
8971
  if ("condition" in colorEnc) return [];
5988
8972
  if (colorEnc.type === "quantitative") return [];
5989
- const uniqueValues = [...new Set(spec.data.map((d) => String(d[colorEnc.field])))];
8973
+ const dataValues = [...new Set(spec.data.map((d) => String(d[colorEnc.field])))];
5990
8974
  const explicitDomain = colorEnc.scale?.domain;
5991
8975
  const explicitRange = colorEnc.scale?.range;
5992
8976
  const palette = explicitRange ?? theme.colors.categorical;
5993
8977
  const shape = swatchShapeForType(spec.markType);
8978
+ const uniqueValues = explicitDomain ? [
8979
+ ...explicitDomain.filter((v) => dataValues.includes(v)),
8980
+ ...dataValues.filter((v) => !explicitDomain.includes(v))
8981
+ ] : dataValues;
5994
8982
  return uniqueValues.map((value2, i) => {
5995
8983
  let colorIndex = i;
5996
8984
  if (explicitDomain && explicitRange) {
@@ -6045,8 +9033,8 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
6045
9033
  if (isLineOrArea && hasLabels && labelsWillRender && hasColorEncoding && legendNotForced) {
6046
9034
  const isArea = spec.markType === "area";
6047
9035
  const quantChannel = spec.encoding.y?.type === "quantitative" ? spec.encoding.y : spec.encoding.x;
6048
- const stackValue = quantChannel?.stack;
6049
- const isStacked = stackValue !== null && stackValue !== false;
9036
+ const stackValue2 = quantChannel?.stack;
9037
+ const isStacked = stackValue2 !== null && stackValue2 !== false;
6050
9038
  if (!isArea || !isStacked) {
6051
9039
  entries = [];
6052
9040
  }
@@ -6072,7 +9060,7 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
6072
9060
  }
6073
9061
  if (resolvedPosition === "right" || resolvedPosition === "bottom-right") {
6074
9062
  const maxLabelWidth = Math.max(
6075
- ...entries.map((e) => estimateTextWidth5(e.label, labelStyle.fontSize, labelStyle.fontWeight))
9063
+ ...entries.map((e) => estimateTextWidth10(e.label, labelStyle.fontSize, labelStyle.fontWeight))
6076
9064
  );
6077
9065
  const legendWidth = Math.min(
6078
9066
  LEGEND_RIGHT_WIDTH,
@@ -6110,7 +9098,10 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
6110
9098
  };
6111
9099
  }
6112
9100
  const reserveBrand = watermark && resolvedPosition === "bottom";
6113
- const availableWidth = chartArea.width - LEGEND_PADDING * 2 - (reserveBrand ? BRAND_RESERVE_WIDTH2 : 0);
9101
+ const isCompact = chartArea.width < COMPACT_WIDTH2;
9102
+ const effectivePadding = isCompact ? 2 : LEGEND_PADDING;
9103
+ const effectiveEntryGap = isCompact ? ENTRY_GAP_COMPACT : ENTRY_GAP2;
9104
+ const availableWidth = chartArea.width - effectivePadding * 2 - (reserveBrand ? BRAND_RESERVE_WIDTH2 : 0);
6114
9105
  if (spec.legend?.symbolLimit != null) {
6115
9106
  const limit = Math.max(1, spec.legend.symbolLimit);
6116
9107
  if (limit < entries.length) {
@@ -6118,17 +9109,29 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
6118
9109
  }
6119
9110
  }
6120
9111
  const maxRows = spec.legend?.maxRows != null ? Math.max(1, spec.legend.maxRows) : spec.legend?.columns != null ? Math.ceil(entries.length / spec.legend.columns) : TOP_LEGEND_MAX_ROWS;
6121
- const { fittingCount } = measureLegendWrap(entries, availableWidth, labelStyle, maxRows);
9112
+ const { fittingCount } = measureLegendWrap(
9113
+ entries,
9114
+ availableWidth,
9115
+ labelStyle,
9116
+ maxRows,
9117
+ effectiveEntryGap
9118
+ );
6122
9119
  if (fittingCount < entries.length) {
6123
9120
  entries = truncateEntries(entries, fittingCount);
6124
9121
  }
6125
9122
  const totalWidth = entries.reduce((sum2, entry) => {
6126
- const labelWidth = estimateTextWidth5(entry.label, labelStyle.fontSize, labelStyle.fontWeight);
6127
- return sum2 + SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + ENTRY_GAP2;
9123
+ const labelWidth = estimateTextWidth10(entry.label, labelStyle.fontSize, labelStyle.fontWeight);
9124
+ return sum2 + SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth + effectiveEntryGap;
6128
9125
  }, 0);
6129
- const { rowCount } = measureLegendWrap(entries, availableWidth, labelStyle);
9126
+ const { rowCount } = measureLegendWrap(
9127
+ entries,
9128
+ availableWidth,
9129
+ labelStyle,
9130
+ void 0,
9131
+ effectiveEntryGap
9132
+ );
6130
9133
  const rowHeight = SWATCH_SIZE2 + 4;
6131
- const legendHeight = rowCount * rowHeight + LEGEND_PADDING * 2;
9134
+ const legendHeight = rowCount * rowHeight + effectivePadding * 2;
6132
9135
  const offsetDx = spec.legend?.offset?.dx ?? 0;
6133
9136
  const offsetDy = spec.legend?.offset?.dy ?? 0;
6134
9137
  return {
@@ -6143,58 +9146,58 @@ function computeLegend(spec, strategy, theme, chartArea, watermark = true) {
6143
9146
  labelStyle,
6144
9147
  swatchSize: SWATCH_SIZE2,
6145
9148
  swatchGap: SWATCH_GAP2,
6146
- entryGap: ENTRY_GAP2
9149
+ entryGap: effectiveEntryGap
6147
9150
  };
6148
9151
  }
6149
9152
 
6150
9153
  // src/sankey/compile-sankey.ts
6151
9154
  import {
6152
9155
  adaptTheme as adaptTheme2,
6153
- buildD3Formatter as buildD3Formatter2,
9156
+ buildD3Formatter as buildD3Formatter5,
6154
9157
  computeChrome as computeChrome3,
6155
- estimateTextWidth as estimateTextWidth6,
6156
- formatNumber as formatNumber2,
9158
+ estimateTextWidth as estimateTextWidth11,
9159
+ formatNumber as formatNumber3,
6157
9160
  resolveTheme as resolveTheme2
6158
9161
  } from "@opendata-ai/openchart-core";
6159
9162
 
6160
9163
  // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/max.js
6161
- function max2(values, valueof) {
6162
- let max3;
9164
+ function max3(values, valueof) {
9165
+ let max4;
6163
9166
  if (valueof === void 0) {
6164
9167
  for (const value2 of values) {
6165
- if (value2 != null && (max3 < value2 || max3 === void 0 && value2 >= value2)) {
6166
- max3 = value2;
9168
+ if (value2 != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
9169
+ max4 = value2;
6167
9170
  }
6168
9171
  }
6169
9172
  } else {
6170
9173
  let index = -1;
6171
9174
  for (let value2 of values) {
6172
- if ((value2 = valueof(value2, ++index, values)) != null && (max3 < value2 || max3 === void 0 && value2 >= value2)) {
6173
- max3 = value2;
9175
+ if ((value2 = valueof(value2, ++index, values)) != null && (max4 < value2 || max4 === void 0 && value2 >= value2)) {
9176
+ max4 = value2;
6174
9177
  }
6175
9178
  }
6176
9179
  }
6177
- return max3;
9180
+ return max4;
6178
9181
  }
6179
9182
 
6180
9183
  // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/min.js
6181
- function min2(values, valueof) {
6182
- let min3;
9184
+ function min3(values, valueof) {
9185
+ let min4;
6183
9186
  if (valueof === void 0) {
6184
9187
  for (const value2 of values) {
6185
- if (value2 != null && (min3 > value2 || min3 === void 0 && value2 >= value2)) {
6186
- min3 = value2;
9188
+ if (value2 != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
9189
+ min4 = value2;
6187
9190
  }
6188
9191
  }
6189
9192
  } else {
6190
9193
  let index = -1;
6191
9194
  for (let value2 of values) {
6192
- if ((value2 = valueof(value2, ++index, values)) != null && (min3 > value2 || min3 === void 0 && value2 >= value2)) {
6193
- min3 = value2;
9195
+ if ((value2 = valueof(value2, ++index, values)) != null && (min4 > value2 || min4 === void 0 && value2 >= value2)) {
9196
+ min4 = value2;
6194
9197
  }
6195
9198
  }
6196
9199
  }
6197
- return min3;
9200
+ return min4;
6198
9201
  }
6199
9202
 
6200
9203
  // ../../node_modules/.bun/d3-array@2.12.1/node_modules/d3-array/src/sum.js
@@ -6231,13 +9234,13 @@ function justify(node, n) {
6231
9234
  return node.sourceLinks.length ? node.depth : n - 1;
6232
9235
  }
6233
9236
  function center(node) {
6234
- return node.targetLinks.length ? node.depth : node.sourceLinks.length ? min2(node.sourceLinks, targetDepth) - 1 : 0;
9237
+ return node.targetLinks.length ? node.depth : node.sourceLinks.length ? min3(node.sourceLinks, targetDepth) - 1 : 0;
6235
9238
  }
6236
9239
 
6237
9240
  // ../../node_modules/.bun/d3-sankey@0.12.3/node_modules/d3-sankey/src/constant.js
6238
- function constant(x) {
9241
+ function constant(x2) {
6239
9242
  return function() {
6240
- return x;
9243
+ return x2;
6241
9244
  };
6242
9245
  }
6243
9246
 
@@ -6371,15 +9374,15 @@ function Sankey() {
6371
9374
  const n = nodes2.length;
6372
9375
  let current = new Set(nodes2);
6373
9376
  let next = /* @__PURE__ */ new Set();
6374
- let x = 0;
9377
+ let x2 = 0;
6375
9378
  while (current.size) {
6376
9379
  for (const node of current) {
6377
- node.depth = x;
9380
+ node.depth = x2;
6378
9381
  for (const { target } of node.sourceLinks) {
6379
9382
  next.add(target);
6380
9383
  }
6381
9384
  }
6382
- if (++x > n) throw new Error("circular link");
9385
+ if (++x2 > n) throw new Error("circular link");
6383
9386
  current = next;
6384
9387
  next = /* @__PURE__ */ new Set();
6385
9388
  }
@@ -6388,25 +9391,25 @@ function Sankey() {
6388
9391
  const n = nodes2.length;
6389
9392
  let current = new Set(nodes2);
6390
9393
  let next = /* @__PURE__ */ new Set();
6391
- let x = 0;
9394
+ let x2 = 0;
6392
9395
  while (current.size) {
6393
9396
  for (const node of current) {
6394
- node.height = x;
9397
+ node.height = x2;
6395
9398
  for (const { source } of node.targetLinks) {
6396
9399
  next.add(source);
6397
9400
  }
6398
9401
  }
6399
- if (++x > n) throw new Error("circular link");
9402
+ if (++x2 > n) throw new Error("circular link");
6400
9403
  current = next;
6401
9404
  next = /* @__PURE__ */ new Set();
6402
9405
  }
6403
9406
  }
6404
9407
  function computeNodeLayers({ nodes: nodes2 }) {
6405
- const x = max2(nodes2, (d) => d.depth) + 1;
6406
- const kx = (x1 - x0 - dx) / (x - 1);
6407
- const columns = new Array(x);
9408
+ const x2 = max3(nodes2, (d) => d.depth) + 1;
9409
+ const kx = (x1 - x0 - dx) / (x2 - 1);
9410
+ const columns = new Array(x2);
6408
9411
  for (const node of nodes2) {
6409
- const i = Math.max(0, Math.min(x - 1, Math.floor(align.call(null, node, x))));
9412
+ const i = Math.max(0, Math.min(x2 - 1, Math.floor(align.call(null, node, x2))));
6410
9413
  node.layer = i;
6411
9414
  node.x0 = x0 + i * kx;
6412
9415
  node.x1 = node.x0 + dx;
@@ -6419,29 +9422,29 @@ function Sankey() {
6419
9422
  return columns;
6420
9423
  }
6421
9424
  function initializeNodeBreadths(columns) {
6422
- const ky = min2(columns, (c) => (y1 - y0 - (c.length - 1) * py) / sum(c, value));
9425
+ const ky = min3(columns, (c) => (y1 - y0 - (c.length - 1) * py) / sum(c, value));
6423
9426
  for (const nodes2 of columns) {
6424
- let y = y0;
9427
+ let y2 = y0;
6425
9428
  for (const node of nodes2) {
6426
- node.y0 = y;
6427
- node.y1 = y + node.value * ky;
6428
- y = node.y1 + py;
9429
+ node.y0 = y2;
9430
+ node.y1 = y2 + node.value * ky;
9431
+ y2 = node.y1 + py;
6429
9432
  for (const link of node.sourceLinks) {
6430
9433
  link.width = link.value * ky;
6431
9434
  }
6432
9435
  }
6433
- y = (y1 - y + py) / (nodes2.length + 1);
9436
+ y2 = (y1 - y2 + py) / (nodes2.length + 1);
6434
9437
  for (let i = 0; i < nodes2.length; ++i) {
6435
9438
  const node = nodes2[i];
6436
- node.y0 += y * (i + 1);
6437
- node.y1 += y * (i + 1);
9439
+ node.y0 += y2 * (i + 1);
9440
+ node.y1 += y2 * (i + 1);
6438
9441
  }
6439
9442
  reorderLinks(nodes2);
6440
9443
  }
6441
9444
  }
6442
9445
  function computeNodeBreadths(graph) {
6443
9446
  const columns = computeNodeLayers(graph);
6444
- py = Math.min(dy, (y1 - y0) / (max2(columns, (c) => c.length) - 1));
9447
+ py = Math.min(dy, (y1 - y0) / (max3(columns, (c) => c.length) - 1));
6445
9448
  initializeNodeBreadths(columns);
6446
9449
  for (let i = 0; i < iterations; ++i) {
6447
9450
  const alpha = Math.pow(0.99, i);
@@ -6454,45 +9457,45 @@ function Sankey() {
6454
9457
  for (let i = 1, n = columns.length; i < n; ++i) {
6455
9458
  const column = columns[i];
6456
9459
  for (const target of column) {
6457
- let y = 0;
9460
+ let y2 = 0;
6458
9461
  let w = 0;
6459
9462
  for (const { source, value: value2 } of target.targetLinks) {
6460
9463
  let v = value2 * (target.layer - source.layer);
6461
- y += targetTop(source, target) * v;
9464
+ y2 += targetTop(source, target) * v;
6462
9465
  w += v;
6463
9466
  }
6464
9467
  if (!(w > 0)) continue;
6465
- let dy2 = (y / w - target.y0) * alpha;
9468
+ let dy2 = (y2 / w - target.y0) * alpha;
6466
9469
  target.y0 += dy2;
6467
9470
  target.y1 += dy2;
6468
9471
  reorderNodeLinks(target);
6469
9472
  }
6470
9473
  if (sort === void 0) column.sort(ascendingBreadth);
6471
- resolveCollisions(column, beta);
9474
+ resolveCollisions6(column, beta);
6472
9475
  }
6473
9476
  }
6474
9477
  function relaxRightToLeft(columns, alpha, beta) {
6475
9478
  for (let n = columns.length, i = n - 2; i >= 0; --i) {
6476
9479
  const column = columns[i];
6477
9480
  for (const source of column) {
6478
- let y = 0;
9481
+ let y2 = 0;
6479
9482
  let w = 0;
6480
9483
  for (const { target, value: value2 } of source.sourceLinks) {
6481
9484
  let v = value2 * (target.layer - source.layer);
6482
- y += sourceTop(source, target) * v;
9485
+ y2 += sourceTop(source, target) * v;
6483
9486
  w += v;
6484
9487
  }
6485
9488
  if (!(w > 0)) continue;
6486
- let dy2 = (y / w - source.y0) * alpha;
9489
+ let dy2 = (y2 / w - source.y0) * alpha;
6487
9490
  source.y0 += dy2;
6488
9491
  source.y1 += dy2;
6489
9492
  reorderNodeLinks(source);
6490
9493
  }
6491
9494
  if (sort === void 0) column.sort(ascendingBreadth);
6492
- resolveCollisions(column, beta);
9495
+ resolveCollisions6(column, beta);
6493
9496
  }
6494
9497
  }
6495
- function resolveCollisions(nodes2, alpha) {
9498
+ function resolveCollisions6(nodes2, alpha) {
6496
9499
  const i = nodes2.length >> 1;
6497
9500
  const subject = nodes2[i];
6498
9501
  resolveCollisionsBottomToTop(nodes2, subject.y0 - py, i - 1, alpha);
@@ -6500,20 +9503,20 @@ function Sankey() {
6500
9503
  resolveCollisionsBottomToTop(nodes2, y1, nodes2.length - 1, alpha);
6501
9504
  resolveCollisionsTopToBottom(nodes2, y0, 0, alpha);
6502
9505
  }
6503
- function resolveCollisionsTopToBottom(nodes2, y, i, alpha) {
9506
+ function resolveCollisionsTopToBottom(nodes2, y2, i, alpha) {
6504
9507
  for (; i < nodes2.length; ++i) {
6505
9508
  const node = nodes2[i];
6506
- const dy2 = (y - node.y0) * alpha;
9509
+ const dy2 = (y2 - node.y0) * alpha;
6507
9510
  if (dy2 > 1e-6) node.y0 += dy2, node.y1 += dy2;
6508
- y = node.y1 + py;
9511
+ y2 = node.y1 + py;
6509
9512
  }
6510
9513
  }
6511
- function resolveCollisionsBottomToTop(nodes2, y, i, alpha) {
9514
+ function resolveCollisionsBottomToTop(nodes2, y2, i, alpha) {
6512
9515
  for (; i >= 0; --i) {
6513
9516
  const node = nodes2[i];
6514
- const dy2 = (node.y1 - y) * alpha;
9517
+ const dy2 = (node.y1 - y2) * alpha;
6515
9518
  if (dy2 > 1e-6) node.y0 -= dy2, node.y1 -= dy2;
6516
- y = node.y0 - py;
9519
+ y2 = node.y0 - py;
6517
9520
  }
6518
9521
  }
6519
9522
  function reorderNodeLinks({ sourceLinks, targetLinks }) {
@@ -6535,28 +9538,28 @@ function Sankey() {
6535
9538
  }
6536
9539
  }
6537
9540
  function targetTop(source, target) {
6538
- let y = source.y0 - (source.sourceLinks.length - 1) * py / 2;
9541
+ let y2 = source.y0 - (source.sourceLinks.length - 1) * py / 2;
6539
9542
  for (const { target: node, width } of source.sourceLinks) {
6540
9543
  if (node === target) break;
6541
- y += width + py;
9544
+ y2 += width + py;
6542
9545
  }
6543
9546
  for (const { source: node, width } of target.targetLinks) {
6544
9547
  if (node === source) break;
6545
- y -= width;
9548
+ y2 -= width;
6546
9549
  }
6547
- return y;
9550
+ return y2;
6548
9551
  }
6549
9552
  function sourceTop(source, target) {
6550
- let y = target.y0 - (target.targetLinks.length - 1) * py / 2;
9553
+ let y2 = target.y0 - (target.targetLinks.length - 1) * py / 2;
6551
9554
  for (const { source: node, width } of target.targetLinks) {
6552
9555
  if (node === source) break;
6553
- y += width + py;
9556
+ y2 += width + py;
6554
9557
  }
6555
9558
  for (const { target: node, width } of source.sourceLinks) {
6556
9559
  if (node === target) break;
6557
- y -= width;
9560
+ y2 -= width;
6558
9561
  }
6559
- return y;
9562
+ return y2;
6560
9563
  }
6561
9564
  return sankey;
6562
9565
  }
@@ -6797,12 +9800,12 @@ function compileSankey(spec, options) {
6797
9800
  theme,
6798
9801
  fullArea
6799
9802
  );
6800
- const legendGap = legend.entries.length > 0 ? 4 : 0;
9803
+ const legendGap2 = legend.entries.length > 0 ? 4 : 0;
6801
9804
  const area = {
6802
9805
  x: fullArea.x,
6803
- y: fullArea.y + legend.bounds.height + legendGap,
9806
+ y: fullArea.y + legend.bounds.height + legendGap2,
6804
9807
  width: fullArea.width,
6805
- height: fullArea.height - legend.bounds.height - legendGap
9808
+ height: fullArea.height - legend.bounds.height - legendGap2
6806
9809
  };
6807
9810
  if (area.height <= 0) {
6808
9811
  return emptyLayout(area, chrome, theme, options, watermark);
@@ -6824,7 +9827,7 @@ function compileSankey(spec, options) {
6824
9827
  sankeySpec.nodeSort
6825
9828
  );
6826
9829
  const nodeLabelAlign = sankeySpec.nodeLabelAlign ?? "auto";
6827
- const maxDepthFirst = nodes.reduce((max3, n) => Math.max(max3, n.depth ?? 0), 0);
9830
+ const maxDepthFirst = nodes.reduce((max4, n) => Math.max(max4, n.depth ?? 0), 0);
6828
9831
  const rightEdge = area.x + area.width;
6829
9832
  let maxOverflow = 0;
6830
9833
  for (const node of nodes) {
@@ -6833,7 +9836,7 @@ function compileSankey(spec, options) {
6833
9836
  if (labelsLeft) continue;
6834
9837
  const labelX = (node.x1 ?? nodeWidth) + LABEL_GAP;
6835
9838
  const labelText = node.label ?? node.id;
6836
- const labelWidth = estimateTextWidth6(labelText, labelFontSize, labelFontWeight);
9839
+ const labelWidth = estimateTextWidth11(labelText, labelFontSize, labelFontWeight);
6837
9840
  const overflow = labelX + labelWidth - rightEdge;
6838
9841
  if (overflow > maxOverflow) maxOverflow = overflow;
6839
9842
  }
@@ -6866,7 +9869,7 @@ function compileSankey(spec, options) {
6866
9869
  sourceField,
6867
9870
  targetField
6868
9871
  );
6869
- const maxDepth = nodes.reduce((max3, n) => Math.max(max3, n.depth ?? 0), 0);
9872
+ const maxDepth = nodes.reduce((max4, n) => Math.max(max4, n.depth ?? 0), 0);
6870
9873
  const nodeMarks = nodes.map((node) => {
6871
9874
  const fill = nodeColorMap.get(node.id) ?? theme.colors.categorical[0];
6872
9875
  const depth = node.depth ?? 0;
@@ -6960,7 +9963,8 @@ function compileSankey(spec, options) {
6960
9963
  height: options.height
6961
9964
  },
6962
9965
  animation: resolvedAnimation,
6963
- watermark
9966
+ watermark,
9967
+ measureText: options.measureText
6964
9968
  };
6965
9969
  }
6966
9970
  function buildSankeyLegend(nodeColorMap, colorField, data, sourceField, targetField, theme, area) {
@@ -7022,10 +10026,10 @@ function buildSankeyLegend(nodeColorMap, colorField, data, sourceField, targetFi
7022
10026
  }
7023
10027
  function formatFlowValue(value2, valueFormat) {
7024
10028
  if (valueFormat) {
7025
- const fmt = buildD3Formatter2(valueFormat);
10029
+ const fmt = buildD3Formatter5(valueFormat);
7026
10030
  if (fmt) return fmt(value2);
7027
10031
  }
7028
- return formatNumber2(value2);
10032
+ return formatNumber3(value2);
7029
10033
  }
7030
10034
  function buildTooltipDescriptors(nodes, links, valueFormat) {
7031
10035
  const descriptors = /* @__PURE__ */ new Map();
@@ -7094,7 +10098,7 @@ function emptyLayout(area, chrome, theme, options, watermark) {
7094
10098
  }
7095
10099
 
7096
10100
  // src/tables/compile-table.ts
7097
- import { computeChrome as computeChrome4, estimateTextWidth as estimateTextWidth7 } from "@opendata-ai/openchart-core";
10101
+ import { computeChrome as computeChrome4, estimateTextWidth as estimateTextWidth12 } from "@opendata-ai/openchart-core";
7098
10102
 
7099
10103
  // src/tables/bar-column.ts
7100
10104
  var NEGATIVE_BAR_COLOR = "#c44e52";
@@ -7132,24 +10136,24 @@ function computeBarCell(value2, config, columnMax, columnMin, theme, _darkMode)
7132
10136
  };
7133
10137
  }
7134
10138
  function computeColumnMax(data, key) {
7135
- let max3 = 0;
10139
+ let max4 = 0;
7136
10140
  for (const row of data) {
7137
10141
  const val = row[key];
7138
- if (typeof val === "number" && Number.isFinite(val) && val > max3) {
7139
- max3 = val;
10142
+ if (typeof val === "number" && Number.isFinite(val) && val > max4) {
10143
+ max4 = val;
7140
10144
  }
7141
10145
  }
7142
- return max3;
10146
+ return max4;
7143
10147
  }
7144
10148
  function computeColumnMin(data, key) {
7145
- let min3 = 0;
10149
+ let min4 = 0;
7146
10150
  for (const row of data) {
7147
10151
  const val = row[key];
7148
- if (typeof val === "number" && Number.isFinite(val) && val < min3) {
7149
- min3 = val;
10152
+ if (typeof val === "number" && Number.isFinite(val) && val < min4) {
10153
+ min4 = val;
7150
10154
  }
7151
10155
  }
7152
- return min3;
10156
+ return min4;
7153
10157
  }
7154
10158
 
7155
10159
  // src/tables/category-colors.ts
@@ -7211,7 +10215,7 @@ function computeCategoryColors(data, column, theme, darkMode) {
7211
10215
  }
7212
10216
 
7213
10217
  // src/tables/format-cells.ts
7214
- import { buildD3Formatter as buildD3Formatter3, formatDate as formatDate2, formatNumber as formatNumber3 } from "@opendata-ai/openchart-core";
10218
+ import { buildD3Formatter as buildD3Formatter6, formatDate as formatDate2, formatNumber as formatNumber4 } from "@opendata-ai/openchart-core";
7215
10219
  function isNumericValue(value2) {
7216
10220
  if (typeof value2 === "number") return Number.isFinite(value2);
7217
10221
  return false;
@@ -7230,7 +10234,7 @@ function formatCell(value2, column) {
7230
10234
  };
7231
10235
  }
7232
10236
  if (column.format && isNumericValue(value2)) {
7233
- const formatter = buildD3Formatter3(column.format);
10237
+ const formatter = buildD3Formatter6(column.format);
7234
10238
  if (formatter) {
7235
10239
  return {
7236
10240
  value: value2,
@@ -7242,7 +10246,7 @@ function formatCell(value2, column) {
7242
10246
  if (isNumericValue(value2)) {
7243
10247
  return {
7244
10248
  value: value2,
7245
- formattedValue: formatNumber3(value2),
10249
+ formattedValue: formatNumber4(value2),
7246
10250
  style
7247
10251
  };
7248
10252
  }
@@ -7262,13 +10266,13 @@ function formatCell(value2, column) {
7262
10266
  function formatValueForSearch(value2, column) {
7263
10267
  if (value2 == null) return "";
7264
10268
  if (column.format && isNumericValue(value2)) {
7265
- const formatter = buildD3Formatter3(column.format);
10269
+ const formatter = buildD3Formatter6(column.format);
7266
10270
  if (formatter) {
7267
10271
  return formatter(value2);
7268
10272
  }
7269
10273
  }
7270
10274
  if (isNumericValue(value2)) {
7271
- return formatNumber3(value2);
10275
+ return formatNumber4(value2);
7272
10276
  }
7273
10277
  return String(value2);
7274
10278
  }
@@ -7315,13 +10319,13 @@ function computeHeatmapColors(data, column, theme, darkMode) {
7315
10319
  if (config.domain) {
7316
10320
  domain = config.domain;
7317
10321
  } else {
7318
- let min3 = Infinity;
7319
- let max3 = -Infinity;
10322
+ let min4 = Infinity;
10323
+ let max4 = -Infinity;
7320
10324
  for (const { value: value2 } of numericValues) {
7321
- if (value2 < min3) min3 = value2;
7322
- if (value2 > max3) max3 = value2;
10325
+ if (value2 < min4) min4 = value2;
10326
+ if (value2 > max4) max4 = value2;
7323
10327
  }
7324
- domain = [min3, max3];
10328
+ domain = [min4, max4];
7325
10329
  }
7326
10330
  let stops = resolvePalette(config.palette, theme);
7327
10331
  if (darkMode) {
@@ -7437,14 +10441,14 @@ function computeSparkline(values, config, theme, _darkMode) {
7437
10441
  if (values.length === 0) return null;
7438
10442
  const type = config.type ?? "line";
7439
10443
  const color2 = config.color ?? theme.colors.categorical[0];
7440
- let min3 = Infinity;
7441
- let max3 = -Infinity;
10444
+ let min4 = Infinity;
10445
+ let max4 = -Infinity;
7442
10446
  for (const v of values) {
7443
- if (v < min3) min3 = v;
7444
- if (v > max3) max3 = v;
10447
+ if (v < min4) min4 = v;
10448
+ if (v > max4) max4 = v;
7445
10449
  }
7446
- const range2 = max3 - min3;
7447
- const normalize2 = (v) => range2 === 0 ? 0.5 : (v - min3) / range2;
10450
+ const range2 = max4 - min4;
10451
+ const normalize2 = (v) => range2 === 0 ? 0.5 : (v - min4) / range2;
7448
10452
  const startValue = values[0];
7449
10453
  const endValue = values[values.length - 1];
7450
10454
  if (type === "line") {
@@ -7509,13 +10513,13 @@ function estimateColumnWidth(col, data, fontSize) {
7509
10513
  if (col.image) return (col.image.width ?? 24) + PADDING;
7510
10514
  if (col.flag) return 60;
7511
10515
  const label = col.label ?? col.key;
7512
- const headerWidth = estimateTextWidth7(label, fontSize, 600) + PADDING;
10516
+ const headerWidth = estimateTextWidth12(label, fontSize, 600) + PADDING;
7513
10517
  const sampleSize = Math.min(100, data.length);
7514
10518
  let maxDataWidth = 0;
7515
10519
  for (let i = 0; i < sampleSize; i++) {
7516
10520
  const val = data[i][col.key];
7517
10521
  const text = val == null ? "" : String(val);
7518
- const width = estimateTextWidth7(text, fontSize, 400) + PADDING;
10522
+ const width = estimateTextWidth12(text, fontSize, 400) + PADDING;
7519
10523
  if (width > maxDataWidth) maxDataWidth = width;
7520
10524
  }
7521
10525
  return Math.max(MIN_WIDTH, headerWidth, maxDataWidth);
@@ -7743,8 +10747,8 @@ function compileTableLayout(spec, options, theme) {
7743
10747
  import {
7744
10748
  buildTemporalFormatter as buildTemporalFormatter2,
7745
10749
  formatDate as formatDate3,
7746
- formatNumber as formatNumber4,
7747
- getRepresentativeColor
10750
+ formatNumber as formatNumber5,
10751
+ getRepresentativeColor as getRepresentativeColor10
7748
10752
  } from "@opendata-ai/openchart-core";
7749
10753
  function formatValue(value2, fieldType, format2) {
7750
10754
  if (value2 == null) return "";
@@ -7758,10 +10762,10 @@ function formatValue(value2, fieldType, format2) {
7758
10762
  try {
7759
10763
  return format(format2)(value2);
7760
10764
  } catch {
7761
- return formatNumber4(value2);
10765
+ return formatNumber5(value2);
7762
10766
  }
7763
10767
  }
7764
- return formatNumber4(value2);
10768
+ return formatNumber5(value2);
7765
10769
  }
7766
10770
  return String(value2);
7767
10771
  }
@@ -7860,12 +10864,12 @@ function tooltipsForLine(mark, encoding, _markIndex) {
7860
10864
  }
7861
10865
  function tooltipsForPoint(mark, encoding, markIndex) {
7862
10866
  const title = getTooltipTitle(mark.data, encoding);
7863
- const fields = buildFields(mark.data, encoding, getRepresentativeColor(mark.fill));
10867
+ const fields = buildFields(mark.data, encoding, getRepresentativeColor10(mark.fill));
7864
10868
  return [[`point-${markIndex}`, { title, fields }]];
7865
10869
  }
7866
10870
  function tooltipsForRect(mark, encoding, markIndex) {
7867
10871
  const title = getTooltipTitle(mark.data, encoding);
7868
- const fields = buildFields(mark.data, encoding, getRepresentativeColor(mark.fill));
10872
+ const fields = buildFields(mark.data, encoding, getRepresentativeColor10(mark.fill));
7869
10873
  return [[`rect-${markIndex}`, { title, fields }]];
7870
10874
  }
7871
10875
  function tooltipsForArc(mark, encoding, markIndex) {
@@ -7878,14 +10882,14 @@ function tooltipsForArc(mark, encoding, markIndex) {
7878
10882
  fields.push({
7879
10883
  label: categoryName,
7880
10884
  value: formatValue(row[encoding.y.field], encoding.y.type, resolveFormat(encoding.y)),
7881
- color: getRepresentativeColor(mark.fill)
10885
+ color: getRepresentativeColor10(mark.fill)
7882
10886
  });
7883
10887
  }
7884
10888
  } else if (encoding.y) {
7885
10889
  fields.push({
7886
10890
  label: resolveLabel(encoding.y),
7887
10891
  value: formatValue(row[encoding.y.field], encoding.y.type, resolveFormat(encoding.y)),
7888
- color: getRepresentativeColor(mark.fill)
10892
+ color: getRepresentativeColor10(mark.fill)
7889
10893
  });
7890
10894
  }
7891
10895
  const title = colorEnc ? String(row[colorEnc.field] ?? "") : void 0;
@@ -7896,7 +10900,7 @@ function tooltipsForArea(mark, encoding, _markIndex) {
7896
10900
  for (const dp of mark.dataPoints) {
7897
10901
  dp.tooltip = {
7898
10902
  title: getTooltipTitle(dp.datum, encoding),
7899
- fields: buildFields(dp.datum, encoding, getRepresentativeColor(mark.fill))
10903
+ fields: buildFields(dp.datum, encoding, getRepresentativeColor10(mark.fill))
7900
10904
  };
7901
10905
  }
7902
10906
  }
@@ -8046,16 +11050,16 @@ function runBin(data, transform) {
8046
11050
  const field = transform.field;
8047
11051
  let extent2 = params.extent;
8048
11052
  if (!extent2) {
8049
- let min3 = Infinity;
8050
- let max3 = -Infinity;
11053
+ let min4 = Infinity;
11054
+ let max4 = -Infinity;
8051
11055
  for (const row of data) {
8052
11056
  const v = Number(row[field]);
8053
11057
  if (Number.isFinite(v)) {
8054
- if (v < min3) min3 = v;
8055
- if (v > max3) max3 = v;
11058
+ if (v < min4) min4 = v;
11059
+ if (v > max4) max4 = v;
8056
11060
  }
8057
11061
  }
8058
- extent2 = [min3 === Infinity ? 0 : min3, max3 === -Infinity ? 0 : max3];
11062
+ extent2 = [min4 === Infinity ? 0 : min4, max4 === -Infinity ? 0 : max4];
8059
11063
  }
8060
11064
  const step = params.step ?? computeStep(extent2, maxbins, nice2);
8061
11065
  const [startAs, endAs] = Array.isArray(transform.as) ? transform.as : [transform.as, void 0];
@@ -8351,13 +11355,14 @@ function compileChart(spec, options) {
8351
11355
  const chartArea = dims.chartArea;
8352
11356
  const legendArea = { ...chartArea };
8353
11357
  if (legendLayout.entries.length > 0) {
11358
+ const gap = legendGap(options.width);
8354
11359
  switch (legendLayout.position) {
8355
11360
  case "top":
8356
- legendArea.y -= legendLayout.bounds.height + 4;
8357
- legendArea.height += legendLayout.bounds.height + 4;
11361
+ legendArea.y -= legendLayout.bounds.height + gap;
11362
+ legendArea.height += legendLayout.bounds.height + gap;
8358
11363
  break;
8359
11364
  case "bottom":
8360
- legendArea.height += legendLayout.bounds.height + 4;
11365
+ legendArea.height += legendLayout.bounds.height + gap;
8361
11366
  break;
8362
11367
  case "right":
8363
11368
  case "bottom-right":