@opendata-ai/openchart-core 7.2.4 → 7.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +91 -11
- package/dist/index.js +469 -138
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/index.ts +9 -0
- package/src/labels/__tests__/collision.test.ts +49 -1
- package/src/labels/collision.ts +39 -2
- package/src/labels/index.ts +1 -0
- package/src/layout/__tests__/text-measure.test.ts +7 -8
- package/src/layout/chrome.ts +5 -1
- package/src/layout/index.ts +3 -0
- package/src/layout/text-measure.ts +347 -38
- package/src/responsive/index.ts +5 -0
- package/src/responsive/metrics.ts +51 -0
- package/src/styles/tokens.css +4 -0
- package/src/theme/defaults.ts +6 -3
- package/src/types/index.ts +1 -0
- package/src/types/layout.ts +26 -0
package/dist/index.js
CHANGED
|
@@ -813,6 +813,441 @@ var DIVERGING_PALETTES = {
|
|
|
813
813
|
brownTeal: [...DIVERGING_BROWN_TEAL.stops]
|
|
814
814
|
};
|
|
815
815
|
|
|
816
|
+
// src/layout/text-measure.ts
|
|
817
|
+
var CHAR_WIDTHS_400 = {
|
|
818
|
+
" ": 0.278,
|
|
819
|
+
"!": 0.278,
|
|
820
|
+
'"': 0.355,
|
|
821
|
+
"#": 0.556,
|
|
822
|
+
$: 0.556,
|
|
823
|
+
"%": 0.889,
|
|
824
|
+
"&": 0.667,
|
|
825
|
+
"'": 0.191,
|
|
826
|
+
"(": 0.333,
|
|
827
|
+
")": 0.333,
|
|
828
|
+
"*": 0.389,
|
|
829
|
+
"+": 0.584,
|
|
830
|
+
",": 0.278,
|
|
831
|
+
"-": 0.333,
|
|
832
|
+
".": 0.278,
|
|
833
|
+
"/": 0.278,
|
|
834
|
+
"0": 0.556,
|
|
835
|
+
"1": 0.556,
|
|
836
|
+
"2": 0.556,
|
|
837
|
+
"3": 0.556,
|
|
838
|
+
"4": 0.556,
|
|
839
|
+
"5": 0.556,
|
|
840
|
+
"6": 0.556,
|
|
841
|
+
"7": 0.556,
|
|
842
|
+
"8": 0.556,
|
|
843
|
+
"9": 0.556,
|
|
844
|
+
":": 0.278,
|
|
845
|
+
";": 0.278,
|
|
846
|
+
"<": 0.584,
|
|
847
|
+
"=": 0.584,
|
|
848
|
+
">": 0.584,
|
|
849
|
+
"?": 0.556,
|
|
850
|
+
"@": 1.015,
|
|
851
|
+
A: 0.667,
|
|
852
|
+
B: 0.667,
|
|
853
|
+
C: 0.722,
|
|
854
|
+
D: 0.722,
|
|
855
|
+
E: 0.667,
|
|
856
|
+
F: 0.611,
|
|
857
|
+
G: 0.778,
|
|
858
|
+
H: 0.722,
|
|
859
|
+
I: 0.278,
|
|
860
|
+
J: 0.5,
|
|
861
|
+
K: 0.667,
|
|
862
|
+
L: 0.556,
|
|
863
|
+
M: 0.833,
|
|
864
|
+
N: 0.722,
|
|
865
|
+
O: 0.778,
|
|
866
|
+
P: 0.667,
|
|
867
|
+
Q: 0.778,
|
|
868
|
+
R: 0.722,
|
|
869
|
+
S: 0.667,
|
|
870
|
+
T: 0.611,
|
|
871
|
+
U: 0.722,
|
|
872
|
+
V: 0.667,
|
|
873
|
+
W: 0.944,
|
|
874
|
+
X: 0.667,
|
|
875
|
+
Y: 0.667,
|
|
876
|
+
Z: 0.611,
|
|
877
|
+
"[": 0.278,
|
|
878
|
+
"\\": 0.278,
|
|
879
|
+
"]": 0.278,
|
|
880
|
+
"^": 0.469,
|
|
881
|
+
_: 0.556,
|
|
882
|
+
"`": 0.333,
|
|
883
|
+
a: 0.556,
|
|
884
|
+
b: 0.556,
|
|
885
|
+
c: 0.5,
|
|
886
|
+
d: 0.556,
|
|
887
|
+
e: 0.556,
|
|
888
|
+
f: 0.278,
|
|
889
|
+
g: 0.556,
|
|
890
|
+
h: 0.556,
|
|
891
|
+
i: 0.222,
|
|
892
|
+
j: 0.222,
|
|
893
|
+
k: 0.5,
|
|
894
|
+
l: 0.222,
|
|
895
|
+
m: 0.833,
|
|
896
|
+
n: 0.556,
|
|
897
|
+
o: 0.556,
|
|
898
|
+
p: 0.556,
|
|
899
|
+
q: 0.556,
|
|
900
|
+
r: 0.333,
|
|
901
|
+
s: 0.5,
|
|
902
|
+
t: 0.278,
|
|
903
|
+
u: 0.556,
|
|
904
|
+
v: 0.5,
|
|
905
|
+
w: 0.722,
|
|
906
|
+
x: 0.5,
|
|
907
|
+
y: 0.5,
|
|
908
|
+
z: 0.5,
|
|
909
|
+
"{": 0.334,
|
|
910
|
+
"|": 0.26,
|
|
911
|
+
"}": 0.334,
|
|
912
|
+
"~": 0.584,
|
|
913
|
+
"\u20B9": 0.52,
|
|
914
|
+
"\u20A9": 1.022,
|
|
915
|
+
"\xA5": 0.556,
|
|
916
|
+
"\uFFE5": 1,
|
|
917
|
+
"\u20AC": 0.744,
|
|
918
|
+
"\xA3": 0.556,
|
|
919
|
+
"\xA2": 0.556,
|
|
920
|
+
"\xA7": 0.556,
|
|
921
|
+
"\xA9": 0.737,
|
|
922
|
+
"\xAE": 0.737,
|
|
923
|
+
"\u2122": 1,
|
|
924
|
+
"\xB0": 0.4,
|
|
925
|
+
"\u2013": 0.556,
|
|
926
|
+
"\u2014": 1,
|
|
927
|
+
"\u2018": 0.222,
|
|
928
|
+
"\u2019": 0.222,
|
|
929
|
+
"\u201C": 0.333,
|
|
930
|
+
"\u201D": 0.333,
|
|
931
|
+
"\u2026": 1,
|
|
932
|
+
"\xB1": 0.549,
|
|
933
|
+
"\xD7": 0.584,
|
|
934
|
+
"\xF7": 0.549
|
|
935
|
+
};
|
|
936
|
+
var AVG_CHAR_WIDTH_400 = 0.53;
|
|
937
|
+
var CHAR_WIDTHS_700 = {
|
|
938
|
+
" ": 0.278,
|
|
939
|
+
"!": 0.333,
|
|
940
|
+
'"': 0.474,
|
|
941
|
+
"#": 0.556,
|
|
942
|
+
$: 0.556,
|
|
943
|
+
"%": 0.889,
|
|
944
|
+
"&": 0.722,
|
|
945
|
+
"'": 0.238,
|
|
946
|
+
"(": 0.333,
|
|
947
|
+
")": 0.333,
|
|
948
|
+
"*": 0.389,
|
|
949
|
+
"+": 0.584,
|
|
950
|
+
",": 0.278,
|
|
951
|
+
"-": 0.333,
|
|
952
|
+
".": 0.278,
|
|
953
|
+
"/": 0.278,
|
|
954
|
+
"0": 0.556,
|
|
955
|
+
"1": 0.556,
|
|
956
|
+
"2": 0.556,
|
|
957
|
+
"3": 0.556,
|
|
958
|
+
"4": 0.556,
|
|
959
|
+
"5": 0.556,
|
|
960
|
+
"6": 0.556,
|
|
961
|
+
"7": 0.556,
|
|
962
|
+
"8": 0.556,
|
|
963
|
+
"9": 0.556,
|
|
964
|
+
":": 0.333,
|
|
965
|
+
";": 0.333,
|
|
966
|
+
"<": 0.584,
|
|
967
|
+
"=": 0.584,
|
|
968
|
+
">": 0.584,
|
|
969
|
+
"?": 0.611,
|
|
970
|
+
"@": 0.975,
|
|
971
|
+
A: 0.722,
|
|
972
|
+
B: 0.722,
|
|
973
|
+
C: 0.722,
|
|
974
|
+
D: 0.722,
|
|
975
|
+
E: 0.667,
|
|
976
|
+
F: 0.611,
|
|
977
|
+
G: 0.778,
|
|
978
|
+
H: 0.722,
|
|
979
|
+
I: 0.278,
|
|
980
|
+
J: 0.556,
|
|
981
|
+
K: 0.722,
|
|
982
|
+
L: 0.611,
|
|
983
|
+
M: 0.833,
|
|
984
|
+
N: 0.722,
|
|
985
|
+
O: 0.778,
|
|
986
|
+
P: 0.667,
|
|
987
|
+
Q: 0.778,
|
|
988
|
+
R: 0.722,
|
|
989
|
+
S: 0.667,
|
|
990
|
+
T: 0.611,
|
|
991
|
+
U: 0.722,
|
|
992
|
+
V: 0.667,
|
|
993
|
+
W: 0.944,
|
|
994
|
+
X: 0.667,
|
|
995
|
+
Y: 0.667,
|
|
996
|
+
Z: 0.611,
|
|
997
|
+
"[": 0.333,
|
|
998
|
+
"\\": 0.278,
|
|
999
|
+
"]": 0.333,
|
|
1000
|
+
"^": 0.584,
|
|
1001
|
+
_: 0.556,
|
|
1002
|
+
"`": 0.333,
|
|
1003
|
+
a: 0.556,
|
|
1004
|
+
b: 0.611,
|
|
1005
|
+
c: 0.556,
|
|
1006
|
+
d: 0.611,
|
|
1007
|
+
e: 0.556,
|
|
1008
|
+
f: 0.333,
|
|
1009
|
+
g: 0.611,
|
|
1010
|
+
h: 0.611,
|
|
1011
|
+
i: 0.278,
|
|
1012
|
+
j: 0.278,
|
|
1013
|
+
k: 0.556,
|
|
1014
|
+
l: 0.278,
|
|
1015
|
+
m: 0.889,
|
|
1016
|
+
n: 0.611,
|
|
1017
|
+
o: 0.611,
|
|
1018
|
+
p: 0.611,
|
|
1019
|
+
q: 0.611,
|
|
1020
|
+
r: 0.389,
|
|
1021
|
+
s: 0.556,
|
|
1022
|
+
t: 0.333,
|
|
1023
|
+
u: 0.611,
|
|
1024
|
+
v: 0.556,
|
|
1025
|
+
w: 0.778,
|
|
1026
|
+
x: 0.556,
|
|
1027
|
+
y: 0.556,
|
|
1028
|
+
z: 0.5,
|
|
1029
|
+
"{": 0.389,
|
|
1030
|
+
"|": 0.28,
|
|
1031
|
+
"}": 0.389,
|
|
1032
|
+
"~": 0.584,
|
|
1033
|
+
"\u20B9": 0.553,
|
|
1034
|
+
"\u20A9": 1.024,
|
|
1035
|
+
"\xA5": 0.556,
|
|
1036
|
+
"\uFFE5": 1,
|
|
1037
|
+
"\u20AC": 0.744,
|
|
1038
|
+
"\xA3": 0.556,
|
|
1039
|
+
"\xA2": 0.556,
|
|
1040
|
+
"\xA7": 0.556,
|
|
1041
|
+
"\xA9": 0.737,
|
|
1042
|
+
"\xAE": 0.737,
|
|
1043
|
+
"\u2122": 1,
|
|
1044
|
+
"\xB0": 0.4,
|
|
1045
|
+
"\u2013": 0.556,
|
|
1046
|
+
"\u2014": 1,
|
|
1047
|
+
"\u2018": 0.278,
|
|
1048
|
+
"\u2019": 0.278,
|
|
1049
|
+
"\u201C": 0.5,
|
|
1050
|
+
"\u201D": 0.5,
|
|
1051
|
+
"\u2026": 1,
|
|
1052
|
+
"\xB1": 0.549,
|
|
1053
|
+
"\xD7": 0.584,
|
|
1054
|
+
"\xF7": 0.549
|
|
1055
|
+
};
|
|
1056
|
+
var AVG_CHAR_WIDTH_700 = 0.554;
|
|
1057
|
+
var WEIGHT_ADJUSTMENT = {
|
|
1058
|
+
100: 0.9,
|
|
1059
|
+
200: 0.92,
|
|
1060
|
+
300: 0.95,
|
|
1061
|
+
400: 1,
|
|
1062
|
+
500: 1.02,
|
|
1063
|
+
600: 1.05,
|
|
1064
|
+
700: 1,
|
|
1065
|
+
// uses CHAR_WIDTHS_700 directly
|
|
1066
|
+
800: 1.1,
|
|
1067
|
+
900: 1.12
|
|
1068
|
+
};
|
|
1069
|
+
function resolveTable(fontWeight) {
|
|
1070
|
+
if (fontWeight >= 650) {
|
|
1071
|
+
return {
|
|
1072
|
+
table: CHAR_WIDTHS_700,
|
|
1073
|
+
avg: AVG_CHAR_WIDTH_700,
|
|
1074
|
+
scale: WEIGHT_ADJUSTMENT[fontWeight] ?? 1
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
return {
|
|
1078
|
+
table: CHAR_WIDTHS_400,
|
|
1079
|
+
avg: AVG_CHAR_WIDTH_400,
|
|
1080
|
+
scale: WEIGHT_ADJUSTMENT[fontWeight] ?? 1
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
function charWidthRatio(ch, table, avg) {
|
|
1084
|
+
const direct = table[ch];
|
|
1085
|
+
if (direct !== void 0) return direct;
|
|
1086
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
1087
|
+
if (code >= 768 && code <= 879 || code >= 6832 && code <= 6911) return 0;
|
|
1088
|
+
if (code >= 4352 && code <= 4607 || code >= 11904 && code <= 40959 || code >= 44032 && code <= 55215 || code >= 63744 && code <= 64255 || code >= 65280 && code <= 65376)
|
|
1089
|
+
return 1;
|
|
1090
|
+
return avg;
|
|
1091
|
+
}
|
|
1092
|
+
function estimateCharWidth(fontSize, fontWeight = 400) {
|
|
1093
|
+
const { avg, scale } = resolveTable(fontWeight);
|
|
1094
|
+
return fontSize * avg * scale;
|
|
1095
|
+
}
|
|
1096
|
+
function estimateTextWidth(text, fontSize, fontWeight = 400) {
|
|
1097
|
+
const { table, avg, scale } = resolveTable(fontWeight);
|
|
1098
|
+
const measureLine = (line) => {
|
|
1099
|
+
let sum = 0;
|
|
1100
|
+
for (const ch of line) {
|
|
1101
|
+
sum += charWidthRatio(ch, table, avg);
|
|
1102
|
+
}
|
|
1103
|
+
return sum * fontSize * scale;
|
|
1104
|
+
};
|
|
1105
|
+
if (text.includes("\n")) {
|
|
1106
|
+
let maxWidth = 0;
|
|
1107
|
+
for (const line of text.split("\n")) {
|
|
1108
|
+
const w = measureLine(line);
|
|
1109
|
+
if (w > maxWidth) maxWidth = w;
|
|
1110
|
+
}
|
|
1111
|
+
return maxWidth;
|
|
1112
|
+
}
|
|
1113
|
+
return measureLine(text);
|
|
1114
|
+
}
|
|
1115
|
+
var BRAND_RESERVE_WIDTH = 130;
|
|
1116
|
+
var BRAND_FONT_SIZE = 12;
|
|
1117
|
+
var BRAND_MIN_WIDTH = 120;
|
|
1118
|
+
var COMPACT_WIDTH = 420;
|
|
1119
|
+
function estimateTextHeight(fontSize, lineCount = 1, lineHeight = 1.3) {
|
|
1120
|
+
return fontSize * lineHeight * lineCount;
|
|
1121
|
+
}
|
|
1122
|
+
function textAscent(fontSize) {
|
|
1123
|
+
return fontSize * 0.8;
|
|
1124
|
+
}
|
|
1125
|
+
var heuristicMeasure = (text, fontSize, fontWeight) => ({
|
|
1126
|
+
width: estimateTextWidth(text, fontSize, fontWeight),
|
|
1127
|
+
height: estimateTextHeight(fontSize)
|
|
1128
|
+
});
|
|
1129
|
+
function resolveMeasurer(measureText) {
|
|
1130
|
+
return measureText ?? heuristicMeasure;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// src/responsive/breakpoints.ts
|
|
1134
|
+
var BREAKPOINT_COMPACT_MAX = 400;
|
|
1135
|
+
var BREAKPOINT_MEDIUM_MAX = 700;
|
|
1136
|
+
function getBreakpoint(width) {
|
|
1137
|
+
if (width < BREAKPOINT_COMPACT_MAX) return "compact";
|
|
1138
|
+
if (width <= BREAKPOINT_MEDIUM_MAX) return "medium";
|
|
1139
|
+
return "full";
|
|
1140
|
+
}
|
|
1141
|
+
var HEIGHT_CRAMPED_MAX = 200;
|
|
1142
|
+
var HEIGHT_SHORT_MAX = 350;
|
|
1143
|
+
function getHeightClass(height) {
|
|
1144
|
+
if (height < HEIGHT_CRAMPED_MAX) return "cramped";
|
|
1145
|
+
if (height <= HEIGHT_SHORT_MAX) return "short";
|
|
1146
|
+
return "normal";
|
|
1147
|
+
}
|
|
1148
|
+
function getWidthStrategy(breakpoint) {
|
|
1149
|
+
switch (breakpoint) {
|
|
1150
|
+
case "compact":
|
|
1151
|
+
return {
|
|
1152
|
+
labelMode: "none",
|
|
1153
|
+
legendPosition: "top",
|
|
1154
|
+
annotationPosition: "tooltip-only",
|
|
1155
|
+
axisLabelDensity: "minimal",
|
|
1156
|
+
chromeMode: "full",
|
|
1157
|
+
legendMaxHeight: -1
|
|
1158
|
+
};
|
|
1159
|
+
case "medium":
|
|
1160
|
+
return {
|
|
1161
|
+
labelMode: "important",
|
|
1162
|
+
legendPosition: "top",
|
|
1163
|
+
annotationPosition: "inline",
|
|
1164
|
+
axisLabelDensity: "reduced",
|
|
1165
|
+
chromeMode: "full",
|
|
1166
|
+
legendMaxHeight: -1
|
|
1167
|
+
};
|
|
1168
|
+
case "full":
|
|
1169
|
+
return {
|
|
1170
|
+
labelMode: "all",
|
|
1171
|
+
legendPosition: "right",
|
|
1172
|
+
annotationPosition: "inline",
|
|
1173
|
+
axisLabelDensity: "full",
|
|
1174
|
+
chromeMode: "full",
|
|
1175
|
+
legendMaxHeight: -1
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
function applyHeightConstraints(strategy, heightClass) {
|
|
1180
|
+
if (heightClass === "normal") return strategy;
|
|
1181
|
+
if (heightClass === "cramped") {
|
|
1182
|
+
return {
|
|
1183
|
+
...strategy,
|
|
1184
|
+
chromeMode: "hidden",
|
|
1185
|
+
legendMaxHeight: 0,
|
|
1186
|
+
labelMode: "none",
|
|
1187
|
+
annotationPosition: "tooltip-only"
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
return {
|
|
1191
|
+
...strategy,
|
|
1192
|
+
chromeMode: "compact",
|
|
1193
|
+
legendMaxHeight: 0.15
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
function getLayoutStrategy(breakpoint, heightClass = "normal") {
|
|
1197
|
+
const base = getWidthStrategy(breakpoint);
|
|
1198
|
+
return applyHeightConstraints(base, heightClass);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// src/responsive/metrics.ts
|
|
1202
|
+
var AXIS_TITLE_OFFSET_COMPACT = 35;
|
|
1203
|
+
var AXIS_TITLE_OFFSET_DEFAULT = 45;
|
|
1204
|
+
function getAxisTitleOffset(width) {
|
|
1205
|
+
return width < BREAKPOINT_COMPACT_MAX ? AXIS_TITLE_OFFSET_COMPACT : AXIS_TITLE_OFFSET_DEFAULT;
|
|
1206
|
+
}
|
|
1207
|
+
var HPAD_COMPACT_FRACTION = 0.5;
|
|
1208
|
+
var HPAD_COMPACT_MIN = 4;
|
|
1209
|
+
var TICK_LABEL_OFFSET = 6;
|
|
1210
|
+
var AXIS_TITLE_TRAILING_PAD = 4;
|
|
1211
|
+
var AXIS_TITLE_GAP = 7;
|
|
1212
|
+
function axisTitleOffset(maxTickLabelWidth, titleFontSize, width) {
|
|
1213
|
+
const halfTitleGlyph = Math.ceil(titleFontSize / 2);
|
|
1214
|
+
const dynamic = TICK_LABEL_OFFSET + maxTickLabelWidth + AXIS_TITLE_GAP + halfTitleGlyph;
|
|
1215
|
+
return Math.max(dynamic, getAxisTitleOffset(width));
|
|
1216
|
+
}
|
|
1217
|
+
var NARROW_VIEWPORT_MAX = 500;
|
|
1218
|
+
var TOP_PAD_EXTRA_NARROW = 10;
|
|
1219
|
+
var TOP_PAD_NARROW_MAX = NARROW_VIEWPORT_MAX;
|
|
1220
|
+
var LABEL_GAP_COMPACT = 8;
|
|
1221
|
+
var LABEL_GAP_DEFAULT = 12;
|
|
1222
|
+
var LABEL_GAP_NARROW_MAX = NARROW_VIEWPORT_MAX;
|
|
1223
|
+
var MAX_LEFT_LABEL_FRACTION_MEDIUM_MAX = 600;
|
|
1224
|
+
var MAX_LEFT_LABEL_FRACTION_COMPACT = 0.45;
|
|
1225
|
+
var MAX_LEFT_LABEL_FRACTION_MEDIUM = 0.55;
|
|
1226
|
+
var MAX_LEFT_LABEL_FRACTION_DEFAULT = 1;
|
|
1227
|
+
var X_AXIS_BAND_HEIGHT = 26;
|
|
1228
|
+
var X_AXIS_TITLE_BAND = 22;
|
|
1229
|
+
var X_AXIS_TITLE_BAND_ROTATED = 20;
|
|
1230
|
+
function computeXAxisExtentFromLabels(input) {
|
|
1231
|
+
const measure = input.measure ?? estimateTextWidth;
|
|
1232
|
+
const baseHeight = input.xAxisHeight ?? X_AXIS_BAND_HEIGHT;
|
|
1233
|
+
if (input.tickAngle && Math.abs(input.tickAngle) > 10) {
|
|
1234
|
+
const angleRad = Math.abs(input.tickAngle) * (Math.PI / 180);
|
|
1235
|
+
let maxLabelWidth = 40;
|
|
1236
|
+
for (const label of input.labels) {
|
|
1237
|
+
const w = measure(label, input.tickFontSize, input.tickFontWeight);
|
|
1238
|
+
if (w > maxLabelWidth) maxLabelWidth = w;
|
|
1239
|
+
}
|
|
1240
|
+
const lineHeight = input.tickFontSize * 1.2;
|
|
1241
|
+
const AXIS_TO_LABEL_GAP = 3;
|
|
1242
|
+
const rotatedHeight = Math.min(
|
|
1243
|
+
maxLabelWidth * Math.sin(angleRad) + lineHeight * Math.cos(angleRad) + AXIS_TO_LABEL_GAP,
|
|
1244
|
+
120
|
|
1245
|
+
);
|
|
1246
|
+
return input.hasTitle ? rotatedHeight + X_AXIS_TITLE_BAND_ROTATED : rotatedHeight;
|
|
1247
|
+
}
|
|
1248
|
+
return input.hasTitle ? baseHeight + X_AXIS_TITLE_BAND : baseHeight;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
816
1251
|
// src/theme/defaults.ts
|
|
817
1252
|
var DEFAULT_THEME = {
|
|
818
1253
|
colors: {
|
|
@@ -856,10 +1291,12 @@ var DEFAULT_THEME = {
|
|
|
856
1291
|
chromeToChart: 8,
|
|
857
1292
|
chartToFooter: 8,
|
|
858
1293
|
axisMargin: 6,
|
|
859
|
-
xAxisHeight:
|
|
1294
|
+
xAxisHeight: X_AXIS_BAND_HEIGHT,
|
|
860
1295
|
// Gap (px) between the x-axis line and the TOP of the tick labels. The
|
|
861
|
-
// renderer
|
|
862
|
-
//
|
|
1296
|
+
// renderer treats this as a literal top gap and then shifts the label down
|
|
1297
|
+
// by textAscent() to land it on the alphabetic baseline (rather than
|
|
1298
|
+
// dominant-baseline:hanging, which WebKit positions from different metrics),
|
|
1299
|
+
// so the gap holds regardless of font size.
|
|
863
1300
|
xAxisLabelPadding: 4
|
|
864
1301
|
},
|
|
865
1302
|
borderRadius: 2,
|
|
@@ -1164,42 +1601,6 @@ function resolveTheme(userTheme, base = DEFAULT_THEME) {
|
|
|
1164
1601
|
};
|
|
1165
1602
|
}
|
|
1166
1603
|
|
|
1167
|
-
// src/layout/text-measure.ts
|
|
1168
|
-
var AVG_CHAR_WIDTH_RATIO = 0.57;
|
|
1169
|
-
var WEIGHT_ADJUSTMENT = {
|
|
1170
|
-
100: 0.9,
|
|
1171
|
-
200: 0.92,
|
|
1172
|
-
300: 0.95,
|
|
1173
|
-
400: 1,
|
|
1174
|
-
500: 1.02,
|
|
1175
|
-
600: 1.05,
|
|
1176
|
-
700: 1.08,
|
|
1177
|
-
800: 1.1,
|
|
1178
|
-
900: 1.12
|
|
1179
|
-
};
|
|
1180
|
-
function estimateCharWidth(fontSize, fontWeight = 400) {
|
|
1181
|
-
const weightFactor = WEIGHT_ADJUSTMENT[fontWeight] ?? 1;
|
|
1182
|
-
return fontSize * AVG_CHAR_WIDTH_RATIO * weightFactor;
|
|
1183
|
-
}
|
|
1184
|
-
function estimateTextWidth(text, fontSize, fontWeight = 400) {
|
|
1185
|
-
const charWidth = estimateCharWidth(fontSize, fontWeight);
|
|
1186
|
-
if (text.includes("\n")) {
|
|
1187
|
-
let maxLen = 0;
|
|
1188
|
-
for (const line of text.split("\n")) {
|
|
1189
|
-
if (line.length > maxLen) maxLen = line.length;
|
|
1190
|
-
}
|
|
1191
|
-
return maxLen * charWidth;
|
|
1192
|
-
}
|
|
1193
|
-
return text.length * charWidth;
|
|
1194
|
-
}
|
|
1195
|
-
var BRAND_RESERVE_WIDTH = 130;
|
|
1196
|
-
var BRAND_FONT_SIZE = 12;
|
|
1197
|
-
var BRAND_MIN_WIDTH = 120;
|
|
1198
|
-
var COMPACT_WIDTH = 420;
|
|
1199
|
-
function estimateTextHeight(fontSize, lineCount = 1, lineHeight = 1.3) {
|
|
1200
|
-
return fontSize * lineHeight * lineCount;
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
1604
|
// src/layout/chrome.ts
|
|
1204
1605
|
function normalizeChromeText(value) {
|
|
1205
1606
|
if (value === void 0) return null;
|
|
@@ -1222,8 +1623,7 @@ function buildTextStyle(defaults, fontFamily, textColor, width, overrides) {
|
|
|
1222
1623
|
fontWeight: overrides?.fontWeight ?? defaults.fontWeight,
|
|
1223
1624
|
fill: overrides?.color ?? textColor ?? defaults.color,
|
|
1224
1625
|
lineHeight: defaults.lineHeight,
|
|
1225
|
-
textAnchor: "start"
|
|
1226
|
-
dominantBaseline: "hanging"
|
|
1626
|
+
textAnchor: "start"
|
|
1227
1627
|
};
|
|
1228
1628
|
}
|
|
1229
1629
|
function estimateLineCount(text, style, maxWidth, measureText) {
|
|
@@ -1505,101 +1905,6 @@ function wrapText(text, fontSize, fontWeight, maxWidth, measureText) {
|
|
|
1505
1905
|
return lines;
|
|
1506
1906
|
}
|
|
1507
1907
|
|
|
1508
|
-
// src/responsive/breakpoints.ts
|
|
1509
|
-
var BREAKPOINT_COMPACT_MAX = 400;
|
|
1510
|
-
var BREAKPOINT_MEDIUM_MAX = 700;
|
|
1511
|
-
function getBreakpoint(width) {
|
|
1512
|
-
if (width < BREAKPOINT_COMPACT_MAX) return "compact";
|
|
1513
|
-
if (width <= BREAKPOINT_MEDIUM_MAX) return "medium";
|
|
1514
|
-
return "full";
|
|
1515
|
-
}
|
|
1516
|
-
var HEIGHT_CRAMPED_MAX = 200;
|
|
1517
|
-
var HEIGHT_SHORT_MAX = 350;
|
|
1518
|
-
function getHeightClass(height) {
|
|
1519
|
-
if (height < HEIGHT_CRAMPED_MAX) return "cramped";
|
|
1520
|
-
if (height <= HEIGHT_SHORT_MAX) return "short";
|
|
1521
|
-
return "normal";
|
|
1522
|
-
}
|
|
1523
|
-
function getWidthStrategy(breakpoint) {
|
|
1524
|
-
switch (breakpoint) {
|
|
1525
|
-
case "compact":
|
|
1526
|
-
return {
|
|
1527
|
-
labelMode: "none",
|
|
1528
|
-
legendPosition: "top",
|
|
1529
|
-
annotationPosition: "tooltip-only",
|
|
1530
|
-
axisLabelDensity: "minimal",
|
|
1531
|
-
chromeMode: "full",
|
|
1532
|
-
legendMaxHeight: -1
|
|
1533
|
-
};
|
|
1534
|
-
case "medium":
|
|
1535
|
-
return {
|
|
1536
|
-
labelMode: "important",
|
|
1537
|
-
legendPosition: "top",
|
|
1538
|
-
annotationPosition: "inline",
|
|
1539
|
-
axisLabelDensity: "reduced",
|
|
1540
|
-
chromeMode: "full",
|
|
1541
|
-
legendMaxHeight: -1
|
|
1542
|
-
};
|
|
1543
|
-
case "full":
|
|
1544
|
-
return {
|
|
1545
|
-
labelMode: "all",
|
|
1546
|
-
legendPosition: "right",
|
|
1547
|
-
annotationPosition: "inline",
|
|
1548
|
-
axisLabelDensity: "full",
|
|
1549
|
-
chromeMode: "full",
|
|
1550
|
-
legendMaxHeight: -1
|
|
1551
|
-
};
|
|
1552
|
-
}
|
|
1553
|
-
}
|
|
1554
|
-
function applyHeightConstraints(strategy, heightClass) {
|
|
1555
|
-
if (heightClass === "normal") return strategy;
|
|
1556
|
-
if (heightClass === "cramped") {
|
|
1557
|
-
return {
|
|
1558
|
-
...strategy,
|
|
1559
|
-
chromeMode: "hidden",
|
|
1560
|
-
legendMaxHeight: 0,
|
|
1561
|
-
labelMode: "none",
|
|
1562
|
-
annotationPosition: "tooltip-only"
|
|
1563
|
-
};
|
|
1564
|
-
}
|
|
1565
|
-
return {
|
|
1566
|
-
...strategy,
|
|
1567
|
-
chromeMode: "compact",
|
|
1568
|
-
legendMaxHeight: 0.15
|
|
1569
|
-
};
|
|
1570
|
-
}
|
|
1571
|
-
function getLayoutStrategy(breakpoint, heightClass = "normal") {
|
|
1572
|
-
const base = getWidthStrategy(breakpoint);
|
|
1573
|
-
return applyHeightConstraints(base, heightClass);
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
|
-
// src/responsive/metrics.ts
|
|
1577
|
-
var AXIS_TITLE_OFFSET_COMPACT = 35;
|
|
1578
|
-
var AXIS_TITLE_OFFSET_DEFAULT = 45;
|
|
1579
|
-
function getAxisTitleOffset(width) {
|
|
1580
|
-
return width < BREAKPOINT_COMPACT_MAX ? AXIS_TITLE_OFFSET_COMPACT : AXIS_TITLE_OFFSET_DEFAULT;
|
|
1581
|
-
}
|
|
1582
|
-
var HPAD_COMPACT_FRACTION = 0.5;
|
|
1583
|
-
var HPAD_COMPACT_MIN = 4;
|
|
1584
|
-
var TICK_LABEL_OFFSET = 6;
|
|
1585
|
-
var AXIS_TITLE_TRAILING_PAD = 4;
|
|
1586
|
-
var AXIS_TITLE_GAP = 7;
|
|
1587
|
-
function axisTitleOffset(maxTickLabelWidth, titleFontSize, width) {
|
|
1588
|
-
const halfTitleGlyph = Math.ceil(titleFontSize / 2);
|
|
1589
|
-
const dynamic = TICK_LABEL_OFFSET + maxTickLabelWidth + AXIS_TITLE_GAP + halfTitleGlyph;
|
|
1590
|
-
return Math.max(dynamic, getAxisTitleOffset(width));
|
|
1591
|
-
}
|
|
1592
|
-
var NARROW_VIEWPORT_MAX = 500;
|
|
1593
|
-
var TOP_PAD_EXTRA_NARROW = 10;
|
|
1594
|
-
var TOP_PAD_NARROW_MAX = NARROW_VIEWPORT_MAX;
|
|
1595
|
-
var LABEL_GAP_COMPACT = 8;
|
|
1596
|
-
var LABEL_GAP_DEFAULT = 12;
|
|
1597
|
-
var LABEL_GAP_NARROW_MAX = NARROW_VIEWPORT_MAX;
|
|
1598
|
-
var MAX_LEFT_LABEL_FRACTION_MEDIUM_MAX = 600;
|
|
1599
|
-
var MAX_LEFT_LABEL_FRACTION_COMPACT = 0.45;
|
|
1600
|
-
var MAX_LEFT_LABEL_FRACTION_MEDIUM = 0.55;
|
|
1601
|
-
var MAX_LEFT_LABEL_FRACTION_DEFAULT = 1;
|
|
1602
|
-
|
|
1603
1908
|
// src/labels/collision.ts
|
|
1604
1909
|
var PRIORITY_ORDER = {
|
|
1605
1910
|
data: 0,
|
|
@@ -1609,6 +1914,11 @@ var PRIORITY_ORDER = {
|
|
|
1609
1914
|
function detectCollision(a, b) {
|
|
1610
1915
|
return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
|
|
1611
1916
|
}
|
|
1917
|
+
function overlapArea(a, b) {
|
|
1918
|
+
const w = Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x);
|
|
1919
|
+
const h = Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y);
|
|
1920
|
+
return w > 0 && h > 0 ? w * h : 0;
|
|
1921
|
+
}
|
|
1612
1922
|
var OFFSET_STRATEGIES = [
|
|
1613
1923
|
{ dx: 0, dy: 0 },
|
|
1614
1924
|
// original position
|
|
@@ -1680,6 +1990,9 @@ function resolveCollisions(labels, strategies = OFFSET_STRATEGIES) {
|
|
|
1680
1990
|
y: bestY,
|
|
1681
1991
|
style: label.style,
|
|
1682
1992
|
visible: true,
|
|
1993
|
+
// Only carry the index through when the caller set one, so labels that
|
|
1994
|
+
// don't need it keep an unchanged output shape.
|
|
1995
|
+
...label.index !== void 0 ? { index: label.index } : {},
|
|
1683
1996
|
connector: needsConnector ? {
|
|
1684
1997
|
from: { x: bestX, y: bestY },
|
|
1685
1998
|
to: { x: label.anchorX, y: label.anchorY },
|
|
@@ -1693,7 +2006,8 @@ function resolveCollisions(labels, strategies = OFFSET_STRATEGIES) {
|
|
|
1693
2006
|
x: label.anchorX,
|
|
1694
2007
|
y: label.anchorY,
|
|
1695
2008
|
style: label.style,
|
|
1696
|
-
visible: false
|
|
2009
|
+
visible: false,
|
|
2010
|
+
...label.index !== void 0 ? { index: label.index } : {}
|
|
1697
2011
|
});
|
|
1698
2012
|
}
|
|
1699
2013
|
}
|
|
@@ -1710,7 +2024,16 @@ function computeLabelBounds(label) {
|
|
|
1710
2024
|
} else if (label.style.textAnchor === "end") {
|
|
1711
2025
|
x = label.x - width;
|
|
1712
2026
|
}
|
|
1713
|
-
|
|
2027
|
+
const baseline = label.style.dominantBaseline;
|
|
2028
|
+
let y;
|
|
2029
|
+
if (baseline === "central") {
|
|
2030
|
+
y = label.y - height / 2;
|
|
2031
|
+
} else if (baseline === "hanging" || baseline === "text-after-edge") {
|
|
2032
|
+
y = label.y;
|
|
2033
|
+
} else {
|
|
2034
|
+
y = label.y - fontSize * 0.8;
|
|
2035
|
+
}
|
|
2036
|
+
return { x, y, width, height };
|
|
1714
2037
|
}
|
|
1715
2038
|
|
|
1716
2039
|
// ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatDecimal.js
|
|
@@ -3093,6 +3416,9 @@ export {
|
|
|
3093
3416
|
TICK_LABEL_OFFSET,
|
|
3094
3417
|
TOP_PAD_EXTRA_NARROW,
|
|
3095
3418
|
TOP_PAD_NARROW_MAX,
|
|
3419
|
+
X_AXIS_BAND_HEIGHT,
|
|
3420
|
+
X_AXIS_TITLE_BAND,
|
|
3421
|
+
X_AXIS_TITLE_BAND_ROTATED,
|
|
3096
3422
|
abbreviateNumber,
|
|
3097
3423
|
adaptColorForDarkMode,
|
|
3098
3424
|
adaptTheme,
|
|
@@ -3105,6 +3431,7 @@ export {
|
|
|
3105
3431
|
columnChart,
|
|
3106
3432
|
computeChrome,
|
|
3107
3433
|
computeLabelBounds,
|
|
3434
|
+
computeXAxisExtentFromLabels,
|
|
3108
3435
|
contrastRatio,
|
|
3109
3436
|
dataTable,
|
|
3110
3437
|
detectCollision,
|
|
@@ -3123,6 +3450,7 @@ export {
|
|
|
3123
3450
|
getHeightClass,
|
|
3124
3451
|
getLayoutStrategy,
|
|
3125
3452
|
getRepresentativeColor,
|
|
3453
|
+
heuristicMeasure,
|
|
3126
3454
|
inferFieldType,
|
|
3127
3455
|
isBarListSpec,
|
|
3128
3456
|
isChartSpec,
|
|
@@ -3139,14 +3467,17 @@ export {
|
|
|
3139
3467
|
isTileMapSpec,
|
|
3140
3468
|
lineChart,
|
|
3141
3469
|
meetsAA,
|
|
3470
|
+
overlapArea,
|
|
3142
3471
|
pickLabelColor,
|
|
3143
3472
|
pieChart,
|
|
3144
3473
|
resolveCollisions,
|
|
3145
3474
|
resolveMarkDef,
|
|
3146
3475
|
resolveMarkType,
|
|
3476
|
+
resolveMeasurer,
|
|
3147
3477
|
resolveTheme,
|
|
3148
3478
|
scatterChart,
|
|
3149
3479
|
simulateColorBlindness,
|
|
3480
|
+
textAscent,
|
|
3150
3481
|
tileMap,
|
|
3151
3482
|
wrapText
|
|
3152
3483
|
};
|