Restricted Cursor Tracking
By default, ParticleText.js tracks cursor position globally across the entire page. The trackCursorOnlyInsideCanvas option lets you restrict particle reactions to only occur when the cursor is within the canvas boundaries, providing precise control over interaction zones.
How It Works
Section titled “How It Works”Default Behavior (Unrestricted)
Section titled “Default Behavior (Unrestricted)”// Default: Particles track cursor anywhere on the pageconst instance = initParticleJS('#canvas', {text: 'GLOBAL',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: false // Default});
// Particles react even when cursor is outside canvas// Creates smooth anticipation as cursor approachesBehavior:
- Mouse position is tracked globally via
window.addEventListener('mousemove') - Particles calculate distance to cursor regardless of canvas position
- Smooth transitions as cursor approaches from outside
- Creates anticipatory effects
Restricted Mode
Section titled “Restricted Mode”// Restricted: Particles only react inside canvasconst instance = initParticleJS('#canvas', {text: 'BOUNDED',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// When cursor leaves canvas:// - Mouse position resets to (-9999, -9999)// - All particles immediately return to rest positions// - Clear boundary for interaction zoneBehavior:
- Checks if cursor is within canvas
getBoundingClientRect() - If outside:
mouse.x = -9999; mouse.y = -9999 - Particles immediately return to original positions
- Clear visual feedback for interaction boundaries
Configuration
Section titled “Configuration”Basic Setup
Section titled “Basic Setup”const instance = initParticleJS('#canvas', {text: 'RESTRICTED',colors: ['#695aa6'],
// Enable restricted trackingtrackCursorOnlyInsideCanvas: true,
// Optional: Increase explosion radius for better interactionexplosionRadius: { xs: 100, lg: 150}});Touch Device Support
Section titled “Touch Device Support”Restricted tracking works seamlessly with touch devices:
const instance = initParticleJS('#canvas', {text: 'TOUCH',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// On touch devices:// - Tracks first touch only (touches[0])// - Same boundary checking as mouse// - touchend event resets mouse positionUse Cases
Section titled “Use Cases”1. Multiple Canvas Instances
Section titled “1. Multiple Canvas Instances”Prevent interference between adjacent particle effects:
// Side-by-side canvasesconst canvas1 = initParticleJS('#canvas1', {text: 'LEFT',colors: ['#FF6B6B'],trackCursorOnlyInsideCanvas: true // Only react to own canvas});
const canvas2 = initParticleJS('#canvas2', {text: 'RIGHT',colors: ['#4ECDC4'],trackCursorOnlyInsideCanvas: true // Independent tracking});
// Without restriction:// - Cursor over canvas1 would affect canvas2// - Confusing user experience// - Particles react to distant cursor
// With restriction:// - Each canvas is independent// - Clear interaction boundaries// - Better UX for multiple instances2. Interactive Galleries
Section titled “2. Interactive Galleries”Define clear interaction zones for gallery items:
// Gallery with multiple particle text itemsconst galleryItems = document.querySelectorAll('.gallery-item canvas');
galleryItems.forEach((canvas, index) => {initParticleJS(canvas, { text: `ITEM ${index + 1}`, colors: ['#695aa6'], trackCursorOnlyInsideCanvas: true, // Each item independent
explosionRadius: { xs: 80, lg: 120 }});});
// User can clearly see which item they're interacting with// No cross-contamination between gallery items3. Page with Interactive Elements
Section titled “3. Page with Interactive Elements”Prevent particle effects from interfering with buttons/links:
<div class="hero"><canvas id="hero-canvas"></canvas><button class="cta-button">Get Started</button></div>
<script>const instance = initParticleJS('#hero-canvas', {text: 'HERO',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// Benefits:// - Particles don't react when user hovers button// - Clearer focus on interactive elements// - Better accessibility// - Reduced distraction</script>4. Performance Optimization
Section titled “4. Performance Optimization”Reduce unnecessary calculations when cursor is far away:
const instance = initParticleJS('#canvas', {text: 'OPTIMIZED',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true,
// Large canvas with many particlesfontSize: 200,maxParticles: 5000});
// Performance benefits:// - No explosion calculations when cursor outside// - Particles return to rest (simpler physics)// - Especially beneficial for large canvases// - Reduces CPU usage when not interacting5. UI/UX Clarity
Section titled “5. UI/UX Clarity”Make interaction zones explicit:
const instance = initParticleJS('#canvas', {text: 'EXPLICIT',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// Add visual cue for canvas boundarycanvas.style.border = '2px solid #695aa6';canvas.style.borderRadius = '8px';canvas.style.cursor = 'crosshair';
// Users immediately understand:// - Where they can interact// - Boundary of effect zone// - Expected behavior6. Fixed Position Elements
Section titled “6. Fixed Position Elements”Prevent issues with fixed/sticky elements:
<header style="position: fixed; top: 0;"><canvas id="header-canvas"></canvas></header>
<script>const instance = initParticleJS('#header-canvas', {text: 'HEADER',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// Prevents:// - Particles reacting when scrolling past header// - Unexpected behavior with fixed positioning// - Confusion about scroll vs hover</script>Implementation Details
Section titled “Implementation Details”Boundary Detection
Section titled “Boundary Detection”// How ParticleText.js detects boundariesfunction onMouseMove(e) {const rect = element.getBoundingClientRect();const relativeX = e.clientX - rect.left;const relativeY = e.clientY - rect.top;
if (trackCursorOnlyInsideCanvas) { // Check if cursor is outside bounds if (relativeX < 0 || relativeX > rect.width || relativeY < 0 || relativeY > rect.height) {
// Reset to far-away position mouse.x = -9999; mouse.y = -9999; return; // Don't update position }}
// Update mouse position (inside or unrestricted)mouse.x = relativeX * (canvas.width / rect.width);mouse.y = relativeY * (canvas.height / rect.height);}Touch Handling
Section titled “Touch Handling”// Touch events use same logicfunction onTouchMove(e) {if (e.touches.length > 0) { const rect = element.getBoundingClientRect(); const relativeX = e.touches[0].clientX - rect.left; const relativeY = e.touches[0].clientY - rect.top;
if (trackCursorOnlyInsideCanvas) { if (relativeX < 0 || relativeX > rect.width || relativeY < 0 || relativeY > rect.height) { mouse.x = -9999; mouse.y = -9999; return; } }
mouse.x = relativeX * (canvas.width / rect.width); mouse.y = relativeY * (canvas.height / rect.height);}}
// Touch end always resetsfunction onTouchEnd(e) {mouse.x = -9999;mouse.y = -9999;}Visual Feedback
Section titled “Visual Feedback”Add Border to Canvas
Section titled “Add Border to Canvas”const instance = initParticleJS('#canvas', {text: 'BORDERED',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// Style canvas to show interaction boundaryconst canvas = document.getElementById('canvas');canvas.style.border = '3px solid #695aa6';canvas.style.borderRadius = '10px';canvas.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';canvas.style.cursor = 'crosshair'; // Clear affordanceHover State Indicator
Section titled “Hover State Indicator”const instance = initParticleJS('#canvas', {text: 'HOVER',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
const canvas = document.getElementById('canvas');
// Visual feedback on hovercanvas.addEventListener('mouseenter', () => {canvas.style.borderColor = '#4ECDC4';canvas.style.boxShadow = '0 0 20px rgba(78, 205, 196, 0.5)';});
canvas.addEventListener('mouseleave', () => {canvas.style.borderColor = '#695aa6';canvas.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';});Status Indicator
Section titled “Status Indicator”<div id="status">Outside canvas</div><canvas id="canvas"></canvas>
<script>const instance = initParticleJS('#canvas', {text: 'STATUS',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
const canvas = document.getElementById('canvas');const status = document.getElementById('status');
canvas.addEventListener('mouseenter', () => {status.textContent = 'Inside canvas - Particles active';status.style.color = '#4CAF50';});
canvas.addEventListener('mouseleave', () => {status.textContent = 'Outside canvas - Particles at rest';status.style.color = '#999';});</script>Combining with Other Features
Section titled “Combining with Other Features”With Explosion Radius
Section titled “With Explosion Radius”const instance = initParticleJS('#canvas', {text: 'COMBINED',colors: ['#695aa6'],
// Restrict tracking to canvastrackCursorOnlyInsideCanvas: true,
// Large explosion radius for dramatic effect within boundaryexplosionRadius: { xs: 150, lg: 250}});
// Result:// - No reaction outside canvas// - Dramatic explosions inside canvas// - Clear on/off behaviorWith Custom Breakpoints
Section titled “With Custom Breakpoints”const instance = initParticleJS('#canvas', {text: 'CUSTOM',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// Override breakpoint logicinstance.getCurrentBreakpoint = function() {return window.innerWidth < 768 ? 'mobile' : 'desktop';};
// Restricted tracking works with custom breakpoints// Boundary detection is breakpoint-independentWith Manual Control
Section titled “With Manual Control”const instance = initParticleJS('#canvas', {text: 'MANUAL',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true,autoAnimate: false});
const canvas = document.getElementById('canvas');
// Start animation only when mouse enterscanvas.addEventListener('mouseenter', () => {instance.startAnimation();});
// Stop when mouse leavescanvas.addEventListener('mouseleave', () => {instance.destroy();});
// Combine restricted tracking with manual animation control// Very efficient: only animates when neededBest Practices
Section titled “Best Practices”1. Use for Multiple Canvases
Section titled “1. Use for Multiple Canvases”// ✅ Good: Independent canvasesdocument.querySelectorAll('.particle-canvas').forEach(canvas => {initParticleJS(canvas, { text: canvas.dataset.text, colors: ['#695aa6'], trackCursorOnlyInsideCanvas: true // Each independent});});
// ❌ Bad: Overlapping effectsdocument.querySelectorAll('.particle-canvas').forEach(canvas => {initParticleJS(canvas, { text: canvas.dataset.text, colors: ['#695aa6'], trackCursorOnlyInsideCanvas: false // All affect each other});});2. Provide Visual Cues
Section titled “2. Provide Visual Cues”// ✅ Good: Clear boundariesconst instance = initParticleJS('#canvas', {text: 'CLEAR',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
canvas.style.border = '2px solid #695aa6';canvas.style.cursor = 'crosshair';
// ❌ Bad: No visual indicationconst instance = initParticleJS('#canvas', {text: 'UNCLEAR',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});// Users don't know where interaction zone is3. Consider Touch Devices
Section titled “3. Consider Touch Devices”// ✅ Good: Works well on touchconst instance = initParticleJS('#canvas', {text: 'TOUCH FRIENDLY',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true,
// Larger explosion radius for fingersexplosionRadius: { xs: 80, // Larger for touch lg: 120}});
// ❌ Bad: Too precise for touchconst instance = initParticleJS('#canvas', {text: 'TOO PRECISE',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true,explosionRadius: { xs: 20, // Too small for fingers lg: 30}});4. Test with Fixed/Sticky Elements
Section titled “4. Test with Fixed/Sticky Elements”// ✅ Good: Explicit testingconst instance = initParticleJS('#fixed-header-canvas', {text: 'FIXED',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// Test:// - Scroll past header// - Hover over header// - Resize window// Verify particles only react when cursor is over canvas
// ❌ Bad: Assume it works// Don't test edge cases with positioning5. Document Your Choice
Section titled “5. Document Your Choice”// ✅ Good: Clear intentconst instance = initParticleJS('#canvas', {text: 'GALLERY ITEM',colors: ['#695aa6'],
// Restricted to prevent interference between gallery itemstrackCursorOnlyInsideCanvas: true});
// ❌ Bad: Unclear whyconst instance = initParticleJS('#canvas', {text: 'SOMETHING',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true // Why?});Troubleshooting
Section titled “Troubleshooting”Particles don’t react at all?
- Check
trackCursorOnlyInsideCanvasistrue, not'true'(string) - Verify canvas is visible and has dimensions
- Check browser console for errors
- Ensure animation is running (
instance.isAnimating)
Particles react outside canvas?
- Verify
trackCursorOnlyInsideCanvas: truein config - Check for multiple instances with different settings
- Clear browser cache
- Check that correct instance is being configured
Touch not working on mobile?
- Touch events are automatically handled
- Ensure canvas is touchable (no
pointer-events: none) - Test with
touchmoveevent listener - Check for conflicting touch handlers
Boundary detection off by a few pixels?
- This can happen with CSS transforms
- Check
getBoundingClientRect()in console - Verify canvas doesn’t have unusual positioning
- Test without CSS transforms
Works on desktop but not mobile?
- Touch uses
touches[0](first touch) - Multi-touch devices: only first touch tracked
- Ensure canvas is large enough for finger
- Test with actual device, not emulator
Related Documentation
Section titled “Related Documentation”- trackCursorOnlyInsideCanvas (API Reference) - Configuration option
- Cursor Tracking Comparison - Compare restricted vs unrestricted
- Explosion Radius - Control interaction distance
- Multiple Canvases - Managing multiple instances
- Manual Control - Combine with animation control