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