# Animation > High-performance animations using requestAnimationFrame, drawCell, and updateCells. --- .. toc:: ### Overview Dash Glide Grid supports several animation patterns, each with different trade-offs between simplicity and performance. The key principle: **never use dcc.Interval with Python callbacks for animations** - they cause constant server roundtrips and "Updating..." messages. All animation functions are in `assets/dgg_animation.js` and support dark mode. ### Choosing the Right Pattern | Pattern | Complexity | Performance | Use Case | |---------|------------|-------------|----------| | `setProps` + highlightRegions | Simple | Good | Pulsing overlays, status indicators | | `drawCell` + requestAnimationFrame | Medium | Better | Custom visual effects (waves, glows) | | `setProps` + FPS throttling | Medium | Better | Hover effects, selection highlights | | `updateCells` + drawCell | Advanced | Best | Visual-only flash effects | | `updateCells` + themeOverride | Advanced | Best | Persistent cell colors (Game of Life) | ### Pattern 1: Clientside Highlight Pulsing Use `requestAnimationFrame` with `setProps({ highlightRegions })` to create pulsing overlays. No "Updating..." message because we're not using dcc.Interval. .. exec::examples.reference.animation.clientside_pulse :code: false :defaultExpanded: false :withExpandedButton: true **When to use:** - Status indicators (warning/error rows) - Simple attention-drawing effects - When you don't need custom cell rendering **Key points:** - `requestAnimationFrame` controls the animation loop - `setProps({ highlightRegions })` updates visual state directly - No dcc.Interval = no React reconciliation overhead - FPS throttling (30 FPS) saves CPU/battery ### Pattern 2: drawCell + requestAnimationFrame For custom visual effects like waves, glows, or particle animations, use a custom `drawCell` function combined with a JavaScript animation loop. Click "Start" to enable the effect. .. exec::examples.reference.animation.wave_effect :code: false :defaultExpanded: false :withExpandedButton: true **When to use:** - Custom visual effects (waves, glows, particles) - Mouse-following animations - Per-cell custom rendering **Key points:** - `drawCell` function receives canvas context and cell info - `requestAnimationFrame` loop controls animation timing - `setProps({ redrawTrigger })` triggers grid to call drawCell again - Track mouse position via pointer events - Always provide a "Stop" button to clean up animation loops ### Pattern 3: requestAnimationFrame + setProps with FPS Throttling For hover effects and selection highlights, use a JavaScript animation loop that updates grid props directly. Include FPS throttling to save CPU/battery. Click "Start Pulse" then select cells to see them pulse. .. exec::examples.reference.animation.pulse_selection :code: false :defaultExpanded: false :withExpandedButton: true **When to use:** - Selection pulse effects - Hover-based highlights - When you need FPS control **Key points:** - Get `setProps` via React fiber traversal - FPS throttling prevents unnecessary CPU usage - Update `highlightRegions` or other props directly - Read grid state (selection, data) from props ### Pattern 4A: updateCells + drawCell (Visual Effects) For high-performance visual effects, use `updateCells` to mark cells for re-render and `drawCell` to render flash effects. The visual effect is handled entirely by drawCell - no data modification. .. exec::examples.reference.animation.draw_cell_updates :code: false :defaultExpanded: false :withExpandedButton: true **When to use:** - Visual flash/highlight effects - When you don't want to modify cell data - Temporary effects that fade out **Key points:** - `updateCells([{cell: [col, row]}, ...])` marks cells for re-render - `drawCell` tracks recently updated cells and renders flash - Effect is purely visual - data unchanged - Flash fades out over time (configurable duration) ### Pattern 4B: updateCells + themeOverride (Data Modification) For persistent cell coloring (like Game of Life), modify the actual cell data with `themeOverride`, then call `updateCells` to re-render. Colors persist until explicitly cleared. .. exec::examples.reference.animation.data_updates :code: false :defaultExpanded: false :withExpandedButton: true **When to use:** - Game of Life, cellular automata - Persistent cell highlighting - Heatmaps, status grids **Key points:** - Modify `gridData[row][colId].themeOverride.bgCell` directly - Call `updateCells` to mark cells for re-render - Grid reads colors from themeOverride during render - Colors persist until cleared **How it works:** ```javascript // 1. Get grid data reference const gridData = getGridData(gridId); // 2. Modify cell with themeOverride gridData[row][colId] = { kind: 'text', data: cellValue, displayData: cellValue, themeOverride: { bgCell: '#DBEAFE' } // Blue tint }; // 3. Mark cell for re-render gridRef.updateCells([{ cell: [col, row] }]); ``` ### Accessing Grid Ref Dash Glide Grid exposes grid refs via `window._glideGridRefs` for high-performance access: ```javascript function getGridRef(gridId) { return window._glideGridRefs?.[gridId] || null; } // Usage const gridRef = getGridRef('my-grid-id'); if (gridRef) { gridRef.updateCells([{ cell: [0, 0] }, { cell: [1, 1] }]); } ``` ### Getting setProps To update Dash component props from JavaScript: ```javascript function getSetProps(gridElement) { if (gridElement._dashprivate_setProps) { return gridElement._dashprivate_setProps; } const key = Object.keys(gridElement).find(k => k.startsWith('__reactFiber$')); if (!key) return null; let fiber = gridElement[key]; while (fiber) { if (fiber.memoizedProps?.setProps) { return fiber.memoizedProps.setProps; } fiber = fiber.return; } return null; } ``` ### Dark Mode Support All animation functions use `getThemeColors()` to detect dark mode and adjust colors: ```javascript function getThemeColors() { const isDark = document.documentElement.getAttribute('data-mantine-color-scheme') === 'dark'; return { isDark, bgCell: isDark ? '#1A1B1E' : '#ffffff', accent: isDark ? 'rgba(99, 179, 237, 0.4)' : 'rgba(59, 130, 246, 0.3)', // ... other theme-aware colors }; } ``` ### Performance Best Practices 1. **Never use dcc.Interval for animations** - It causes constant React reconciliation and "Updating..." messages 2. **Use requestAnimationFrame** - Syncs with browser refresh rate: ```javascript function animate(timestamp) { // Your animation logic requestAnimationFrame(animate); } requestAnimationFrame(animate); ``` 3. **Use FPS throttling** - 30 FPS is usually sufficient: ```javascript const targetFps = 30; const frameInterval = 1000 / targetFps; if (timestamp - lastFrameTime >= frameInterval) { lastFrameTime = timestamp; // Update } ``` 4. **Batch cell updates** - Collect all changes, then call `updateCells` once: ```javascript const cells = []; for (let i = 0; i < 100; i++) { cells.push({ cell: [col, row] }); } gridRef.updateCells(cells); // Single call ``` 5. **Clean up animations** - Stop animation loops when not needed: ```javascript function cleanup() { isRunning = false; if (animationId) cancelAnimationFrame(animationId); } ``` 6. **Use `highlightRegions` for overlays** - Faster than updating cell data when you just need visual indicators ### Props Reference | Property | Type | Description | |----------|------|-------------| | `redrawTrigger` | number \| string | Change to force grid redraw | | `highlightRegions` | list[dict] | Overlay regions with color and range | | `drawCell` | dict | Custom cell rendering function | ### Highlight Region Object | Property | Type | Description | |----------|------|-------------| | `color` | string | RGBA color (e.g., "rgba(255, 0, 0, 0.3)") | | `range` | dict | Cell range: `{x, y, width, height}` | | `style` | string | Border style: "solid", "dashed", "no-outline" | --- *Source: /reference/animation* *Generated with dash-improve-my-llms*