Skip to content

Commit c6666fd

Browse files
committed
feat: update text properties to use dynamic font size limits and scaling
1 parent 9b5fd6e commit c6666fd

File tree

4 files changed

+37
-10
lines changed

4 files changed

+37
-10
lines changed

apps/web/src/components/editor/panels/properties/text-properties.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
} from "@/components/ui/tooltip";
3131
import { useEditor } from "@/hooks/use-editor";
3232
import { DEFAULT_COLOR } from "@/constants/project-constants";
33+
import { MIN_FONT_SIZE, MAX_FONT_SIZE } from "@/constants/text-constants";
3334

3435
export function TextProperties({
3536
element,
@@ -57,7 +58,7 @@ export function TextProperties({
5758
const parsed = parseInt(value, 10);
5859
const fontSize = Number.isNaN(parsed)
5960
? element.fontSize
60-
: clamp({ value: parsed, min: 8, max: 300 });
61+
: clamp({ value: parsed, min: MIN_FONT_SIZE, max: MAX_FONT_SIZE });
6162
editor.timeline.updateTextElement({
6263
trackId,
6364
elementId: element.id,
@@ -70,7 +71,7 @@ export function TextProperties({
7071
const parsed = parseInt(fontSizeInput, 10);
7172
const fontSize = Number.isNaN(parsed)
7273
? element.fontSize
73-
: clamp({ value: parsed, min: 8, max: 300 });
74+
: clamp({ value: parsed, min: MIN_FONT_SIZE, max: MAX_FONT_SIZE });
7475
setFontSizeInput(fontSize.toString());
7576
editor.timeline.updateTextElement({
7677
trackId,
@@ -274,8 +275,8 @@ export function TextProperties({
274275
<div className="flex items-center gap-2">
275276
<Slider
276277
value={[element.fontSize]}
277-
min={8}
278-
max={300}
278+
min={MIN_FONT_SIZE}
279+
max={MAX_FONT_SIZE}
279280
step={1}
280281
onValueChange={([value]) => {
281282
editor.timeline.updateTextElement({
@@ -290,8 +291,8 @@ export function TextProperties({
290291
<Input
291292
type="number"
292293
value={fontSizeInput}
293-
min={8}
294-
max={300}
294+
min={MIN_FONT_SIZE}
295+
max={MAX_FONT_SIZE}
295296
onChange={(e) =>
296297
handleFontSizeChange({ value: e.target.value })
297298
}

apps/web/src/constants/text-constants.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import type { TextElement } from "@/types/timeline";
22
import { TIMELINE_CONSTANTS } from "./timeline-constants";
33

4+
export const MIN_FONT_SIZE = 5;
5+
export const MAX_FONT_SIZE = 300;
6+
7+
/**
8+
* higher value: smaller font size
9+
* lower value: larger font size
10+
*/
11+
export const FONT_SIZE_SCALE_REFERENCE = 90;
12+
413
export const DEFAULT_TEXT_ELEMENT: Omit<TextElement, "id"> = {
514
type: "text",
615
name: "Text",
716
content: "Default Text",
8-
fontSize: 48,
17+
fontSize: 15,
918
fontFamily: "Arial",
1019
color: "#ffffff",
1120
backgroundColor: "transparent",

apps/web/src/services/renderer/nodes/text-node.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
import type { CanvasRenderer } from "../canvas-renderer";
22
import { BaseNode } from "./base-node";
33
import type { TextElement } from "@/types/timeline";
4+
import { FONT_SIZE_SCALE_REFERENCE } from "@/constants/text-constants";
5+
6+
function scaleFontSize({
7+
fontSize,
8+
canvasHeight,
9+
}: {
10+
fontSize: number;
11+
canvasHeight: number;
12+
}): number {
13+
return fontSize * (canvasHeight / FONT_SIZE_SCALE_REFERENCE);
14+
}
415

516
export type TextNodeParams = TextElement & {
617
canvasCenter: { x: number; y: number };
18+
canvasHeight: number;
719
textBaseline?: CanvasTextBaseline;
820
};
921

@@ -32,7 +44,11 @@ export class TextNode extends BaseNode<TextNodeParams> {
3244

3345
const fontWeight = this.params.fontWeight === "bold" ? "bold" : "normal";
3446
const fontStyle = this.params.fontStyle === "italic" ? "italic" : "normal";
35-
renderer.context.font = `${fontStyle} ${fontWeight} ${this.params.fontSize}px ${this.params.fontFamily}`;
47+
const scaledFontSize = scaleFontSize({
48+
fontSize: this.params.fontSize,
49+
canvasHeight: this.params.canvasHeight,
50+
});
51+
renderer.context.font = `${fontStyle} ${fontWeight} ${scaledFontSize}px ${this.params.fontFamily}`;
3652
renderer.context.textAlign = this.params.textAlign;
3753
renderer.context.textBaseline = this.params.textBaseline || "middle";
3854
renderer.context.fillStyle = this.params.color;
@@ -43,9 +59,9 @@ export class TextNode extends BaseNode<TextNodeParams> {
4359
if (this.params.backgroundColor) {
4460
const metrics = renderer.context.measureText(this.params.content);
4561
const ascent =
46-
metrics.actualBoundingBoxAscent ?? this.params.fontSize * 0.8;
62+
metrics.actualBoundingBoxAscent ?? scaledFontSize * 0.8;
4763
const descent =
48-
metrics.actualBoundingBoxDescent ?? this.params.fontSize * 0.2;
64+
metrics.actualBoundingBoxDescent ?? scaledFontSize * 0.2;
4965
const textW = metrics.width;
5066
const textH = ascent + descent;
5167
const padX = 8;

apps/web/src/services/renderer/scene-builder.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export function buildScene(params: BuildSceneParams) {
8585
new TextNode({
8686
...element,
8787
canvasCenter: { x: canvasSize.width / 2, y: canvasSize.height / 2 },
88+
canvasHeight: canvasSize.height,
8889
textBaseline: "middle",
8990
}),
9091
);

0 commit comments

Comments
 (0)