|
11 | 11 | aspectRatio, // e.g., 369/93 or 16/9 |
12 | 12 | stateMachine = "State Machine 1", |
13 | 13 | fallbackImages = [], // Array of {src, className, alt} |
14 | | - fit = 'Contain', // Rive fit mode |
| 14 | + fit = 'Contain', // Rive fit mode (Contain, Cover, FitWidth, FitHeight, None) |
15 | 15 | eventHandlers = {} // Custom event handlers: {'Event Name': (eventData) => {...}} |
16 | 16 | } = config; |
17 | 17 |
|
|
44 | 44 | } |
45 | 45 |
|
46 | 46 | try { |
47 | | - // Calculate correct dimensions with high-DPI support |
48 | | - const rect = riveContainer.getBoundingClientRect(); |
49 | | - |
50 | | - // Use available width, fallback to a reasonable default if container has no width yet |
51 | | - const width = rect.width > 0 ? rect.width : 800; |
52 | | - const height = width / aspectRatio; // Force correct aspect ratio |
53 | | - |
54 | | - // Set container dimensions to prevent layout shift |
55 | | - riveContainer.style.width = width + 'px'; |
56 | | - riveContainer.style.height = height + 'px'; |
57 | | - |
58 | | - // Also ensure the parent container accommodates the content |
59 | | - if (sdkRiveContainer) { |
60 | | - sdkRiveContainer.style.minHeight = height + 'px'; |
| 47 | + // Set container aspect ratio while respecting existing layout |
| 48 | + const currentWidth = riveContainer.offsetWidth || riveContainer.clientWidth; |
| 49 | + if (currentWidth > 0) { |
| 50 | + // Use existing width, set height based on aspect ratio |
| 51 | + riveContainer.style.height = (currentWidth / aspectRatio) + 'px'; |
| 52 | + } else { |
| 53 | + // Fallback: use CSS aspect-ratio if container has no initial width |
| 54 | + riveContainer.style.aspectRatio = aspectRatio.toString(); |
| 55 | + riveContainer.style.width = '100%'; |
61 | 56 | } |
62 | 57 |
|
63 | | - // Force minimum 2x resolution for crispness (even on non-retina displays) |
64 | | - const dpr = Math.max(window.devicePixelRatio || 1, 2); |
65 | | - canvas.width = width * dpr; |
66 | | - canvas.height = height * dpr; |
67 | | - |
68 | | - // Set explicit CSS size to prevent stretching |
69 | | - canvas.style.width = width + 'px'; |
70 | | - canvas.style.height = height + 'px'; |
71 | | - canvas.style.display = 'block'; |
72 | | - |
73 | | - // Create Rive instance |
| 58 | + // Let Rive handle canvas sizing internally - much simpler! |
74 | 59 | const r = new rive.Rive({ |
75 | 60 | src: riveUrl, |
76 | 61 | canvas: canvas, |
77 | 62 | autoplay: true, |
78 | 63 | stateMachines: stateMachine, |
79 | 64 | layout: new rive.Layout({ |
80 | | - fit: rive.Fit[fit], |
| 65 | + fit: rive.Fit[fit], // Configurable fit mode |
81 | 66 | alignment: rive.Alignment.Center |
82 | 67 | }), |
83 | 68 | shouldDisableRiveListeners: false, // Enable native Rive interactions (hover, click, etc.) |
|
86 | 71 | canvas.style.pointerEvents = 'auto'; |
87 | 72 | canvas.style.userSelect = 'none'; |
88 | 73 |
|
| 74 | + // Critical: Resize drawing surface to canvas after load |
| 75 | + r.resizeDrawingSurfaceToCanvas(); |
| 76 | + |
89 | 77 | // Set up dynamic cursor changes based on Rive's interactive areas |
90 | 78 | setupDynamicCursor(canvas, r, stateMachine); |
91 | 79 |
|
|
110 | 98 | // Store instance for cleanup |
111 | 99 | canvas._riveInstance = r; |
112 | 100 |
|
113 | | - // Add resize observer for responsive behavior |
114 | | - const resizeObserver = new ResizeObserver(entries => { |
115 | | - for (let entry of entries) { |
116 | | - if (entry.target === riveContainer) { |
117 | | - const newWidth = entry.contentRect.width; |
118 | | - if (newWidth > 0) { |
119 | | - const newHeight = newWidth / aspectRatio; |
120 | | - |
121 | | - // Update container size |
122 | | - riveContainer.style.height = newHeight + 'px'; |
123 | | - if (sdkRiveContainer) { |
124 | | - sdkRiveContainer.style.minHeight = newHeight + 'px'; |
125 | | - } |
126 | | - |
127 | | - // Update canvas size |
128 | | - const dpr = Math.max(window.devicePixelRatio || 1, 2); |
129 | | - canvas.width = newWidth * dpr; |
130 | | - canvas.height = newHeight * dpr; |
131 | | - canvas.style.width = newWidth + 'px'; |
132 | | - canvas.style.height = newHeight + 'px'; |
133 | | - |
134 | | - // Resize Rive animation |
135 | | - if (r && r.resizeDrawingSurfaceToCanvas) { |
136 | | - r.resizeDrawingSurfaceToCanvas(); |
137 | | - } |
138 | | - } |
139 | | - } |
| 101 | + // Simple resize handling (following Rive best practices) |
| 102 | + const windowResizeHandler = () => { |
| 103 | + // Let Rive handle the canvas sizing internally |
| 104 | + if (r && r.resizeDrawingSurfaceToCanvas) { |
| 105 | + r.resizeDrawingSurfaceToCanvas(); |
140 | 106 | } |
141 | | - }); |
| 107 | + }; |
| 108 | + |
| 109 | + // Add window resize listener (as per Rive documentation) |
| 110 | + window.addEventListener('resize', windowResizeHandler, false); |
142 | 111 |
|
143 | | - resizeObserver.observe(riveContainer); |
144 | | - canvas._resizeObserver = resizeObserver; |
| 112 | + // Store cleanup function |
| 113 | + canvas._windowResizeHandler = windowResizeHandler; |
145 | 114 |
|
146 | 115 | } catch (error) { |
147 | 116 | console.error('Rive creation error:', error); |
|
329 | 298 | canvas._riveInstance.cleanup(); |
330 | 299 | canvas._riveInstance = null; |
331 | 300 | } |
332 | | - if (canvas._resizeObserver) { |
333 | | - canvas._resizeObserver.disconnect(); |
334 | | - canvas._resizeObserver = null; |
| 301 | + if (canvas._windowResizeHandler) { |
| 302 | + window.removeEventListener('resize', canvas._windowResizeHandler, false); |
| 303 | + canvas._windowResizeHandler = null; |
335 | 304 | } |
336 | 305 | }); |
337 | 306 | } |
|
0 commit comments