Files
memefast/resources/js/modules/editor/utils/timeline-template-processor.js
2025-06-28 12:54:30 +08:00

111 lines
5.0 KiB
JavaScript

// utils/timeline-template-processor.js
export const generateTimelineFromTemplate = (dimensions, template, mediaStoreData) => {
const { selectedMeme, selectedBackground, currentCaption } = mediaStoreData;
// If no selections, return empty timeline
if (!selectedMeme && !selectedBackground) {
return [];
}
// Calculate duration based on template config
let maxDuration = 5; // default fallback
if (template.max_duration_based_on === 'memes' && selectedMeme?.duration) {
maxDuration = parseFloat(selectedMeme.duration);
}
// Process each timeline element
const processedTimeline = template.timeline
.map((element) => {
let processedElement = { ...element };
// Update duration for all elements
processedElement.duration = maxDuration;
// Process by element ID/type
switch (element.id) {
case 'background':
if (selectedBackground) {
processedElement.source = selectedBackground.media_url;
processedElement.name = selectedBackground.prompt || 'Background';
processedElement.media_width = selectedBackground.media_width;
processedElement.media_height = selectedBackground.media_height;
const canvasWidth = dimensions.width;
const canvasHeight = dimensions.height;
// Calculate scale factors to fit media within canvas while maintaining aspect ratio
const scaleX = canvasWidth / selectedBackground.media_width;
const scaleY = canvasHeight / selectedBackground.media_height;
// Use the larger scale factor to ensure the media fills the entire canvas
const scale = Math.max(scaleX, scaleY);
// Calculate final dimensions
const scaledWidth = selectedBackground.media_width * scale;
const scaledHeight = selectedBackground.media_height * scale;
// Center the scaled media within the canvas
const offsetX = (canvasWidth - scaledWidth) / 2;
const offsetY = (canvasHeight - scaledHeight) / 2;
// Set the processed element properties
processedElement.width = scaledWidth;
processedElement.height = scaledHeight;
processedElement.x = offsetX;
processedElement.y = offsetY;
} else {
return null; // Skip if no background selected
}
break;
case 'meme':
if (selectedMeme) {
processedElement.source_webm = selectedMeme.webm_url;
processedElement.source_mov = selectedMeme.mov_url;
processedElement.poster = selectedMeme.webp_url;
processedElement.name = selectedMeme.name;
processedElement.media_width = selectedMeme.media_width;
processedElement.media_height = selectedMeme.media_height;
processedElement.width = selectedMeme.media_width;
processedElement.height = selectedMeme.media_height;
} else {
return null; // Skip if no meme selected
}
break;
case 'caption':
if (currentCaption) {
processedElement.text = currentCaption;
// Calculate text width properties for better rendering consistency
const textWidth = Math.min(dimensions.width * 0.8, 600); // Max 80% of canvas width or 600px
processedElement.fixedWidth = textWidth;
processedElement.offsetX = textWidth / 2; // Center alignment offset
// Ensure text is positioned properly (center horizontally)
if (!processedElement.x || processedElement.x === 0) {
processedElement.x = dimensions.width / 2; // Center horizontally
}
// Ensure text has proper vertical positioning
if (!processedElement.y || processedElement.y === 0) {
processedElement.y = dimensions.height * 0.1; // 10% from top
}
} else {
return null; // Skip if no caption
}
break;
default:
// Keep element as-is for any other types
break;
}
return processedElement;
})
.filter(Boolean); // Remove null elements
return processedTimeline;
};