PivotViewer - Performance
Architecture
Section titled “Architecture”PivotViewer uses several techniques for high performance with large datasets.
Web Workers
Section titled “Web Workers”Filtering and grouping operations run in a background Web Worker thread:
- Main thread: Handles UI rendering and interactions
- Worker thread: Processes data filtering and grouping
Benefits:
- UI remains responsive during heavy computations
- No frame drops or stuttering
- Smooth interactions even with 50,000+ items
Columnar Storage
Section titled “Columnar Storage”Data is stored in columnar format for efficient filtering:
Traditional (row-based):[{id: 1, name: 'A', price: 10}, {id: 2, name: 'B', price: 20}, ...]
Columnar:{ id: [1, 2, 3, ...], name: ['A', 'B', 'C', ...], price: [10, 20, 30, ...]}Benefits:
- Faster filtering (only process relevant columns)
- Better cache utilization
- Lower memory overhead
Virtualized Rendering
Section titled “Virtualized Rendering”Only visible cards are rendered to the DOM:
- Renders cards in viewport + small buffer
- Reuses DOM elements as you scroll
- Handles thousands of items smoothly
Performance Tips
Section titled “Performance Tips”Optimize Accessors
Section titled “Optimize Accessors”Keep dimension and filter accessors simple:
Good:
{ key: 'status', getValue: (item) => item.status}Avoid:
{ key: 'status', getValue: (item) => { // Complex computation on every filter return expensiveCalculation(item.data, item.metadata, item.relationships); }}Memoize Renderers
Section titled “Memoize Renderers”The cardRenderer returns lightweight structured data ({ title, labels?, values? }), so keep it cheap. For the heavier detailRenderer, wrap the component in React.memo:
const TaskDetails = React.memo(({ item }: { item: Task }) => ( <div className="task-details"> <h4>{item.title}</h4> <p>{item.description}</p> </div>));
<PivotViewer cardRenderer={(item) => ({ title: item.title, values: [item.description] })} detailRenderer={(item) => <TaskDetails item={item} />} // .../>Limit Initial Data
Section titled “Limit Initial Data”Start with a reasonable dataset size:
const [data, setData] = useState([]);const [hasMore, setHasMore] = useState(true);
// Load data in chunksconst loadMore = async () => { const nextBatch = await fetchNextBatch(); setData([...data, ...nextBatch]);};Optimize Images
Section titled “Optimize Images”For card images:
- Use thumbnails, not full-size images
- Lazy load images
- Use appropriate formats (WebP, AVIF)
- Set explicit dimensions
<img src={item.thumbnailUrl} alt={item.name} width={200} height={150} loading="lazy"/>Reduce Re-renders
Section titled “Reduce Re-renders”Avoid creating new objects in render:
Avoid:
<PivotViewer dimensions={[{ key: 'status', label: 'Status', getValue: i => i.status }]} // ... creates new array on every render/>Better:
const dimensions = useMemo(() => [ { key: 'status', label: 'Status', getValue: i => i.status }], []);
<PivotViewer dimensions={dimensions} />Establish an application performance budget
Section titled “Establish an application performance budget”Components does not publish universal item-count timing claims: load, filter, grouping, layout, and sprite cost depend on the data shape, accessors, card renderer, browser, device, and whether the worker path is available. Benchmark the representative production shape on the slowest supported device before choosing a maximum collection size.
Record at least:
- time from data change to the first stable collection frame;
- filter-update latency;
- dimension/grouping-change latency;
- main-thread long tasks while the worker is active;
- worker-unavailable fallback latency;
- memory after repeated data/filter changes;
- zoom/pan frame rate with the representative card renderer.
Use fixed fixtures and repeat each run after warm-up. Keep the dataset, browser/device, build mode, and measurement method with the result so future releases can compare like-for-like. If a budget is exceeded, reduce the client collection before rendering, provide narrower searchFields, simplify the card renderer, or move more filtering into the application’s query/data preparation path.
Monitoring Performance
Section titled “Monitoring Performance”Browser DevTools
Section titled “Browser DevTools”- Performance tab: Record interaction, analyze bottlenecks
- Memory tab: Check for memory leaks
- React DevTools: Profiler for component renders
Console Warnings
Section titled “Console Warnings”The component logs warnings for performance issues:
PivotViewer: Large dataset detected (100,000 items).Consider implementing pagination or virtual scrolling.Scaling Strategies
Section titled “Scaling Strategies”For 1K-10K Items
Section titled “For 1K-10K Items”Default configuration works well. No special optimization needed.
For 10K-50K Items
Section titled “For 10K-50K Items”- Use simple card renderers
- Minimize dimension/filter count
- Consider precomputed values
For 50K-100K Items
Section titled “For 50K-100K Items”- Implement pagination
- Use server-side filtering
- Precompute dimensions on backend
- Limit active filters
For 100K+ Items
Section titled “For 100K+ Items”- Server-side filtering is essential
- Paginate or virtualize at API level
- Consider alternative visualization
- Use database indexes
Memory Considerations
Section titled “Memory Considerations”PivotViewer stores:
- Original data array
- Columnar indexed data
- Filter results (Uint32Array of IDs)
- Rendered components (virtualized)
Approximate memory usage:
BaseMemory = DataSize × 3(original + columnar + filter indexes)
Example:10,000 items × 5KB each = 50MB × 3 = 150MBBest Practices
Section titled “Best Practices”- Profile before optimizing: Measure actual performance
- Optimize data structure: Clean, normalized data loads faster
- Lazy load details: Fetch full item details only when selected
- Use production build: Development mode is slower
- Consider pagination: For very large datasets
- Monitor memory: Check for leaks in long sessions
- Test on target devices: Mobile performance differs from desktop
- Set appropriate limits: Don’t try to visualize millions of items
Troubleshooting Performance Issues
Section titled “Troubleshooting Performance Issues”Slow Initial Load
Section titled “Slow Initial Load”- Check data size
- Optimize accessor functions
- Reduce number of dimensions/filters
- Preprocess data server-side
Laggy Filtering
Section titled “Laggy Filtering”- Simplify filter accessors
- Reduce dataset size
- Check browser console for errors
- Ensure Web Worker is initialized
Stuttery Scrolling
Section titled “Stuttery Scrolling”- Simplify card renderer
- Optimize images
- Reduce number of visible cards
- Check for expensive computations in render
High Memory Usage
Section titled “High Memory Usage”- Check for memory leaks in renderers
- Reduce data retention
- Clear old filter results
- Implement pagination