feat(createCharacterComparison): add generic for font type and checks for the absence of the fonts
This commit is contained in:
@@ -15,16 +15,22 @@ export interface LineData {
|
||||
* @param fontB - The second font definition
|
||||
* @returns Object with reactive state (lines, containerWidth) and methods (breakIntoLines, getCharState)
|
||||
*/
|
||||
export function createCharacterComparison(
|
||||
export function createCharacterComparison<
|
||||
T extends { name: string; id: string } | undefined = undefined,
|
||||
>(
|
||||
text: () => string,
|
||||
fontA: () => { name: string; id: string },
|
||||
fontB: () => { name: string; id: string },
|
||||
fontA: () => T,
|
||||
fontB: () => T,
|
||||
weight: () => number,
|
||||
size: () => number,
|
||||
) {
|
||||
let lines = $state<LineData[]>([]);
|
||||
let containerWidth = $state(0);
|
||||
|
||||
function fontDefined<T extends { name: string; id: string }>(font: T | undefined): font is T {
|
||||
return font !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures text width using a canvas context.
|
||||
* @param ctx - Canvas rendering context
|
||||
@@ -36,10 +42,11 @@ export function createCharacterComparison(
|
||||
function measureText(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
text: string,
|
||||
fontFamily: string,
|
||||
fontSize: number,
|
||||
fontWeight: number,
|
||||
fontFamily?: string,
|
||||
): number {
|
||||
if (!fontFamily) return 0;
|
||||
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
|
||||
return ctx.measureText(text).width;
|
||||
}
|
||||
@@ -73,7 +80,7 @@ export function createCharacterComparison(
|
||||
container: HTMLElement | undefined,
|
||||
measureCanvas: HTMLCanvasElement | undefined,
|
||||
) {
|
||||
if (!container || !measureCanvas) return;
|
||||
if (!container || !measureCanvas || !fontA() || !fontB()) return;
|
||||
|
||||
const rect = container.getBoundingClientRect();
|
||||
containerWidth = rect.width;
|
||||
@@ -92,22 +99,24 @@ export function createCharacterComparison(
|
||||
let currentLineWords: string[] = [];
|
||||
|
||||
function pushLine(words: string[]) {
|
||||
if (words.length === 0) return;
|
||||
if (words.length === 0 || !fontDefined(fontA()) || !fontDefined(fontB())) {
|
||||
return;
|
||||
}
|
||||
const lineText = words.join(' ');
|
||||
// Measure both fonts at the CURRENT weight
|
||||
const widthA = measureText(
|
||||
ctx!,
|
||||
lineText,
|
||||
fontA().name,
|
||||
Math.min(fontSize, controlledFontSize),
|
||||
currentWeight,
|
||||
fontA()?.name,
|
||||
);
|
||||
const widthB = measureText(
|
||||
ctx!,
|
||||
lineText,
|
||||
fontB().name,
|
||||
Math.min(fontSize, controlledFontSize),
|
||||
currentWeight,
|
||||
fontB()?.name,
|
||||
);
|
||||
const maxWidth = Math.max(widthA, widthB);
|
||||
newLines.push({ text: lineText, width: maxWidth });
|
||||
@@ -121,16 +130,16 @@ export function createCharacterComparison(
|
||||
const widthA = measureText(
|
||||
ctx,
|
||||
testLine,
|
||||
fontA().name,
|
||||
Math.min(fontSize, controlledFontSize),
|
||||
currentWeight,
|
||||
fontA()?.name,
|
||||
);
|
||||
const widthB = measureText(
|
||||
ctx,
|
||||
testLine,
|
||||
fontB().name,
|
||||
Math.min(fontSize, controlledFontSize),
|
||||
currentWeight,
|
||||
fontB()?.name,
|
||||
);
|
||||
const maxWidth = Math.max(widthA, widthB);
|
||||
const isContainerOverflown = maxWidth > availableWidth;
|
||||
@@ -155,16 +164,16 @@ export function createCharacterComparison(
|
||||
const wA = measureText(
|
||||
ctx,
|
||||
testFragment,
|
||||
fontA().name,
|
||||
fontSize,
|
||||
currentWeight,
|
||||
fontA()?.name,
|
||||
);
|
||||
const wB = measureText(
|
||||
ctx,
|
||||
testFragment,
|
||||
fontB().name,
|
||||
fontSize,
|
||||
currentWeight,
|
||||
fontB()?.name,
|
||||
);
|
||||
|
||||
if (Math.max(wA, wB) <= availableWidth) {
|
||||
|
||||
Reference in New Issue
Block a user