Skip to content

Commit a1f53cc

Browse files
committed
refactor(#178): improved text width calculation with canvas
1 parent fda703a commit a1f53cc

File tree

5 files changed

+172
-8
lines changed

5 files changed

+172
-8
lines changed
160 KB
Binary file not shown.

lib/@dsvgui/package-lock.json

+147
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/@dsvgui/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@storybook/react": "^7.0.6",
2020
"@storybook/testing-library": "^0.1.0",
2121
"buffer": "^6.0.3",
22+
"canvas": "^2.11.2",
2223
"image-size": "^1.0.2",
2324
"react": "^18.2.0",
2425
"react-dom": "^18.2.0",

lib/@dsvgui/utils/index.ts

+24-8
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,40 @@
11
import getImageSize from "image-size";
2+
import { createCanvas } from "canvas";
23

34
type IGetTextWidth = (
45
inputText: string | number | null,
56
options: {
67
fontSize: number;
7-
ratio?: number;
8+
fontFamily?: string;
9+
fontWeight?: string;
810
}
911
) => number;
1012

1113
export const getTextWidth: IGetTextWidth = (inputText, options) => {
12-
const { fontSize = 16, ratio = 0.5 } = options;
14+
const {
15+
fontSize = 16,
16+
fontFamily = "sans-serif",
17+
fontWeight = "normal",
18+
} = options;
1319

14-
let width = 0;
1520
let text = inputText ?? "";
1621
text = text.toString();
1722

18-
// Estimate the width using a monospace font (each character has the same width)
19-
width = text.length * fontSize * ratio;
20-
return width;
23+
const canvas = createCanvas(0, 0);
24+
const context = canvas.getContext("2d");
25+
context.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
26+
27+
const metrics = context.measureText(text);
28+
return metrics.width;
2129
};
2230

2331
type IWrapText = (
2432
inputText: string,
2533
options: {
2634
maxLineWidth: number;
27-
fontSize: number;
2835
maxLines?: number;
36+
fontSize: number;
37+
fontWeight?: string;
2938
},
3039
cb: (value: string, index: number, array: Array<string>) => JSX.Element
3140
) => Array<JSX.Element>;
@@ -40,7 +49,10 @@ export const wrapText: IWrapText = (inputText, options, cb) => {
4049
for (let i = 1; i < words.length; i++) {
4150
const word = words[i];
4251
const testLine = currentLine + " " + word;
43-
const testWidth = getTextWidth(testLine, { fontSize: options.fontSize });
52+
const testWidth = getTextWidth(testLine, {
53+
fontSize: options.fontSize,
54+
fontWeight: options.fontWeight,
55+
});
4456

4557
if (testWidth > maxLineWidth) {
4658
lines.push(currentLine);
@@ -83,6 +95,10 @@ export const convertDateToReadableFormat: IConvertDateToReadbleFormat = (
8395
return `${month} ${day} '${year}`;
8496
};
8597

98+
export function rgbToHex([r, g, b]: Array<number>) {
99+
return "#" + [r, g, b].map((x) => x.toString(16).padStart(2, "0")).join("");
100+
}
101+
86102
export function hexToRgb(hex: string, alpha = 1) {
87103
const bigint = parseInt(hex.slice(1), 16);
88104
const r = (bigint >> 16) & 255;

0 commit comments

Comments
 (0)