delay in animation
This commit is contained in:
@@ -2,7 +2,11 @@ import Select from "@/components/Select";
|
|||||||
import Input from "@/components/Input";
|
import Input from "@/components/Input";
|
||||||
import type { EditorObject } from "../../../store/editorStore";
|
import type { EditorObject } from "../../../store/editorStore";
|
||||||
import { ENTRANCE_ANIMATION_SELECT_ITEMS } from "../constants/entranceAnimationOptions";
|
import { ENTRANCE_ANIMATION_SELECT_ITEMS } from "../constants/entranceAnimationOptions";
|
||||||
import { DEFAULT_ENTRANCE_DURATION_MS } from "@/shared/entranceAnimation";
|
import {
|
||||||
|
DEFAULT_ENTRANCE_DURATION_MS,
|
||||||
|
DEFAULT_ENTRANCE_DELAY_MS,
|
||||||
|
MAX_ENTRANCE_DELAY_MS,
|
||||||
|
} from "@/shared/entranceAnimation";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
selectedObject: EditorObject;
|
selectedObject: EditorObject;
|
||||||
@@ -12,6 +16,7 @@ type Props = {
|
|||||||
const EntranceAnimationSettings = ({ selectedObject, onUpdate }: Props) => {
|
const EntranceAnimationSettings = ({ selectedObject, onUpdate }: Props) => {
|
||||||
const anim = selectedObject.entranceAnimation ?? "none";
|
const anim = selectedObject.entranceAnimation ?? "none";
|
||||||
const duration = selectedObject.entranceDurationMs ?? DEFAULT_ENTRANCE_DURATION_MS;
|
const duration = selectedObject.entranceDurationMs ?? DEFAULT_ENTRANCE_DURATION_MS;
|
||||||
|
const delayMs = selectedObject.entranceDelayMs ?? DEFAULT_ENTRANCE_DELAY_MS;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="pt-4 flex flex-col gap-4 border-t border-border">
|
<div className="pt-4 flex flex-col gap-4 border-t border-border">
|
||||||
@@ -23,12 +28,14 @@ const EntranceAnimationSettings = ({ selectedObject, onUpdate }: Props) => {
|
|||||||
const v = e.target.value as EditorObject["entranceAnimation"];
|
const v = e.target.value as EditorObject["entranceAnimation"];
|
||||||
onUpdate(selectedObject.id, {
|
onUpdate(selectedObject.id, {
|
||||||
entranceAnimation: v === "none" ? undefined : v,
|
entranceAnimation: v === "none" ? undefined : v,
|
||||||
...(v === "none" || !v ? { entranceDurationMs: undefined } : {}),
|
...(v === "none" || !v
|
||||||
|
? { entranceDurationMs: undefined, entranceDelayMs: undefined }
|
||||||
|
: {}),
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{anim !== "none" && (
|
{anim !== "none" && (
|
||||||
<Input
|
<><Input
|
||||||
label="مدت انیمیشن (میلیثانیه)"
|
label="مدت انیمیشن (میلیثانیه)"
|
||||||
type="number"
|
type="number"
|
||||||
min={100}
|
min={100}
|
||||||
@@ -40,8 +47,20 @@ const EntranceAnimationSettings = ({ selectedObject, onUpdate }: Props) => {
|
|||||||
onUpdate(selectedObject.id, {
|
onUpdate(selectedObject.id, {
|
||||||
entranceDurationMs: Math.min(4000, Math.max(100, n)),
|
entranceDurationMs: Math.min(4000, Math.max(100, n)),
|
||||||
});
|
});
|
||||||
}}
|
}} /><Input
|
||||||
/>
|
label="تأخیر قبل از شروع (میلیثانیه)"
|
||||||
|
type="number"
|
||||||
|
min={0}
|
||||||
|
max={MAX_ENTRANCE_DELAY_MS}
|
||||||
|
value={delayMs}
|
||||||
|
onChange={(e) => {
|
||||||
|
const n = parseInt(e.target.value, 10);
|
||||||
|
if (Number.isNaN(n)) return;
|
||||||
|
const clamped = Math.min(MAX_ENTRANCE_DELAY_MS, Math.max(0, n));
|
||||||
|
onUpdate(selectedObject.id, {
|
||||||
|
entranceDelayMs: clamped === 0 ? undefined : clamped,
|
||||||
|
});
|
||||||
|
}} /></>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ export type EditorObject = {
|
|||||||
entranceAnimation?: EntranceAnimationType;
|
entranceAnimation?: EntranceAnimationType;
|
||||||
/** مدت انیمیشن ورود به میلیثانیه (پیشفرض ۶۰۰) */
|
/** مدت انیمیشن ورود به میلیثانیه (پیشفرض ۶۰۰) */
|
||||||
entranceDurationMs?: number;
|
entranceDurationMs?: number;
|
||||||
|
/** تأخیر قبل از شروع انیمیشن ورود به میلیثانیه (پیشفرض ۰) */
|
||||||
|
entranceDelayMs?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PageGuide = {
|
export type PageGuide = {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ type ViewerDataPage = {
|
|||||||
tableData?: TableData;
|
tableData?: TableData;
|
||||||
entranceAnimation?: EditorObject["entranceAnimation"];
|
entranceAnimation?: EditorObject["entranceAnimation"];
|
||||||
entranceDurationMs?: number;
|
entranceDurationMs?: number;
|
||||||
|
entranceDelayMs?: number;
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,6 +143,9 @@ export function transformViewerDataToPages(data: ViewerData): PageData[] {
|
|||||||
if (obj.entranceDurationMs !== undefined) {
|
if (obj.entranceDurationMs !== undefined) {
|
||||||
baseObject.entranceDurationMs = obj.entranceDurationMs;
|
baseObject.entranceDurationMs = obj.entranceDurationMs;
|
||||||
}
|
}
|
||||||
|
if (obj.entranceDelayMs !== undefined) {
|
||||||
|
baseObject.entranceDelayMs = obj.entranceDelayMs;
|
||||||
|
}
|
||||||
|
|
||||||
return baseObject;
|
return baseObject;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import type { CSSProperties } from "react";
|
|||||||
import type { EditorObject } from "@/pages/editor/store/editorStore";
|
import type { EditorObject } from "@/pages/editor/store/editorStore";
|
||||||
import {
|
import {
|
||||||
DEFAULT_ENTRANCE_DURATION_MS,
|
DEFAULT_ENTRANCE_DURATION_MS,
|
||||||
|
DEFAULT_ENTRANCE_DELAY_MS,
|
||||||
ENTRANCE_ANIMATION_BASE_DELAY_MS,
|
ENTRANCE_ANIMATION_BASE_DELAY_MS,
|
||||||
|
MAX_ENTRANCE_DELAY_MS,
|
||||||
} from "@/shared/entranceAnimation";
|
} from "@/shared/entranceAnimation";
|
||||||
|
|
||||||
const ANIMATION_NAMES: Record<
|
const ANIMATION_NAMES: Record<
|
||||||
@@ -76,6 +78,11 @@ export function mergeEntranceAnimationStyle(
|
|||||||
1000;
|
1000;
|
||||||
const baseDelaySec = ENTRANCE_ANIMATION_BASE_DELAY_MS / 1000;
|
const baseDelaySec = ENTRANCE_ANIMATION_BASE_DELAY_MS / 1000;
|
||||||
const staggerSec = Math.min(elementIndex * 0.045, 1.2);
|
const staggerSec = Math.min(elementIndex * 0.045, 1.2);
|
||||||
|
const userDelayMs = Math.min(
|
||||||
|
MAX_ENTRANCE_DELAY_MS,
|
||||||
|
Math.max(DEFAULT_ENTRANCE_DELAY_MS, obj.entranceDelayMs ?? DEFAULT_ENTRANCE_DELAY_MS),
|
||||||
|
);
|
||||||
|
const userDelaySec = userDelayMs / 1000;
|
||||||
|
|
||||||
const rot = options?.rotationDeg ?? obj.rotation ?? 0;
|
const rot = options?.rotationDeg ?? obj.rotation ?? 0;
|
||||||
const opacityEnd = (obj.opacity ?? 100) / 100;
|
const opacityEnd = (obj.opacity ?? 100) / 100;
|
||||||
@@ -102,7 +109,7 @@ export function mergeEntranceAnimationStyle(
|
|||||||
willChange: "transform, opacity",
|
willChange: "transform, opacity",
|
||||||
animationName: name,
|
animationName: name,
|
||||||
animationDuration: `${durationSec}s`,
|
animationDuration: `${durationSec}s`,
|
||||||
animationDelay: `${baseDelaySec + staggerSec}s`,
|
animationDelay: `${baseDelaySec + staggerSec + userDelaySec}s`,
|
||||||
animationTimingFunction: "cubic-bezier(0.22, 1, 0.36, 1)",
|
animationTimingFunction: "cubic-bezier(0.22, 1, 0.36, 1)",
|
||||||
animationFillMode: "both",
|
animationFillMode: "both",
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
/** مدت پیشفرض انیمیشن ورود در editor و viewer (میلیثانیه) */
|
/** مدت پیشفرض انیمیشن ورود در editor و viewer (میلیثانیه) */
|
||||||
export const DEFAULT_ENTRANCE_DURATION_MS = 1000;
|
export const DEFAULT_ENTRANCE_DURATION_MS = 1000;
|
||||||
|
|
||||||
|
/** تأخیر اضافهشده توسط کاربر قبل از شروع انیمیشن (میلیثانیه؛ پیشفرض ۰) */
|
||||||
|
export const DEFAULT_ENTRANCE_DELAY_MS = 0;
|
||||||
|
|
||||||
|
/** سقف تأخیر کاربر (میلیثانیه) */
|
||||||
|
export const MAX_ENTRANCE_DELAY_MS = 30_000;
|
||||||
|
|
||||||
/** تأخیر کوتاه قبل از شروع انیمیشن ورود تا با ورق خوردن صفحه همهماهنگ شود (کمتر = حس فوریتر) */
|
/** تأخیر کوتاه قبل از شروع انیمیشن ورود تا با ورق خوردن صفحه همهماهنگ شود (کمتر = حس فوریتر) */
|
||||||
export const ENTRANCE_ANIMATION_BASE_DELAY_MS = 75;
|
export const ENTRANCE_ANIMATION_BASE_DELAY_MS = 75;
|
||||||
|
|||||||
Reference in New Issue
Block a user