responsive-image-canvas/src/utils/motionPresets.ts
BaekRyang 4db9839f28 feat: Add motion preset registration API
- 모션 프리셋을 동적으로 등록하고 관리할 수 있는 API를 추가했습니다.
- `registerMotionPreset`, `registerMotionPresets`, `unregisterMotionPreset`, `getRegisteredPresets`, `hasPreset`, `resetToBuiltInPresets` 함수를 제공합니다.
- `MotionPreset` 타입을 `BuiltInMotionPreset`과 사용자 정의 문자열을 포함하도록 확장했습니다.
- `MotionPresetDefinition` 타입을 추가하여 커스텀 프리셋 정의 방식을 명확히 했습니다.
2025-11-26 11:05:36 +09:00

164 lines
4.5 KiB
TypeScript

import type {MotionPreset, MotionPresetDefinition, Point, RotationPresetChecker} from '../types';
/**
* 프리셋 레지스트리 (내장 + 커스텀)
*/
const presetRegistry = new Map<string, MotionPresetDefinition>();
/**
* 회전 프리셋 목록
*/
const rotationPresets = new Set<string>(['rotate-cw', 'rotate-ccw']);
/**
* 내장 프리셋 정의
*/
const BUILT_IN_PRESETS: Record<string, MotionPresetDefinition> = {
'none': () => ({x: 0, y: 0}),
'horizontal': (strength) => ({x: strength, y: 0}),
'vertical': (strength) => ({x: 0, y: strength}),
'rotate-cw': (strength) => ({x: strength, y: 0}),
'rotate-ccw': (strength) => ({x: -strength, y: 0}),
'pulse': (strength) => ({x: strength, y: strength}),
'diagonal-1': (strength) => ({x: strength * 0.707, y: strength * 0.707}),
'diagonal-2': (strength) => ({x: strength * 0.707, y: -strength * 0.707}),
};
// 내장 프리셋 등록
Object.entries(BUILT_IN_PRESETS).forEach(([name, definition]) => {
presetRegistry.set(name, definition);
});
/**
* 커스텀 모션 프리셋 등록
* @param name 프리셋 이름
* @param definition 프리셋 정의 함수 (strength를 받아 Point 반환)
* @param options 추가 옵션
* @param options.isRotation 회전 애니메이션 여부 (true면 원운동)
*
* @example
* // 좌우 진짜 왕복 (좌↔우)
* registerMotionPreset('horizontal-full', (strength) => ({
* x: strength * 2, // 진폭 2배
* y: 0
* }));
*
* // 8자 모양 운동 (회전)
* registerMotionPreset('figure-8', (strength) => ({
* x: strength,
* y: strength * 0.5
* }), { isRotation: true });
*/
export function registerMotionPreset(
name: string,
definition: MotionPresetDefinition,
options?: { isRotation?: boolean }
): void {
presetRegistry.set(name, definition);
if (options?.isRotation) {
rotationPresets.add(name);
} else {
rotationPresets.delete(name);
}
}
/**
* 여러 프리셋을 한번에 등록
* @param presets 프리셋 맵 (이름 → 정의)
* @param rotationPresetNames 회전 프리셋 이름 목록
*
* @example
* registerMotionPresets({
* 'horizontal-full': (s) => ({x: s * 2, y: 0}),
* 'wave': (s) => ({x: s, y: s * 0.3}),
* }, ['wave']); // wave는 회전 애니메이션
*/
export function registerMotionPresets(
presets: Record<string, MotionPresetDefinition>,
rotationPresetNames?: string[]
): void {
Object.entries(presets).forEach(([name, definition]) => {
presetRegistry.set(name, definition);
});
rotationPresetNames?.forEach(name => rotationPresets.add(name));
}
/**
* 프리셋 등록 해제
* @param name 프리셋 이름
* @returns 해제 성공 여부
*/
export function unregisterMotionPreset(name: string): boolean {
rotationPresets.delete(name);
return presetRegistry.delete(name);
}
/**
* 등록된 모든 프리셋 이름 조회
* @returns 프리셋 이름 배열
*/
export function getRegisteredPresets(): string[] {
return Array.from(presetRegistry.keys());
}
/**
* 프리셋 존재 여부 확인
* @param name 프리셋 이름
* @returns 존재 여부
*/
export function hasPreset(name: string): boolean {
return presetRegistry.has(name);
}
/**
* 내장 프리셋으로 초기화 (커스텀 프리셋 모두 제거)
*/
export function resetToBuiltInPresets(): void {
presetRegistry.clear();
rotationPresets.clear();
Object.entries(BUILT_IN_PRESETS).forEach(([name, definition]) => {
presetRegistry.set(name, definition);
});
rotationPresets.add('rotate-cw');
rotationPresets.add('rotate-ccw');
}
/**
* 모션 프리셋을 벡터로 변환
* @param preset 모션 프리셋
* @param strength 모션 강도 (기본값: 0.1)
* @returns 계산된 벡터 (vectorA)
*/
export function presetToVector(preset: MotionPreset, strength: number = 0.1): Point {
const definition = presetRegistry.get(preset);
if (definition) {
return definition(strength);
}
// 등록되지 않은 프리셋은 none으로 처리
console.warn(`Unknown motion preset: "${preset}". Falling back to "none".`);
return {x: 0, y: 0};
}
/**
* 프리셋이 회전 타입인지 확인
*/
export function isRotationPreset(preset?: MotionPreset): boolean {
if (!preset) return false;
return rotationPresets.has(preset);
}
/**
* 커스텀 회전 프리셋 판별 함수 등록
* @param checker 판별 함수
* @deprecated isRotation 옵션을 registerMotionPreset에 전달하세요
*/
export function setRotationChecker(checker: RotationPresetChecker): void {
// Legacy support - 기존 코드 호환성을 위해 유지
console.warn('setRotationChecker is deprecated. Use registerMotionPreset with { isRotation: true } option instead.');
}