@opendata-ai/openchart-core 2.10.0 → 2.12.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 +17 -9
- package/dist/index.js +42 -13
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -0
- package/package.json +1 -1
- package/src/index.ts +2 -1
- package/src/labels/collision.ts +26 -0
- package/src/labels/index.ts +1 -1
- package/src/layout/__tests__/chrome.test.ts +17 -0
- package/src/layout/chrome.ts +30 -15
- package/src/layout/index.ts +6 -1
- package/src/layout/text-measure.ts +18 -2
- package/src/styles/viz.css +2 -0
- package/src/theme/__tests__/resolve.test.ts +57 -0
package/dist/index.d.ts
CHANGED
|
@@ -1834,14 +1834,6 @@ declare function resolveTheme(userTheme?: ThemeConfig, base?: Theme): ResolvedTh
|
|
|
1834
1834
|
*/
|
|
1835
1835
|
declare function computeChrome(chrome: Chrome | undefined, theme: ResolvedTheme, width: number, measureText?: MeasureTextFn, chromeMode?: ChromeMode, padding?: number): ResolvedChrome;
|
|
1836
1836
|
|
|
1837
|
-
/**
|
|
1838
|
-
* Heuristic text measurement for environments without a DOM.
|
|
1839
|
-
*
|
|
1840
|
-
* These are intentionally approximate. Adapters can provide a real
|
|
1841
|
-
* measureText function via CompileOptions for higher accuracy.
|
|
1842
|
-
* The engine uses the real function when available, falls back to
|
|
1843
|
-
* these heuristics when not.
|
|
1844
|
-
*/
|
|
1845
1837
|
/**
|
|
1846
1838
|
* Estimate the rendered width of a text string.
|
|
1847
1839
|
*
|
|
@@ -1853,6 +1845,13 @@ declare function computeChrome(chrome: Chrome | undefined, theme: ResolvedTheme,
|
|
|
1853
1845
|
* @param fontWeight - Font weight (100-900). Defaults to 400.
|
|
1854
1846
|
*/
|
|
1855
1847
|
declare function estimateTextWidth(text: string, fontSize: number, fontWeight?: number): number;
|
|
1848
|
+
/**
|
|
1849
|
+
* Width reserved for the "OpenData" brand watermark in the bottom-right corner.
|
|
1850
|
+
* Accounts for ~8 chars at font size 20 with mixed 500/600 weight, plus a gap
|
|
1851
|
+
* so adjacent text doesn't crowd it. Used by chrome and legend layout to avoid
|
|
1852
|
+
* overlapping the brand.
|
|
1853
|
+
*/
|
|
1854
|
+
declare const BRAND_RESERVE_WIDTH = 110;
|
|
1856
1855
|
|
|
1857
1856
|
/**
|
|
1858
1857
|
* Label collision detection and resolution.
|
|
@@ -1884,6 +1883,10 @@ interface LabelCandidate {
|
|
|
1884
1883
|
/** Text style to apply. */
|
|
1885
1884
|
style: TextStyle;
|
|
1886
1885
|
}
|
|
1886
|
+
/**
|
|
1887
|
+
* Detect AABB (axis-aligned bounding box) overlap between two rectangles.
|
|
1888
|
+
*/
|
|
1889
|
+
declare function detectCollision(a: Rect, b: Rect): boolean;
|
|
1887
1890
|
/**
|
|
1888
1891
|
* Resolve label collisions using a greedy placement algorithm.
|
|
1889
1892
|
*
|
|
@@ -1896,6 +1899,11 @@ interface LabelCandidate {
|
|
|
1896
1899
|
* @returns Array of resolved labels with computed positions and visibility.
|
|
1897
1900
|
*/
|
|
1898
1901
|
declare function resolveCollisions(labels: LabelCandidate[]): ResolvedLabel[];
|
|
1902
|
+
/**
|
|
1903
|
+
* Compute the bounding rect of a resolved label from its position and text.
|
|
1904
|
+
* Uses heuristic text measurement so it works without DOM access.
|
|
1905
|
+
*/
|
|
1906
|
+
declare function computeLabelBounds(label: ResolvedLabel): Rect;
|
|
1899
1907
|
|
|
1900
1908
|
/**
|
|
1901
1909
|
* Locale-aware number and date formatting utilities.
|
|
@@ -2144,4 +2152,4 @@ declare function scatterChart(data: DataRow[], x: FieldRef, y: FieldRef, options
|
|
|
2144
2152
|
*/
|
|
2145
2153
|
declare function dataTable(data: DataRow[], options?: TableBuilderOptions): TableSpec;
|
|
2146
2154
|
|
|
2147
|
-
export { type A11yMetadata, type AggregateOp, type Annotation, type AnnotationAnchor, type AnnotationOffset, type AnnotationPosition, type ArcMark, type AreaMark, type AxisConfig, type AxisLabelDensity, type AxisLayout, type AxisTick, type BarColumnConfig, type BarTableCell, type Breakpoint, CATEGORICAL_PALETTE, CHART_ENCODING_RULES, CHART_TYPES, type CategoricalPalette, type CategoryColorsConfig, type CategoryTableCell, type CellStyle, type ChannelRule, type ChartBuilderOptions, type ChartEventHandlers, type ChartLayout, type ChartSpec, type ChartSpecOverride, type ChartSpecWithoutData, type ChartType, type Chrome, type ChromeDefaults, type ChromeKey, type ChromeMode, type ChromeText, type ChromeTextStyle, type ColorBlindnessType, type ColumnConfig, type CompileOptions, type CompileTableOptions, DEFAULT_THEME, DIVERGING_PALETTES, type DarkMode, type DataRow, type DateGranularity, type DivergingPalette, type ElementEdit, type Encoding, type EncodingChannel, type EncodingRule, type FieldRef, type FieldType, type FlagTableCell, GRAPH_ENCODING_RULES, type GraphChannelRule, type GraphEdge, type GraphEdgeLayout, type GraphEncoding, type GraphEncodingChannel, type GraphLayout, type GraphLayoutConfig, type GraphNode, type GraphNodeLayout, type GraphSpec, type GraphSpecWithoutData, type Gridline, type HeatmapColumnConfig, type HeatmapTableCell, type HeightClass, type ImageColumnConfig, type ImageTableCell, type LabelCandidate, type LabelConfig, type LabelDensity, type LabelMode, type LabelPriority, type LayoutStrategy, type LegendConfig, type LegendEntry, type LegendLayout, type LegendPosition, type LineMark, type Margins, type Mark, type MarkAria, type MarkEvent, type MeasureTextFn, type NodeOverride, type PaginationState, type Point, type PointMark, type RangeAnnotation, type Rect, type RectMark, type RefLineAnnotation, type ResolvedAnnotation, type ResolvedChrome, type ResolvedChromeElement, type ResolvedColumn, type ResolvedLabel, type ResolvedTheme, SEQUENTIAL_PALETTES, type ScaleConfig, type SequentialPalette, type SeriesStyle, type SortState, type SparklineColumnConfig, type SparklineData, type SparklineTableCell, type StoredVizSpec, type TableBuilderOptions, type TableCell, type TableCellBase, type TableLayout, type TableRow, type TableSpec, type TableSpecWithoutData, type TextAnnotation, type TextStyle, type TextTableCell, type Theme, type ThemeChromeDefaults, type ThemeColors, type ThemeConfig, type ThemeFontSizes, type ThemeFontWeights, type ThemeFonts, type ThemeSpacing, type TooltipContent, type TooltipField, type VizSpec, abbreviateNumber, adaptColorForDarkMode, adaptTheme, areaChart, barChart, buildD3Formatter, checkPaletteDistinguishability, columnChart, computeChrome, contrastRatio, dataTable, donutChart, dotChart, estimateTextWidth, findAccessibleColor, formatDate, formatNumber, generateAltText, generateAriaLabels, generateDataTable, getBreakpoint, getHeightClass, getLayoutStrategy, inferFieldType, isChartSpec, isGraphSpec, isRangeAnnotation, isRefLineAnnotation, isTableSpec, isTextAnnotation, lineChart, meetsAA, pieChart, resolveCollisions, resolveTheme, scatterChart, simulateColorBlindness };
|
|
2155
|
+
export { type A11yMetadata, type AggregateOp, type Annotation, type AnnotationAnchor, type AnnotationOffset, type AnnotationPosition, type ArcMark, type AreaMark, type AxisConfig, type AxisLabelDensity, type AxisLayout, type AxisTick, BRAND_RESERVE_WIDTH, type BarColumnConfig, type BarTableCell, type Breakpoint, CATEGORICAL_PALETTE, CHART_ENCODING_RULES, CHART_TYPES, type CategoricalPalette, type CategoryColorsConfig, type CategoryTableCell, type CellStyle, type ChannelRule, type ChartBuilderOptions, type ChartEventHandlers, type ChartLayout, type ChartSpec, type ChartSpecOverride, type ChartSpecWithoutData, type ChartType, type Chrome, type ChromeDefaults, type ChromeKey, type ChromeMode, type ChromeText, type ChromeTextStyle, type ColorBlindnessType, type ColumnConfig, type CompileOptions, type CompileTableOptions, DEFAULT_THEME, DIVERGING_PALETTES, type DarkMode, type DataRow, type DateGranularity, type DivergingPalette, type ElementEdit, type Encoding, type EncodingChannel, type EncodingRule, type FieldRef, type FieldType, type FlagTableCell, GRAPH_ENCODING_RULES, type GraphChannelRule, type GraphEdge, type GraphEdgeLayout, type GraphEncoding, type GraphEncodingChannel, type GraphLayout, type GraphLayoutConfig, type GraphNode, type GraphNodeLayout, type GraphSpec, type GraphSpecWithoutData, type Gridline, type HeatmapColumnConfig, type HeatmapTableCell, type HeightClass, type ImageColumnConfig, type ImageTableCell, type LabelCandidate, type LabelConfig, type LabelDensity, type LabelMode, type LabelPriority, type LayoutStrategy, type LegendConfig, type LegendEntry, type LegendLayout, type LegendPosition, type LineMark, type Margins, type Mark, type MarkAria, type MarkEvent, type MeasureTextFn, type NodeOverride, type PaginationState, type Point, type PointMark, type RangeAnnotation, type Rect, type RectMark, type RefLineAnnotation, type ResolvedAnnotation, type ResolvedChrome, type ResolvedChromeElement, type ResolvedColumn, type ResolvedLabel, type ResolvedTheme, SEQUENTIAL_PALETTES, type ScaleConfig, type SequentialPalette, type SeriesStyle, type SortState, type SparklineColumnConfig, type SparklineData, type SparklineTableCell, type StoredVizSpec, type TableBuilderOptions, type TableCell, type TableCellBase, type TableLayout, type TableRow, type TableSpec, type TableSpecWithoutData, type TextAnnotation, type TextStyle, type TextTableCell, type Theme, type ThemeChromeDefaults, type ThemeColors, type ThemeConfig, type ThemeFontSizes, type ThemeFontWeights, type ThemeFonts, type ThemeSpacing, type TooltipContent, type TooltipField, type VizSpec, abbreviateNumber, adaptColorForDarkMode, adaptTheme, areaChart, barChart, buildD3Formatter, checkPaletteDistinguishability, columnChart, computeChrome, computeLabelBounds, contrastRatio, dataTable, detectCollision, donutChart, dotChart, estimateTextWidth, findAccessibleColor, formatDate, formatNumber, generateAltText, generateAriaLabels, generateDataTable, getBreakpoint, getHeightClass, getLayoutStrategy, inferFieldType, isChartSpec, isGraphSpec, isRangeAnnotation, isRefLineAnnotation, isTableSpec, isTextAnnotation, lineChart, meetsAA, pieChart, resolveCollisions, resolveTheme, scatterChart, simulateColorBlindness };
|
package/dist/index.js
CHANGED
|
@@ -908,10 +908,14 @@ var WEIGHT_ADJUSTMENT = {
|
|
|
908
908
|
800: 1.1,
|
|
909
909
|
900: 1.12
|
|
910
910
|
};
|
|
911
|
-
function
|
|
911
|
+
function estimateCharWidth(fontSize, fontWeight = 400) {
|
|
912
912
|
const weightFactor = WEIGHT_ADJUSTMENT[fontWeight] ?? 1;
|
|
913
|
-
return
|
|
913
|
+
return fontSize * AVG_CHAR_WIDTH_RATIO * weightFactor;
|
|
914
|
+
}
|
|
915
|
+
function estimateTextWidth(text, fontSize, fontWeight = 400) {
|
|
916
|
+
return text.length * estimateCharWidth(fontSize, fontWeight);
|
|
914
917
|
}
|
|
918
|
+
var BRAND_RESERVE_WIDTH = 110;
|
|
915
919
|
function estimateTextHeight(fontSize, lineCount = 1, lineHeight = 1.3) {
|
|
916
920
|
return fontSize * lineHeight * lineCount;
|
|
917
921
|
}
|
|
@@ -942,16 +946,24 @@ function buildTextStyle(defaults, fontFamily, textColor, width, overrides) {
|
|
|
942
946
|
dominantBaseline: "hanging"
|
|
943
947
|
};
|
|
944
948
|
}
|
|
945
|
-
function
|
|
946
|
-
if (
|
|
947
|
-
|
|
949
|
+
function estimateLineCount(text, style, maxWidth, _measureText) {
|
|
950
|
+
if (maxWidth <= 0) return 1;
|
|
951
|
+
const charWidth = estimateCharWidth(style.fontSize, style.fontWeight);
|
|
952
|
+
const maxChars = Math.floor(maxWidth / charWidth);
|
|
953
|
+
if (text.length <= maxChars) return 1;
|
|
954
|
+
const words = text.split(" ");
|
|
955
|
+
let lines = 1;
|
|
956
|
+
let current = "";
|
|
957
|
+
for (const word of words) {
|
|
958
|
+
const candidate = current ? `${current} ${word}` : word;
|
|
959
|
+
if (candidate.length > maxChars && current) {
|
|
960
|
+
lines++;
|
|
961
|
+
current = word;
|
|
962
|
+
} else {
|
|
963
|
+
current = candidate;
|
|
964
|
+
}
|
|
948
965
|
}
|
|
949
|
-
return
|
|
950
|
-
}
|
|
951
|
-
function estimateLineCount(text, style, maxWidth, measureText) {
|
|
952
|
-
const fullWidth = measureWidth(text, style, measureText);
|
|
953
|
-
if (fullWidth <= maxWidth) return 1;
|
|
954
|
-
return Math.ceil(fullWidth / maxWidth);
|
|
966
|
+
return lines;
|
|
955
967
|
}
|
|
956
968
|
function computeChrome(chrome, theme, width, measureText, chromeMode = "full", padding) {
|
|
957
969
|
if (!chrome || chromeMode === "hidden") {
|
|
@@ -1012,6 +1024,7 @@ function computeChrome(chrome, theme, width, measureText, chromeMode = "full", p
|
|
|
1012
1024
|
...topElements
|
|
1013
1025
|
};
|
|
1014
1026
|
}
|
|
1027
|
+
const bottomMaxWidth = maxWidth - BRAND_RESERVE_WIDTH;
|
|
1015
1028
|
const bottomElements = {};
|
|
1016
1029
|
let bottomHeight = 0;
|
|
1017
1030
|
const bottomItems = [];
|
|
@@ -1049,14 +1062,14 @@ function computeChrome(chrome, theme, width, measureText, chromeMode = "full", p
|
|
|
1049
1062
|
width,
|
|
1050
1063
|
item.norm.style
|
|
1051
1064
|
);
|
|
1052
|
-
const lineCount = estimateLineCount(item.norm.text, style,
|
|
1065
|
+
const lineCount = estimateLineCount(item.norm.text, style, bottomMaxWidth, measureText);
|
|
1053
1066
|
const height = estimateTextHeight(style.fontSize, lineCount, style.lineHeight);
|
|
1054
1067
|
bottomElements[item.key] = {
|
|
1055
1068
|
text: item.norm.text,
|
|
1056
1069
|
x: pad2 + (item.norm.offset?.dx ?? 0),
|
|
1057
1070
|
y: bottomHeight + (item.norm.offset?.dy ?? 0),
|
|
1058
1071
|
// offset from where bottom chrome starts
|
|
1059
|
-
maxWidth,
|
|
1072
|
+
maxWidth: bottomMaxWidth,
|
|
1060
1073
|
style
|
|
1061
1074
|
};
|
|
1062
1075
|
bottomHeight += height + chromeGap;
|
|
@@ -1224,6 +1237,19 @@ function resolveCollisions(labels) {
|
|
|
1224
1237
|
}
|
|
1225
1238
|
return results;
|
|
1226
1239
|
}
|
|
1240
|
+
function computeLabelBounds(label) {
|
|
1241
|
+
const fontSize = label.style.fontSize;
|
|
1242
|
+
const fontWeight = label.style.fontWeight;
|
|
1243
|
+
const width = estimateTextWidth(label.text, fontSize, fontWeight);
|
|
1244
|
+
const height = fontSize * (label.style.lineHeight ?? 1.2);
|
|
1245
|
+
let x = label.x;
|
|
1246
|
+
if (label.style.textAnchor === "middle") {
|
|
1247
|
+
x = label.x - width / 2;
|
|
1248
|
+
} else if (label.style.textAnchor === "end") {
|
|
1249
|
+
x = label.x - width;
|
|
1250
|
+
}
|
|
1251
|
+
return { x, y: label.y, width, height };
|
|
1252
|
+
}
|
|
1227
1253
|
|
|
1228
1254
|
// ../../node_modules/.bun/d3-format@3.1.2/node_modules/d3-format/src/formatDecimal.js
|
|
1229
1255
|
function formatDecimal_default(x) {
|
|
@@ -2541,6 +2567,7 @@ function dataTable(data, options) {
|
|
|
2541
2567
|
return spec;
|
|
2542
2568
|
}
|
|
2543
2569
|
export {
|
|
2570
|
+
BRAND_RESERVE_WIDTH,
|
|
2544
2571
|
CATEGORICAL_PALETTE,
|
|
2545
2572
|
CHART_ENCODING_RULES,
|
|
2546
2573
|
CHART_TYPES,
|
|
@@ -2557,8 +2584,10 @@ export {
|
|
|
2557
2584
|
checkPaletteDistinguishability,
|
|
2558
2585
|
columnChart,
|
|
2559
2586
|
computeChrome,
|
|
2587
|
+
computeLabelBounds,
|
|
2560
2588
|
contrastRatio,
|
|
2561
2589
|
dataTable,
|
|
2590
|
+
detectCollision,
|
|
2562
2591
|
donutChart,
|
|
2563
2592
|
dotChart,
|
|
2564
2593
|
estimateTextWidth,
|