/** Trading card aspect ratio (width / height). */ export const CARD_ASPECT_RATIO = 5 / 7; /** * Layout math for a video element using CSS object-cover inside a container. */ export function computeObjectCoverLayout(videoWidth, videoHeight, containerWidth, containerHeight) { if (!videoWidth || !videoHeight || !containerWidth || !containerHeight) { return null; } const videoAspect = videoWidth / videoHeight; const containerAspect = containerWidth / containerHeight; let renderedWidth; let renderedHeight; let offsetX; let offsetY; if (videoAspect > containerAspect) { renderedHeight = containerHeight; renderedWidth = containerHeight * videoAspect; offsetX = (containerWidth - renderedWidth) / 2; offsetY = 0; } else { renderedWidth = containerWidth; renderedHeight = containerWidth / videoAspect; offsetX = 0; offsetY = (containerHeight - renderedHeight) / 2; } return { videoWidth, videoHeight, containerWidth, containerHeight, renderedWidth, renderedHeight, offsetX, offsetY, }; } /** Map video-pixel bounds to percentage styles within an object-cover container. */ export function videoBoundsToContainerStyle(bounds, layout) { const { videoWidth, videoHeight, containerWidth, containerHeight, renderedWidth, renderedHeight, offsetX, offsetY, } = layout; const left = offsetX + (bounds.x / videoWidth) * renderedWidth; const top = offsetY + (bounds.y / videoHeight) * renderedHeight; const width = (bounds.width / videoWidth) * renderedWidth; const height = (bounds.height / videoHeight) * renderedHeight; return { left: `${(left / containerWidth) * 100}%`, top: `${(top / containerHeight) * 100}%`, width: `${(width / containerWidth) * 100}%`, height: `${(height / containerHeight) * 100}%`, }; } /** Centered card guide frame in container pixel coordinates. */ export function computeCardGuideBounds(containerWidth, containerHeight) { let width = containerWidth * 0.78; let height = width / CARD_ASPECT_RATIO; const maxHeight = containerHeight * 0.72; if (height > maxHeight) { height = maxHeight; width = height * CARD_ASPECT_RATIO; } return { left: (containerWidth - width) / 2, top: (containerHeight - height) / 2, width, height, }; } /** Card guide as percentage styles for an object-cover container. */ export function cardGuideToContainerStyle(layout) { const guide = computeCardGuideBounds(layout.containerWidth, layout.containerHeight); return { left: `${(guide.left / layout.containerWidth) * 100}%`, top: `${(guide.top / layout.containerHeight) * 100}%`, width: `${(guide.width / layout.containerWidth) * 100}%`, height: `${(guide.height / layout.containerHeight) * 100}%`, }; }