mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
feat: add single player mode
This commit is contained in:
85
packages/lib/client-only/hooks/use-element-scale-size.ts
Normal file
85
packages/lib/client-only/hooks/use-element-scale-size.ts
Normal file
@ -0,0 +1,85 @@
|
||||
/* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user