@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 +3425 -420
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
- package/src/__tests__/axes.test.ts +25 -4
- package/src/__tests__/dimensions.test.ts +48 -0
- package/src/__tests__/legend.test.ts +52 -25
- package/src/charts/dot/__tests__/compute.test.ts +31 -0
- package/src/charts/dot/compute.ts +6 -1
- package/src/compile.ts +5 -3
- package/src/layout/axes.ts +10 -5
- package/src/layout/dimensions.ts +15 -4
- package/src/legend/compute.ts +35 -9
- package/src/legend/wrap.ts +13 -2
- package/src/sankey/compile-sankey.ts +1 -0
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
|
|
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
|
|
399
|
-
let
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
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:
|
|
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
|
-
|
|
605
|
-
|
|
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
|
-
|
|
608
|
-
|
|
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
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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
|
-
|
|
615
|
-
|
|
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
|
|
2997
|
+
return result;
|
|
618
2998
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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
|
-
|
|
624
|
-
|
|
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 (
|
|
627
|
-
|
|
3063
|
+
if (otherValue > 0) {
|
|
3064
|
+
big.push({
|
|
3065
|
+
label: "Other",
|
|
3066
|
+
value: otherValue,
|
|
3067
|
+
originalRow: { label: "Other", value: otherValue }
|
|
3068
|
+
});
|
|
628
3069
|
}
|
|
629
|
-
|
|
630
|
-
|
|
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
|
|
3171
|
+
return marks;
|
|
633
3172
|
}
|
|
634
3173
|
|
|
635
|
-
// src/
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
680
|
-
delta = (d,
|
|
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,
|
|
3371
|
+
function left2(a, x2, lo = 0, hi = a.length) {
|
|
687
3372
|
if (lo < hi) {
|
|
688
|
-
if (compare1(
|
|
3373
|
+
if (compare1(x2, x2) !== 0) return hi;
|
|
689
3374
|
do {
|
|
690
3375
|
const mid = lo + hi >>> 1;
|
|
691
|
-
if (compare2(a[mid],
|
|
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,
|
|
3382
|
+
function right2(a, x2, lo = 0, hi = a.length) {
|
|
698
3383
|
if (lo < hi) {
|
|
699
|
-
if (compare1(
|
|
3384
|
+
if (compare1(x2, x2) !== 0) return hi;
|
|
700
3385
|
do {
|
|
701
3386
|
const mid = lo + hi >>> 1;
|
|
702
|
-
if (compare2(a[mid],
|
|
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,
|
|
709
|
-
const i = left2(a,
|
|
710
|
-
return i > lo && delta(a[i - 1],
|
|
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(
|
|
720
|
-
return
|
|
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
|
|
733
|
-
let
|
|
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 (
|
|
738
|
-
if (value2 >= value2)
|
|
3422
|
+
if (min4 === void 0) {
|
|
3423
|
+
if (value2 >= value2) min4 = max4 = value2;
|
|
739
3424
|
} else {
|
|
740
|
-
if (
|
|
741
|
-
if (
|
|
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 (
|
|
750
|
-
if (value2 >= value2)
|
|
3434
|
+
if (min4 === void 0) {
|
|
3435
|
+
if (value2 >= value2) min4 = max4 = value2;
|
|
751
3436
|
} else {
|
|
752
|
-
if (
|
|
753
|
-
if (
|
|
3437
|
+
if (min4 > value2) min4 = value2;
|
|
3438
|
+
if (max4 < value2) max4 = value2;
|
|
754
3439
|
}
|
|
755
3440
|
}
|
|
756
3441
|
}
|
|
757
3442
|
}
|
|
758
|
-
return [
|
|
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
|
|
855
|
-
let
|
|
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 && (
|
|
859
|
-
|
|
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 && (
|
|
866
|
-
|
|
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
|
|
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
|
|
875
|
-
let
|
|
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 && (
|
|
879
|
-
|
|
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 && (
|
|
886
|
-
|
|
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
|
|
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
|
|
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,
|
|
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 ===
|
|
1334
|
-
else if (g ===
|
|
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 ?
|
|
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
|
|
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
|
|
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,
|
|
1424
|
-
return a = Math.pow(a,
|
|
1425
|
-
return Math.pow(a + t * b,
|
|
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(
|
|
1429
|
-
return (
|
|
1430
|
-
return b - a ? exponential(a, b,
|
|
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) :
|
|
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(
|
|
1440
|
-
var color2 = gamma(
|
|
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(
|
|
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(
|
|
1488
|
-
return ArrayBuffer.isView(
|
|
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,
|
|
1494
|
-
for (i = 0; i < na; ++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] =
|
|
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" ?
|
|
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(
|
|
4276
|
+
function constants(x2) {
|
|
1592
4277
|
return function() {
|
|
1593
|
-
return
|
|
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(
|
|
1599
|
-
return +
|
|
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(
|
|
1605
|
-
return
|
|
4289
|
+
function identity(x2) {
|
|
4290
|
+
return x2;
|
|
1606
4291
|
}
|
|
1607
4292
|
function normalize(a, b) {
|
|
1608
|
-
return (b -= a = +a) ? function(
|
|
1609
|
-
return (
|
|
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(
|
|
1616
|
-
return Math.max(a, Math.min(b,
|
|
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(
|
|
1624
|
-
return r0(d0(
|
|
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(
|
|
1638
|
-
var i2 = bisect_default(domain,
|
|
1639
|
-
return r[i2](d[i2](
|
|
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(
|
|
1655
|
-
return
|
|
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(
|
|
1658
|
-
return clamp(untransform((input || (input = piecewise(range2, domain.map(transform), number_default)))(
|
|
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(
|
|
1689
|
-
return Math.abs(
|
|
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(
|
|
1692
|
-
if (!isFinite(
|
|
1693
|
-
var 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
|
-
+
|
|
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(
|
|
1702
|
-
return
|
|
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(
|
|
1786
|
-
var d = formatDecimalParts(
|
|
1787
|
-
if (!d) return prefixExponent = void 0,
|
|
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(
|
|
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(
|
|
1794
|
-
var d = formatDecimalParts(
|
|
1795
|
-
if (!d) return
|
|
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
|
-
"%": (
|
|
1803
|
-
"b": (
|
|
1804
|
-
"c": (
|
|
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": (
|
|
1807
|
-
"f": (
|
|
1808
|
-
"g": (
|
|
1809
|
-
"o": (
|
|
1810
|
-
"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": (
|
|
1814
|
-
"x": (
|
|
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
|
|
1819
|
-
return
|
|
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 ?
|
|
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,
|
|
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 &&
|
|
1847
|
-
valuePrefix = (valueNegative ?
|
|
1848
|
-
valueSuffix = (type === "s" && !isNaN(value2) && prefixExponent !== void 0 ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative &&
|
|
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,
|
|
1924
|
-
step = Math.abs(step),
|
|
1925
|
-
return Math.max(0, exponent_default(
|
|
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(
|
|
2025
|
-
return Math.log(
|
|
4709
|
+
function transformLog(x2) {
|
|
4710
|
+
return Math.log(x2);
|
|
2026
4711
|
}
|
|
2027
|
-
function transformExp(
|
|
2028
|
-
return Math.exp(
|
|
4712
|
+
function transformExp(x2) {
|
|
4713
|
+
return Math.exp(x2);
|
|
2029
4714
|
}
|
|
2030
|
-
function transformLogn(
|
|
2031
|
-
return -Math.log(-
|
|
4715
|
+
function transformLogn(x2) {
|
|
4716
|
+
return -Math.log(-x2);
|
|
2032
4717
|
}
|
|
2033
|
-
function transformExpn(
|
|
2034
|
-
return -Math.exp(-
|
|
4718
|
+
function transformExpn(x2) {
|
|
4719
|
+
return -Math.exp(-x2);
|
|
2035
4720
|
}
|
|
2036
|
-
function pow10(
|
|
2037
|
-
return isFinite(
|
|
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 : (
|
|
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), (
|
|
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 (
|
|
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: (
|
|
2124
|
-
ceil: (
|
|
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(
|
|
2139
|
-
return Math.sign(
|
|
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(
|
|
2144
|
-
return Math.sign(
|
|
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(
|
|
2165
|
-
return
|
|
4849
|
+
return function(x2) {
|
|
4850
|
+
return x2 < 0 ? -Math.pow(-x2, exponent) : Math.pow(x2, exponent);
|
|
2166
4851
|
};
|
|
2167
4852
|
}
|
|
2168
|
-
function transformSqrt(
|
|
2169
|
-
return
|
|
4853
|
+
function transformSqrt(x2) {
|
|
4854
|
+
return x2 < 0 ? -Math.sqrt(-x2) : Math.sqrt(x2);
|
|
2170
4855
|
}
|
|
2171
|
-
function transformSquare(
|
|
2172
|
-
return
|
|
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
|
|
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(
|
|
2206
|
-
return
|
|
4890
|
+
function scale(x2) {
|
|
4891
|
+
return x2 == null || isNaN(x2 = +x2) ? unknown : range2[bisect_default(thresholds, x2)];
|
|
2207
4892
|
}
|
|
2208
|
-
scale.invertExtent = function(
|
|
2209
|
-
var i = range2.indexOf(
|
|
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(
|
|
2241
|
-
return
|
|
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(
|
|
2256
|
-
var i = range2.indexOf(
|
|
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(
|
|
2275
|
-
return
|
|
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(
|
|
2284
|
-
var i = range2.indexOf(
|
|
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(
|
|
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
|
|
2937
|
-
return
|
|
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(
|
|
3210
|
-
return new Date(invert(
|
|
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(
|
|
3245
|
-
return
|
|
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
|
|
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 =
|
|
4527
|
-
const sizeMax =
|
|
4528
|
-
sizeScale =
|
|
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 =
|
|
4538
|
-
const colorMax =
|
|
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 ??
|
|
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 =
|
|
4602
|
-
const widthMax =
|
|
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 =
|
|
4613
|
-
const colorMax =
|
|
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
|
|
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 :
|
|
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 [
|
|
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(
|
|
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 =
|
|
7948
|
+
const fmt = buildD3Formatter4(formatStr);
|
|
4977
7949
|
if (fmt) return fmt(num);
|
|
4978
7950
|
}
|
|
4979
|
-
if (Math.abs(num) >= 1e3) return
|
|
4980
|
-
return
|
|
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
|
|
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
|
|
8186
|
+
const shouldThinY = scales.y.type !== "band" && !axisConfig?.values;
|
|
5214
8187
|
let ticks2;
|
|
5215
|
-
if (!
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 +
|
|
8453
|
+
margins.top += legendLayout.bounds.height + gap;
|
|
5432
8454
|
} else if (legendLayout.position === "bottom") {
|
|
5433
|
-
margins.bottom += legendLayout.bounds.height +
|
|
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
|
-
|
|
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 =
|
|
5569
|
-
domainMax =
|
|
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] :
|
|
5585
|
-
const domainMax = channel.scale?.domain ? channel.scale.domain[1] :
|
|
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 =
|
|
5604
|
-
domainMax =
|
|
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 =
|
|
5628
|
-
domainMax =
|
|
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 =
|
|
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 =
|
|
5649
|
-
domainMax =
|
|
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] :
|
|
5674
|
-
const domainMax = channel.scale?.domain ? channel.scale.domain[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 =
|
|
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 =
|
|
5727
|
-
const domainMax =
|
|
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
|
|
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
|
|
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
|
|
6049
|
-
const isStacked =
|
|
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) =>
|
|
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
|
|
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(
|
|
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 =
|
|
6127
|
-
return sum2 + SWATCH_SIZE2 + SWATCH_GAP2 + labelWidth +
|
|
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(
|
|
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 +
|
|
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:
|
|
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
|
|
9156
|
+
buildD3Formatter as buildD3Formatter5,
|
|
6154
9157
|
computeChrome as computeChrome3,
|
|
6155
|
-
estimateTextWidth as
|
|
6156
|
-
formatNumber as
|
|
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
|
|
6162
|
-
let
|
|
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 && (
|
|
6166
|
-
|
|
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 && (
|
|
6173
|
-
|
|
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
|
|
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
|
|
6182
|
-
let
|
|
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 && (
|
|
6186
|
-
|
|
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 && (
|
|
6193
|
-
|
|
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
|
|
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 ?
|
|
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(
|
|
9241
|
+
function constant(x2) {
|
|
6239
9242
|
return function() {
|
|
6240
|
-
return
|
|
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
|
|
9377
|
+
let x2 = 0;
|
|
6375
9378
|
while (current.size) {
|
|
6376
9379
|
for (const node of current) {
|
|
6377
|
-
node.depth =
|
|
9380
|
+
node.depth = x2;
|
|
6378
9381
|
for (const { target } of node.sourceLinks) {
|
|
6379
9382
|
next.add(target);
|
|
6380
9383
|
}
|
|
6381
9384
|
}
|
|
6382
|
-
if (++
|
|
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
|
|
9394
|
+
let x2 = 0;
|
|
6392
9395
|
while (current.size) {
|
|
6393
9396
|
for (const node of current) {
|
|
6394
|
-
node.height =
|
|
9397
|
+
node.height = x2;
|
|
6395
9398
|
for (const { source } of node.targetLinks) {
|
|
6396
9399
|
next.add(source);
|
|
6397
9400
|
}
|
|
6398
9401
|
}
|
|
6399
|
-
if (++
|
|
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
|
|
6406
|
-
const kx = (x1 - x0 - dx) / (
|
|
6407
|
-
const columns = new Array(
|
|
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(
|
|
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 =
|
|
9425
|
+
const ky = min3(columns, (c) => (y1 - y0 - (c.length - 1) * py) / sum(c, value));
|
|
6423
9426
|
for (const nodes2 of columns) {
|
|
6424
|
-
let
|
|
9427
|
+
let y2 = y0;
|
|
6425
9428
|
for (const node of nodes2) {
|
|
6426
|
-
node.y0 =
|
|
6427
|
-
node.y1 =
|
|
6428
|
-
|
|
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
|
-
|
|
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 +=
|
|
6437
|
-
node.y1 +=
|
|
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) / (
|
|
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
|
|
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
|
-
|
|
9464
|
+
y2 += targetTop(source, target) * v;
|
|
6462
9465
|
w += v;
|
|
6463
9466
|
}
|
|
6464
9467
|
if (!(w > 0)) continue;
|
|
6465
|
-
let dy2 = (
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
9485
|
+
y2 += sourceTop(source, target) * v;
|
|
6483
9486
|
w += v;
|
|
6484
9487
|
}
|
|
6485
9488
|
if (!(w > 0)) continue;
|
|
6486
|
-
let dy2 = (
|
|
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
|
-
|
|
9495
|
+
resolveCollisions6(column, beta);
|
|
6493
9496
|
}
|
|
6494
9497
|
}
|
|
6495
|
-
function
|
|
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,
|
|
9506
|
+
function resolveCollisionsTopToBottom(nodes2, y2, i, alpha) {
|
|
6504
9507
|
for (; i < nodes2.length; ++i) {
|
|
6505
9508
|
const node = nodes2[i];
|
|
6506
|
-
const dy2 = (
|
|
9509
|
+
const dy2 = (y2 - node.y0) * alpha;
|
|
6507
9510
|
if (dy2 > 1e-6) node.y0 += dy2, node.y1 += dy2;
|
|
6508
|
-
|
|
9511
|
+
y2 = node.y1 + py;
|
|
6509
9512
|
}
|
|
6510
9513
|
}
|
|
6511
|
-
function resolveCollisionsBottomToTop(nodes2,
|
|
9514
|
+
function resolveCollisionsBottomToTop(nodes2, y2, i, alpha) {
|
|
6512
9515
|
for (; i >= 0; --i) {
|
|
6513
9516
|
const node = nodes2[i];
|
|
6514
|
-
const dy2 = (node.y1 -
|
|
9517
|
+
const dy2 = (node.y1 - y2) * alpha;
|
|
6515
9518
|
if (dy2 > 1e-6) node.y0 -= dy2, node.y1 -= dy2;
|
|
6516
|
-
|
|
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
|
|
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
|
-
|
|
9544
|
+
y2 += width + py;
|
|
6542
9545
|
}
|
|
6543
9546
|
for (const { source: node, width } of target.targetLinks) {
|
|
6544
9547
|
if (node === source) break;
|
|
6545
|
-
|
|
9548
|
+
y2 -= width;
|
|
6546
9549
|
}
|
|
6547
|
-
return
|
|
9550
|
+
return y2;
|
|
6548
9551
|
}
|
|
6549
9552
|
function sourceTop(source, target) {
|
|
6550
|
-
let
|
|
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
|
-
|
|
9556
|
+
y2 += width + py;
|
|
6554
9557
|
}
|
|
6555
9558
|
for (const { target: node, width } of source.sourceLinks) {
|
|
6556
9559
|
if (node === target) break;
|
|
6557
|
-
|
|
9560
|
+
y2 -= width;
|
|
6558
9561
|
}
|
|
6559
|
-
return
|
|
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
|
|
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 +
|
|
9806
|
+
y: fullArea.y + legend.bounds.height + legendGap2,
|
|
6804
9807
|
width: fullArea.width,
|
|
6805
|
-
height: fullArea.height - legend.bounds.height -
|
|
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((
|
|
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 =
|
|
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((
|
|
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 =
|
|
10029
|
+
const fmt = buildD3Formatter5(valueFormat);
|
|
7026
10030
|
if (fmt) return fmt(value2);
|
|
7027
10031
|
}
|
|
7028
|
-
return
|
|
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
|
|
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
|
|
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 >
|
|
7139
|
-
|
|
10142
|
+
if (typeof val === "number" && Number.isFinite(val) && val > max4) {
|
|
10143
|
+
max4 = val;
|
|
7140
10144
|
}
|
|
7141
10145
|
}
|
|
7142
|
-
return
|
|
10146
|
+
return max4;
|
|
7143
10147
|
}
|
|
7144
10148
|
function computeColumnMin(data, key) {
|
|
7145
|
-
let
|
|
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 <
|
|
7149
|
-
|
|
10152
|
+
if (typeof val === "number" && Number.isFinite(val) && val < min4) {
|
|
10153
|
+
min4 = val;
|
|
7150
10154
|
}
|
|
7151
10155
|
}
|
|
7152
|
-
return
|
|
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
|
|
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 =
|
|
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:
|
|
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 =
|
|
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
|
|
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
|
|
7319
|
-
let
|
|
10322
|
+
let min4 = Infinity;
|
|
10323
|
+
let max4 = -Infinity;
|
|
7320
10324
|
for (const { value: value2 } of numericValues) {
|
|
7321
|
-
if (value2 <
|
|
7322
|
-
if (value2 >
|
|
10325
|
+
if (value2 < min4) min4 = value2;
|
|
10326
|
+
if (value2 > max4) max4 = value2;
|
|
7323
10327
|
}
|
|
7324
|
-
domain = [
|
|
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
|
|
7441
|
-
let
|
|
10444
|
+
let min4 = Infinity;
|
|
10445
|
+
let max4 = -Infinity;
|
|
7442
10446
|
for (const v of values) {
|
|
7443
|
-
if (v <
|
|
7444
|
-
if (v >
|
|
10447
|
+
if (v < min4) min4 = v;
|
|
10448
|
+
if (v > max4) max4 = v;
|
|
7445
10449
|
}
|
|
7446
|
-
const range2 =
|
|
7447
|
-
const normalize2 = (v) => range2 === 0 ? 0.5 : (v -
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
10765
|
+
return formatNumber5(value2);
|
|
7762
10766
|
}
|
|
7763
10767
|
}
|
|
7764
|
-
return
|
|
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,
|
|
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,
|
|
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:
|
|
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:
|
|
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,
|
|
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
|
|
8050
|
-
let
|
|
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 <
|
|
8055
|
-
if (v >
|
|
11058
|
+
if (v < min4) min4 = v;
|
|
11059
|
+
if (v > max4) max4 = v;
|
|
8056
11060
|
}
|
|
8057
11061
|
}
|
|
8058
|
-
extent2 = [
|
|
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 +
|
|
8357
|
-
legendArea.height += legendLayout.bounds.height +
|
|
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 +
|
|
11365
|
+
legendArea.height += legendLayout.bounds.height + gap;
|
|
8361
11366
|
break;
|
|
8362
11367
|
case "right":
|
|
8363
11368
|
case "bottom-right":
|