mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
86 lines
2.5 KiB
TypeScript
86 lines
2.5 KiB
TypeScript
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
import { RefObject, useEffect, useState } from 'react';
|
|
|
|
/**
|
|
* Calculate the width and height of a text element.
|
|
*
|
|
* @param text The text to calculate the width and height of.
|
|
* @param fontSize The font size to apply to the text.
|
|
* @param fontFamily The font family to apply to the text.
|
|
* @returns Returns the width and height of the text.
|
|
*/
|
|
function calculateTextDimensions(
|
|
text: string,
|
|
fontSize: string,
|
|
fontFamily: string,
|
|
): { width: number; height: number } {
|
|
// Reuse old canvas if available.
|
|
let canvas = (calculateTextDimensions as { canvas?: HTMLCanvasElement }).canvas;
|
|
|
|
if (!canvas) {
|
|
canvas = document.createElement('canvas');
|
|
(calculateTextDimensions as { canvas?: HTMLCanvasElement }).canvas = canvas;
|
|
}
|
|
|
|
const context = canvas.getContext('2d');
|
|
if (!context) {
|
|
return { width: 0, height: 0 };
|
|
}
|
|
|
|
context.font = `${fontSize} ${fontFamily}`;
|
|
const metrics = context.measureText(text);
|
|
|
|
return {
|
|
width: metrics.width,
|
|
height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Calculate the scaling size to apply to a text to fit it within a container.
|
|
*
|
|
* @param container The container dimensions to fit the text within.
|
|
* @param text The text to fit within the container.
|
|
* @param fontSize The font size to apply to the text.
|
|
* @param fontFamily The font family to apply to the text.
|
|
* @returns Returns a value between 0 and 1 which represents the scaling factor to apply to the text.
|
|
*/
|
|
export const calculateTextScaleSize = (
|
|
container: { width: number; height: number },
|
|
text: string,
|
|
fontSize: string,
|
|
fontFamily: string,
|
|
) => {
|
|
const { width, height } = calculateTextDimensions(text, fontSize, fontFamily);
|
|
return Math.min(container.width / width, container.height / height, 1);
|
|
};
|
|
|
|
/**
|
|
* Given a container and child element, calculate the scaling size to apply to the child.
|
|
*/
|
|
export function useElementScaleSize(
|
|
container: { width: number; height: number },
|
|
child: RefObject<HTMLElement | null>,
|
|
fontSize: number,
|
|
fontFamily: string,
|
|
) {
|
|
const [scalingFactor, setScalingFactor] = useState(1);
|
|
|
|
useEffect(() => {
|
|
if (!child.current) {
|
|
return;
|
|
}
|
|
|
|
const scaleSize = calculateTextScaleSize(
|
|
container,
|
|
child.current.innerText,
|
|
`${fontSize}px`,
|
|
fontFamily,
|
|
);
|
|
|
|
setScalingFactor(scaleSize);
|
|
}, [child, container, fontFamily, fontSize]);
|
|
|
|
return scalingFactor;
|
|
}
|