| 1 | import { escapeHtml } from '../../presentation/html/escape' |
| 2 | import type { ImportedElementAnimation } from './animation-import' |
| 3 | |
| 4 | export const clampNumber = (value: unknown, fallback = 0): number => { |
| 5 | const n = Number(value) |
| 6 | return Number.isFinite(n) ? n : fallback |
| 7 | } |
| 8 | |
| 9 | |
| 10 | export const buildBlockStyle = (args: { |
| 11 | element: Record<string, unknown> |
| 12 | scaleX: number |
| 13 | scaleY: number |
| 14 | zIndex: number |
| 15 | offsetX?: number |
| 16 | offsetY?: number |
| 17 | overflow?: 'hidden' | 'visible' |
| 18 | extra?: string[] |
| 19 | }): string => { |
| 20 | const x = (clampNumber(args.element.left) + clampNumber(args.offsetX)) * args.scaleX |
| 21 | const y = (clampNumber(args.element.top) + clampNumber(args.offsetY)) * args.scaleY |
| 22 | const width = Math.max(1, clampNumber(args.element.width) * args.scaleX) |
| 23 | const height = Math.max(1, clampNumber(args.element.height) * args.scaleY) |
| 24 | const rotate = clampNumber(args.element.rotate) |
| 25 | const styles = [ |
| 26 | 'position:absolute', |
| 27 | `left:${x.toFixed(1)}px`, |
| 28 | `top:${y.toFixed(1)}px`, |
| 29 | `width:${width.toFixed(1)}px`, |
| 30 | `height:${height.toFixed(1)}px`, |
| 31 | `z-index:${args.zIndex}`, |
| 32 | `overflow:${args.overflow || 'visible'}`, |
| 33 | rotate ? `transform:rotate(${rotate.toFixed(2)}deg)` : '' |
| 34 | ] |
| 35 | return [...styles, ...(args.extra || [])].filter(Boolean).join(';') |
| 36 | } |
| 37 | |
| 38 | |
| 39 | export const buildAnimationAttrs = (animation: ImportedElementAnimation | undefined): string => { |
| 40 | if (!animation) return '' |
| 41 | return [ |
| 42 | `data-anim="${animation.type}"`, |
| 43 | animation.from ? `data-anim-from="${animation.from}"` : '', |
| 44 | animation.path ? `data-anim-path="${escapeHtml(animation.path)}"` : '', |
| 45 | `data-anim-duration="${animation.duration}"`, |
| 46 | `data-anim-delay="${animation.delay}"`, |
| 47 | animation.trigger === 'click' ? 'data-anim-trigger="click"' : '', |
| 48 | animation.clickGroup ? `data-anim-click-group="${escapeHtml(animation.clickGroup)}"` : '', |
| 49 | `data-pptx-source-spid="${escapeHtml(animation.sourceId)}"` |
| 50 | ] |
| 51 | .filter(Boolean) |
| 52 | .join(' ') |
| 53 | } |
| 54 |