mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
refactor: new parameters modulerefactor: unify element params
This commit is contained in:
@@ -9,7 +9,12 @@ import {
|
||||
getElementLocalTime,
|
||||
} from "@/animation";
|
||||
import { resolveTransformAtTime } from "@/rendering/animation-values";
|
||||
import { buildTransformFromParams } from "@/rendering";
|
||||
import { resolveTextLayout } from "@/text/primitives";
|
||||
import {
|
||||
buildTextBackgroundFromElement,
|
||||
buildTextLayoutParamsFromElement,
|
||||
} from "@/text/measure-element";
|
||||
|
||||
export function TextEditOverlay({
|
||||
trackId,
|
||||
@@ -42,7 +47,7 @@ export function TextEditOverlay({
|
||||
if (!div) return;
|
||||
const text = div.innerText;
|
||||
editor.timeline.previewElements({
|
||||
updates: [{ trackId, elementId, updates: { content: text } }],
|
||||
updates: [{ trackId, elementId, updates: { params: { content: text } } }],
|
||||
});
|
||||
}, [editor.timeline, trackId, elementId]);
|
||||
|
||||
@@ -69,7 +74,7 @@ export function TextEditOverlay({
|
||||
elementDuration: element.duration,
|
||||
});
|
||||
const transform = resolveTransformAtTime({
|
||||
baseTransform: element.transform,
|
||||
baseTransform: buildTransformFromParams({ params: element.params }),
|
||||
animations: element.animations,
|
||||
localTime,
|
||||
});
|
||||
@@ -80,26 +85,17 @@ export function TextEditOverlay({
|
||||
});
|
||||
|
||||
const { x: displayScaleX } = viewport.getDisplayScale();
|
||||
const textParams = buildTextLayoutParamsFromElement({ element });
|
||||
const resolvedTextLayout = resolveTextLayout({
|
||||
text: {
|
||||
content: element.content,
|
||||
fontSize: element.fontSize,
|
||||
fontFamily: element.fontFamily,
|
||||
fontWeight: element.fontWeight,
|
||||
fontStyle: element.fontStyle,
|
||||
textAlign: element.textAlign,
|
||||
textDecoration: element.textDecoration,
|
||||
letterSpacing: element.letterSpacing,
|
||||
lineHeight: element.lineHeight,
|
||||
},
|
||||
text: textParams,
|
||||
canvasHeight: canvasSize.height,
|
||||
});
|
||||
|
||||
const lineHeight = element.lineHeight ?? DEFAULTS.text.lineHeight;
|
||||
const canvasLetterSpacing = element.letterSpacing ?? 0;
|
||||
const lineHeight = textParams.lineHeight ?? DEFAULTS.text.lineHeight;
|
||||
const canvasLetterSpacing = textParams.letterSpacing ?? 0;
|
||||
const lineHeightPx = resolvedTextLayout.lineHeightPx;
|
||||
|
||||
const bg = element.background;
|
||||
const bg = buildTextBackgroundFromElement({ element });
|
||||
const shouldShowBackground =
|
||||
bg.enabled && bg.color && bg.color !== "transparent";
|
||||
const fontSizeRatio = resolvedTextLayout.fontSizeRatio;
|
||||
@@ -130,17 +126,20 @@ export function TextEditOverlay({
|
||||
className="cursor-text select-text outline-none whitespace-pre"
|
||||
style={{
|
||||
fontSize: resolvedTextLayout.scaledFontSize,
|
||||
fontFamily: element.fontFamily,
|
||||
fontWeight: element.fontWeight === "bold" ? "bold" : "normal",
|
||||
fontStyle: element.fontStyle === "italic" ? "italic" : "normal",
|
||||
textAlign: element.textAlign,
|
||||
fontFamily: textParams.fontFamily,
|
||||
fontWeight: textParams.fontWeight === "bold" ? "bold" : "normal",
|
||||
fontStyle: textParams.fontStyle === "italic" ? "italic" : "normal",
|
||||
textAlign: textParams.textAlign,
|
||||
letterSpacing: `${canvasLetterSpacing}px`,
|
||||
lineHeight,
|
||||
color: "transparent",
|
||||
caretColor: element.color,
|
||||
caretColor:
|
||||
typeof element.params.color === "string"
|
||||
? element.params.color
|
||||
: "#ffffff",
|
||||
backgroundColor: shouldShowBackground ? bg.color : "transparent",
|
||||
minHeight: lineHeightPx,
|
||||
textDecoration: element.textDecoration ?? "none",
|
||||
textDecoration: textParams.textDecoration ?? "none",
|
||||
padding: shouldShowBackground
|
||||
? `${canvasPaddingY}px ${canvasPaddingX}px`
|
||||
: 0,
|
||||
@@ -150,7 +149,7 @@ export function TextEditOverlay({
|
||||
onBlur={onCommit}
|
||||
onKeyDown={(event) => handleKeyDown({ event })}
|
||||
>
|
||||
{element.content || ""}
|
||||
{textParams.content}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -18,7 +18,8 @@ import {
|
||||
type SnapLine,
|
||||
} from "@/preview/preview-snap";
|
||||
import type { TCanvasSize } from "@/project/types";
|
||||
import type { Transform } from "@/rendering";
|
||||
import type { ParamValues } from "@/params";
|
||||
import { buildTransformFromParams, type Transform } from "@/rendering";
|
||||
import { isVisualElement } from "@/timeline/element-utils";
|
||||
import type {
|
||||
ElementRef,
|
||||
@@ -51,6 +52,7 @@ interface DragElementSnapshot {
|
||||
readonly trackId: string;
|
||||
readonly elementId: string;
|
||||
readonly initialTransform: Transform;
|
||||
readonly initialParams: ParamValues;
|
||||
}
|
||||
|
||||
interface DraggingGesture extends CapturedPointerState {
|
||||
@@ -218,7 +220,8 @@ function toDragElementSnapshots({
|
||||
.map(({ track, element }) => ({
|
||||
trackId: track.id,
|
||||
elementId: element.id,
|
||||
initialTransform: element.transform,
|
||||
initialTransform: buildTransformFromParams({ params: element.params }),
|
||||
initialParams: element.params,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -565,16 +568,14 @@ export class PreviewInteractionController {
|
||||
snappedPosition.y - firstElement.initialTransform.position.y;
|
||||
|
||||
this.deps.timeline.previewElements(
|
||||
drag.elements.map(({ trackId, elementId, initialTransform }) => ({
|
||||
drag.elements.map(({ trackId, elementId, initialTransform, initialParams }) => ({
|
||||
trackId,
|
||||
elementId,
|
||||
updates: {
|
||||
transform: {
|
||||
...initialTransform,
|
||||
position: {
|
||||
x: initialTransform.position.x + deltaSnappedX,
|
||||
y: initialTransform.position.y + deltaSnappedY,
|
||||
},
|
||||
params: {
|
||||
...initialParams,
|
||||
"transform.positionX": initialTransform.position.x + deltaSnappedX,
|
||||
"transform.positionY": initialTransform.position.y + deltaSnappedY,
|
||||
},
|
||||
},
|
||||
})),
|
||||
|
||||
@@ -23,7 +23,8 @@ import {
|
||||
setChannel,
|
||||
} from "@/animation";
|
||||
import type { ElementAnimations } from "@/animation/types";
|
||||
import type { Transform } from "@/rendering";
|
||||
import type { ParamValues } from "@/params";
|
||||
import { buildTransformFromParams, type Transform } from "@/rendering";
|
||||
import { resolveTransformAtTime } from "@/rendering/animation-values";
|
||||
import type {
|
||||
ElementRef,
|
||||
@@ -47,6 +48,7 @@ interface CornerScaleSession extends CapturedPointerState {
|
||||
readonly trackId: string;
|
||||
readonly elementId: string;
|
||||
readonly initialTransform: Transform;
|
||||
readonly initialParams: ParamValues;
|
||||
readonly initialDistance: number;
|
||||
readonly initialBoundsCx: number;
|
||||
readonly initialBoundsCy: number;
|
||||
@@ -62,6 +64,7 @@ interface EdgeScaleSession extends CapturedPointerState {
|
||||
readonly trackId: string;
|
||||
readonly elementId: string;
|
||||
readonly initialTransform: Transform;
|
||||
readonly initialParams: ParamValues;
|
||||
readonly initialBoundsCx: number;
|
||||
readonly initialBoundsCy: number;
|
||||
readonly baseWidth: number;
|
||||
@@ -76,6 +79,7 @@ interface RotationSession extends CapturedPointerState {
|
||||
readonly trackId: string;
|
||||
readonly elementId: string;
|
||||
readonly initialTransform: Transform;
|
||||
readonly initialParams: ParamValues;
|
||||
readonly initialAngle: number;
|
||||
readonly initialBoundsCx: number;
|
||||
readonly initialBoundsCy: number;
|
||||
@@ -369,6 +373,7 @@ export class TransformHandleController {
|
||||
trackId: context.trackId,
|
||||
elementId: context.elementId,
|
||||
initialTransform: context.resolvedTransform,
|
||||
initialParams: context.element.params,
|
||||
initialDistance: getCornerDistance({
|
||||
bounds: context.bounds,
|
||||
corner,
|
||||
@@ -410,6 +415,7 @@ export class TransformHandleController {
|
||||
trackId: context.trackId,
|
||||
elementId: context.elementId,
|
||||
initialTransform: context.resolvedTransform,
|
||||
initialParams: context.element.params,
|
||||
initialAngle,
|
||||
initialBoundsCx: context.bounds.cx,
|
||||
initialBoundsCy: context.bounds.cy,
|
||||
@@ -447,6 +453,7 @@ export class TransformHandleController {
|
||||
trackId: context.trackId,
|
||||
elementId: context.elementId,
|
||||
initialTransform: context.resolvedTransform,
|
||||
initialParams: context.element.params,
|
||||
initialBoundsCx: context.bounds.cx,
|
||||
initialBoundsCy: context.bounds.cy,
|
||||
baseWidth: context.bounds.width / context.resolvedTransform.scaleX,
|
||||
@@ -561,7 +568,9 @@ export class TransformHandleController {
|
||||
element: selectedWithBounds.element,
|
||||
bounds: selectedWithBounds.bounds,
|
||||
resolvedTransform: resolveTransformAtTime({
|
||||
baseTransform: selectedWithBounds.element.transform,
|
||||
baseTransform: buildTransformFromParams({
|
||||
params: selectedWithBounds.element.params,
|
||||
}),
|
||||
animations: selectedWithBounds.element.animations,
|
||||
localTime,
|
||||
}),
|
||||
@@ -608,15 +617,18 @@ export class TransformHandleController {
|
||||
trackId: session.trackId,
|
||||
elementId: session.elementId,
|
||||
updates: {
|
||||
transform: {
|
||||
...session.initialTransform,
|
||||
scaleX: clampScaleNonZero(
|
||||
session.initialTransform.scaleX * snappedScale,
|
||||
),
|
||||
scaleY: clampScaleNonZero(
|
||||
session.initialTransform.scaleY * snappedScale,
|
||||
),
|
||||
},
|
||||
params: buildParamsWithTransform({
|
||||
params: session.initialParams,
|
||||
transform: {
|
||||
...session.initialTransform,
|
||||
scaleX: clampScaleNonZero(
|
||||
session.initialTransform.scaleX * snappedScale,
|
||||
),
|
||||
scaleY: clampScaleNonZero(
|
||||
session.initialTransform.scaleY * snappedScale,
|
||||
),
|
||||
},
|
||||
}),
|
||||
...(session.shouldClearScaleAnimation && {
|
||||
animations: session.animationsWithoutScale,
|
||||
}),
|
||||
@@ -699,17 +711,20 @@ export class TransformHandleController {
|
||||
trackId: session.trackId,
|
||||
elementId: session.elementId,
|
||||
updates: {
|
||||
transform: {
|
||||
...session.initialTransform,
|
||||
scaleX:
|
||||
session.edge === "right" || session.edge === "left"
|
||||
? xSnap.snappedScale
|
||||
: session.initialTransform.scaleX,
|
||||
scaleY:
|
||||
session.edge === "bottom"
|
||||
? ySnap.snappedScale
|
||||
: session.initialTransform.scaleY,
|
||||
},
|
||||
params: buildParamsWithTransform({
|
||||
params: session.initialParams,
|
||||
transform: {
|
||||
...session.initialTransform,
|
||||
scaleX:
|
||||
session.edge === "right" || session.edge === "left"
|
||||
? xSnap.snappedScale
|
||||
: session.initialTransform.scaleX,
|
||||
scaleY:
|
||||
session.edge === "bottom"
|
||||
? ySnap.snappedScale
|
||||
: session.initialTransform.scaleY,
|
||||
},
|
||||
}),
|
||||
...(session.shouldClearScaleAnimation && {
|
||||
animations: session.animationsWithoutScale,
|
||||
}),
|
||||
@@ -742,12 +757,32 @@ export class TransformHandleController {
|
||||
trackId: session.trackId,
|
||||
elementId: session.elementId,
|
||||
updates: {
|
||||
transform: {
|
||||
...session.initialTransform,
|
||||
rotate: snappedRotation,
|
||||
},
|
||||
params: buildParamsWithTransform({
|
||||
params: session.initialParams,
|
||||
transform: {
|
||||
...session.initialTransform,
|
||||
rotate: snappedRotation,
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function buildParamsWithTransform({
|
||||
params,
|
||||
transform,
|
||||
}: {
|
||||
params: ParamValues;
|
||||
transform: Transform;
|
||||
}): ParamValues {
|
||||
return {
|
||||
...params,
|
||||
"transform.positionX": transform.position.x,
|
||||
"transform.positionY": transform.position.y,
|
||||
"transform.scaleX": transform.scaleX,
|
||||
"transform.scaleY": transform.scaleY,
|
||||
"transform.rotate": transform.rotate,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
getElementLocalTime,
|
||||
} from "@/animation";
|
||||
import { resolveTransformAtTime } from "@/rendering/animation-values";
|
||||
import { buildTransformFromParams } from "@/rendering";
|
||||
|
||||
export interface ElementBounds {
|
||||
cx: number;
|
||||
@@ -123,7 +124,7 @@ function getElementBounds({
|
||||
|
||||
if (element.type === "video" || element.type === "image") {
|
||||
const transform = resolveTransformAtTime({
|
||||
baseTransform: element.transform,
|
||||
baseTransform: buildTransformFromParams({ params: element.params }),
|
||||
animations: element.animations,
|
||||
localTime,
|
||||
});
|
||||
@@ -140,7 +141,7 @@ function getElementBounds({
|
||||
|
||||
if (element.type === "sticker") {
|
||||
const transform = resolveTransformAtTime({
|
||||
baseTransform: element.transform,
|
||||
baseTransform: buildTransformFromParams({ params: element.params }),
|
||||
animations: element.animations,
|
||||
localTime,
|
||||
});
|
||||
@@ -155,7 +156,7 @@ function getElementBounds({
|
||||
|
||||
if (element.type === "graphic") {
|
||||
const transform = resolveTransformAtTime({
|
||||
baseTransform: element.transform,
|
||||
baseTransform: buildTransformFromParams({ params: element.params }),
|
||||
animations: element.animations,
|
||||
localTime,
|
||||
});
|
||||
@@ -170,7 +171,7 @@ function getElementBounds({
|
||||
|
||||
if (element.type === "text") {
|
||||
const transform = resolveTransformAtTime({
|
||||
baseTransform: element.transform,
|
||||
baseTransform: buildTransformFromParams({ params: element.params }),
|
||||
animations: element.animations,
|
||||
localTime,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user