feat: update text properties to use dynamic font size limits and scaling
This commit is contained in:
parent
9b5fd6eb07
commit
c6666fd385
|
|
@ -30,6 +30,7 @@ import {
|
|||
} from "@/components/ui/tooltip";
|
||||
import { useEditor } from "@/hooks/use-editor";
|
||||
import { DEFAULT_COLOR } from "@/constants/project-constants";
|
||||
import { MIN_FONT_SIZE, MAX_FONT_SIZE } from "@/constants/text-constants";
|
||||
|
||||
export function TextProperties({
|
||||
element,
|
||||
|
|
@ -57,7 +58,7 @@ export function TextProperties({
|
|||
const parsed = parseInt(value, 10);
|
||||
const fontSize = Number.isNaN(parsed)
|
||||
? element.fontSize
|
||||
: clamp({ value: parsed, min: 8, max: 300 });
|
||||
: clamp({ value: parsed, min: MIN_FONT_SIZE, max: MAX_FONT_SIZE });
|
||||
editor.timeline.updateTextElement({
|
||||
trackId,
|
||||
elementId: element.id,
|
||||
|
|
@ -70,7 +71,7 @@ export function TextProperties({
|
|||
const parsed = parseInt(fontSizeInput, 10);
|
||||
const fontSize = Number.isNaN(parsed)
|
||||
? element.fontSize
|
||||
: clamp({ value: parsed, min: 8, max: 300 });
|
||||
: clamp({ value: parsed, min: MIN_FONT_SIZE, max: MAX_FONT_SIZE });
|
||||
setFontSizeInput(fontSize.toString());
|
||||
editor.timeline.updateTextElement({
|
||||
trackId,
|
||||
|
|
@ -274,8 +275,8 @@ export function TextProperties({
|
|||
<div className="flex items-center gap-2">
|
||||
<Slider
|
||||
value={[element.fontSize]}
|
||||
min={8}
|
||||
max={300}
|
||||
min={MIN_FONT_SIZE}
|
||||
max={MAX_FONT_SIZE}
|
||||
step={1}
|
||||
onValueChange={([value]) => {
|
||||
editor.timeline.updateTextElement({
|
||||
|
|
@ -290,8 +291,8 @@ export function TextProperties({
|
|||
<Input
|
||||
type="number"
|
||||
value={fontSizeInput}
|
||||
min={8}
|
||||
max={300}
|
||||
min={MIN_FONT_SIZE}
|
||||
max={MAX_FONT_SIZE}
|
||||
onChange={(e) =>
|
||||
handleFontSizeChange({ value: e.target.value })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,20 @@
|
|||
import type { TextElement } from "@/types/timeline";
|
||||
import { TIMELINE_CONSTANTS } from "./timeline-constants";
|
||||
|
||||
export const MIN_FONT_SIZE = 5;
|
||||
export const MAX_FONT_SIZE = 300;
|
||||
|
||||
/**
|
||||
* higher value: smaller font size
|
||||
* lower value: larger font size
|
||||
*/
|
||||
export const FONT_SIZE_SCALE_REFERENCE = 90;
|
||||
|
||||
export const DEFAULT_TEXT_ELEMENT: Omit<TextElement, "id"> = {
|
||||
type: "text",
|
||||
name: "Text",
|
||||
content: "Default Text",
|
||||
fontSize: 48,
|
||||
fontSize: 15,
|
||||
fontFamily: "Arial",
|
||||
color: "#ffffff",
|
||||
backgroundColor: "transparent",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,21 @@
|
|||
import type { CanvasRenderer } from "../canvas-renderer";
|
||||
import { BaseNode } from "./base-node";
|
||||
import type { TextElement } from "@/types/timeline";
|
||||
import { FONT_SIZE_SCALE_REFERENCE } from "@/constants/text-constants";
|
||||
|
||||
function scaleFontSize({
|
||||
fontSize,
|
||||
canvasHeight,
|
||||
}: {
|
||||
fontSize: number;
|
||||
canvasHeight: number;
|
||||
}): number {
|
||||
return fontSize * (canvasHeight / FONT_SIZE_SCALE_REFERENCE);
|
||||
}
|
||||
|
||||
export type TextNodeParams = TextElement & {
|
||||
canvasCenter: { x: number; y: number };
|
||||
canvasHeight: number;
|
||||
textBaseline?: CanvasTextBaseline;
|
||||
};
|
||||
|
||||
|
|
@ -32,7 +44,11 @@ export class TextNode extends BaseNode<TextNodeParams> {
|
|||
|
||||
const fontWeight = this.params.fontWeight === "bold" ? "bold" : "normal";
|
||||
const fontStyle = this.params.fontStyle === "italic" ? "italic" : "normal";
|
||||
renderer.context.font = `${fontStyle} ${fontWeight} ${this.params.fontSize}px ${this.params.fontFamily}`;
|
||||
const scaledFontSize = scaleFontSize({
|
||||
fontSize: this.params.fontSize,
|
||||
canvasHeight: this.params.canvasHeight,
|
||||
});
|
||||
renderer.context.font = `${fontStyle} ${fontWeight} ${scaledFontSize}px ${this.params.fontFamily}`;
|
||||
renderer.context.textAlign = this.params.textAlign;
|
||||
renderer.context.textBaseline = this.params.textBaseline || "middle";
|
||||
renderer.context.fillStyle = this.params.color;
|
||||
|
|
@ -43,9 +59,9 @@ export class TextNode extends BaseNode<TextNodeParams> {
|
|||
if (this.params.backgroundColor) {
|
||||
const metrics = renderer.context.measureText(this.params.content);
|
||||
const ascent =
|
||||
metrics.actualBoundingBoxAscent ?? this.params.fontSize * 0.8;
|
||||
metrics.actualBoundingBoxAscent ?? scaledFontSize * 0.8;
|
||||
const descent =
|
||||
metrics.actualBoundingBoxDescent ?? this.params.fontSize * 0.2;
|
||||
metrics.actualBoundingBoxDescent ?? scaledFontSize * 0.2;
|
||||
const textW = metrics.width;
|
||||
const textH = ascent + descent;
|
||||
const padX = 8;
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ export function buildScene(params: BuildSceneParams) {
|
|||
new TextNode({
|
||||
...element,
|
||||
canvasCenter: { x: canvasSize.width / 2, y: canvasSize.height / 2 },
|
||||
canvasHeight: canvasSize.height,
|
||||
textBaseline: "middle",
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue