mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
115 lines
2.7 KiB
TypeScript
115 lines
2.7 KiB
TypeScript
import type {
|
|
AnimationPath,
|
|
ElementAnimations,
|
|
ChannelData,
|
|
ScalarAnimationChannel,
|
|
ScalarGraphChannel,
|
|
ScalarGraphKeyframeContext,
|
|
} from "@/animation/types";
|
|
import type { ChannelEasingMode } from "@/params";
|
|
import { isCompositeChannelData, isLeafChannelData } from "./channel-data";
|
|
import { isScalarChannel } from "./interpolation";
|
|
|
|
export interface EditableScalarChannels {
|
|
easingMode: ChannelEasingMode;
|
|
channels: ScalarGraphChannel[];
|
|
}
|
|
|
|
function isScalarAnimationChannel(
|
|
channel: ChannelData | undefined,
|
|
): channel is ScalarAnimationChannel {
|
|
return isLeafChannelData(channel) && isScalarChannel(channel);
|
|
}
|
|
|
|
function getEasingModeForChannelData({
|
|
data,
|
|
}: {
|
|
data: ChannelData | undefined;
|
|
}): ChannelEasingMode {
|
|
return isCompositeChannelData(data) &&
|
|
["r", "g", "b", "a"].every((componentKey) => componentKey in data)
|
|
? "shared"
|
|
: "independent";
|
|
}
|
|
|
|
export function getEditableScalarChannels({
|
|
animations,
|
|
propertyPath,
|
|
}: {
|
|
animations: ElementAnimations | undefined;
|
|
propertyPath: AnimationPath;
|
|
}): EditableScalarChannels | null {
|
|
const data = animations?.[propertyPath];
|
|
if (!data) {
|
|
return null;
|
|
}
|
|
|
|
const channelEntries = isLeafChannelData(data)
|
|
? [["value", data] as const]
|
|
: Object.entries(data);
|
|
const channels = channelEntries.flatMap(([componentKey, channel]) => {
|
|
if (!isScalarAnimationChannel(channel)) {
|
|
return [];
|
|
}
|
|
|
|
return [
|
|
{
|
|
propertyPath,
|
|
componentKey,
|
|
channel,
|
|
} satisfies ScalarGraphChannel,
|
|
];
|
|
});
|
|
|
|
return { easingMode: getEasingModeForChannelData({ data }), channels };
|
|
}
|
|
|
|
export function getEditableScalarChannel({
|
|
animations,
|
|
propertyPath,
|
|
componentKey,
|
|
}: {
|
|
animations: ElementAnimations | undefined;
|
|
propertyPath: AnimationPath;
|
|
componentKey: string;
|
|
}): ScalarGraphChannel | null {
|
|
const result = getEditableScalarChannels({ animations, propertyPath });
|
|
return result?.channels.find((channel) => channel.componentKey === componentKey) ?? null;
|
|
}
|
|
|
|
export function getScalarKeyframeContext({
|
|
animations,
|
|
propertyPath,
|
|
componentKey,
|
|
keyframeId,
|
|
}: {
|
|
animations: ElementAnimations | undefined;
|
|
propertyPath: AnimationPath;
|
|
componentKey: string;
|
|
keyframeId: string;
|
|
}): ScalarGraphKeyframeContext | null {
|
|
const scalarChannel = getEditableScalarChannel({
|
|
animations,
|
|
propertyPath,
|
|
componentKey,
|
|
});
|
|
if (!scalarChannel) {
|
|
return null;
|
|
}
|
|
|
|
const keyframeIndex = scalarChannel.channel.keys.findIndex(
|
|
(keyframe) => keyframe.id === keyframeId,
|
|
);
|
|
if (keyframeIndex < 0) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
...scalarChannel,
|
|
keyframe: scalarChannel.channel.keys[keyframeIndex],
|
|
keyframeIndex,
|
|
previousKey: scalarChannel.channel.keys[keyframeIndex - 1] ?? null,
|
|
nextKey: scalarChannel.channel.keys[keyframeIndex + 1] ?? null,
|
|
};
|
|
}
|