Enable Discovery debug logging for production troubleshooting
- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
This commit is contained in:
244
resources/js/modules/canvas-animations/ScrollEffects.js
Normal file
244
resources/js/modules/canvas-animations/ScrollEffects.js
Normal file
@@ -0,0 +1,244 @@
|
||||
// modules/canvas-animations/ScrollEffects.js
|
||||
import { CanvasManager } from './CanvasManager.js';
|
||||
import { useEvent } from '../../core/useEvent.js';
|
||||
import { Logger } from '../../core/logger.js';
|
||||
|
||||
/**
|
||||
* Scroll-based Canvas Effects - Parallax and scroll animations
|
||||
*/
|
||||
export const ScrollEffects = {
|
||||
|
||||
/**
|
||||
* Initialize parallax canvas effect
|
||||
*/
|
||||
initParallax(canvas, config) {
|
||||
const manager = new CanvasManager(canvas);
|
||||
const elements = this.createParallaxElements(canvas, config);
|
||||
|
||||
let ticking = false;
|
||||
|
||||
const updateParallax = () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(() => {
|
||||
this.renderParallax(manager, elements, config);
|
||||
ticking = false;
|
||||
});
|
||||
ticking = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Listen to scroll events
|
||||
useEvent(window, 'scroll', updateParallax, 'scroll-parallax');
|
||||
useEvent(window, 'resize', updateParallax, 'scroll-parallax');
|
||||
|
||||
// Initial render
|
||||
updateParallax();
|
||||
|
||||
Logger.info('[ScrollEffects] Parallax initialized with', elements.length, 'elements');
|
||||
},
|
||||
|
||||
/**
|
||||
* Create parallax elements based on config
|
||||
*/
|
||||
createParallaxElements(canvas, config) {
|
||||
const elements = [];
|
||||
const layerCount = config.layers || 3;
|
||||
const elementCount = config.elements || 20;
|
||||
|
||||
for (let i = 0; i < elementCount; i++) {
|
||||
elements.push({
|
||||
x: Math.random() * canvas.clientWidth,
|
||||
y: Math.random() * canvas.clientHeight * 2, // Allow elements outside viewport
|
||||
size: Math.random() * 20 + 5,
|
||||
layer: Math.floor(Math.random() * layerCount),
|
||||
speed: 0.1 + (Math.random() * 0.5), // Different parallax speeds
|
||||
opacity: Math.random() * 0.7 + 0.3,
|
||||
color: this.getLayerColor(Math.floor(Math.random() * layerCount), config)
|
||||
});
|
||||
}
|
||||
|
||||
return elements;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get color for parallax layer
|
||||
*/
|
||||
getLayerColor(layer, config) {
|
||||
const colors = config.colors || [
|
||||
'rgba(100, 150, 255, 0.6)', // Front layer - more opaque
|
||||
'rgba(150, 100, 255, 0.4)', // Middle layer
|
||||
'rgba(200, 100, 150, 0.2)' // Back layer - more transparent
|
||||
];
|
||||
return colors[layer] || colors[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Render parallax effect
|
||||
*/
|
||||
renderParallax(manager, elements, config) {
|
||||
manager.clear();
|
||||
|
||||
const scrollY = window.pageYOffset;
|
||||
const canvasRect = manager.canvas.getBoundingClientRect();
|
||||
const canvasTop = canvasRect.top + scrollY;
|
||||
|
||||
// Calculate relative scroll position
|
||||
const relativeScroll = scrollY - canvasTop;
|
||||
const scrollProgress = relativeScroll / window.innerHeight;
|
||||
|
||||
elements.forEach(element => {
|
||||
// Apply parallax offset based on layer and scroll
|
||||
const parallaxOffset = scrollProgress * element.speed * 100;
|
||||
const y = element.y - parallaxOffset;
|
||||
|
||||
// Only render elements that are potentially visible
|
||||
if (y > -element.size && y < manager.canvas.clientHeight + element.size) {
|
||||
manager.ctx.save();
|
||||
manager.ctx.globalAlpha = element.opacity;
|
||||
manager.ctx.fillStyle = element.color;
|
||||
manager.ctx.beginPath();
|
||||
manager.ctx.arc(element.x, y, element.size, 0, Math.PI * 2);
|
||||
manager.ctx.fill();
|
||||
manager.ctx.restore();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize scroll-based animations
|
||||
*/
|
||||
initScrollAnimation(canvas, config) {
|
||||
const manager = new CanvasManager(canvas);
|
||||
const animationType = config.animation || 'wave';
|
||||
|
||||
let ticking = false;
|
||||
|
||||
const updateAnimation = () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(() => {
|
||||
this.renderScrollAnimation(manager, animationType, config);
|
||||
ticking = false;
|
||||
});
|
||||
ticking = true;
|
||||
}
|
||||
};
|
||||
|
||||
useEvent(window, 'scroll', updateAnimation, 'scroll-animation');
|
||||
useEvent(window, 'resize', updateAnimation, 'scroll-animation');
|
||||
|
||||
// Initial render
|
||||
updateAnimation();
|
||||
|
||||
Logger.info('[ScrollEffects] Scroll animation initialized:', animationType);
|
||||
},
|
||||
|
||||
/**
|
||||
* Render scroll-based animations
|
||||
*/
|
||||
renderScrollAnimation(manager, animationType, config) {
|
||||
manager.clear();
|
||||
|
||||
const scrollY = window.pageYOffset;
|
||||
const canvasRect = manager.canvas.getBoundingClientRect();
|
||||
const canvasTop = canvasRect.top + scrollY;
|
||||
const relativeScroll = scrollY - canvasTop;
|
||||
const scrollProgress = Math.max(0, Math.min(1, relativeScroll / window.innerHeight));
|
||||
|
||||
switch (animationType) {
|
||||
case 'wave':
|
||||
this.renderWaveAnimation(manager, scrollProgress, config);
|
||||
break;
|
||||
case 'progress':
|
||||
this.renderProgressAnimation(manager, scrollProgress, config);
|
||||
break;
|
||||
case 'morph':
|
||||
this.renderMorphAnimation(manager, scrollProgress, config);
|
||||
break;
|
||||
default:
|
||||
this.renderWaveAnimation(manager, scrollProgress, config);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Render wave animation based on scroll
|
||||
*/
|
||||
renderWaveAnimation(manager, progress, config) {
|
||||
const { ctx } = manager;
|
||||
const { width, height } = manager.getSize();
|
||||
|
||||
ctx.strokeStyle = config.color || 'rgba(100, 150, 255, 0.8)';
|
||||
ctx.lineWidth = config.lineWidth || 3;
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
const amplitude = (config.amplitude || 50) * progress;
|
||||
const frequency = config.frequency || 0.02;
|
||||
const phase = progress * Math.PI * 2;
|
||||
|
||||
for (let x = 0; x <= width; x += 2) {
|
||||
const y = height / 2 + Math.sin(x * frequency + phase) * amplitude;
|
||||
|
||||
if (x === 0) {
|
||||
ctx.moveTo(x, y);
|
||||
} else {
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
},
|
||||
|
||||
/**
|
||||
* Render progress bar animation
|
||||
*/
|
||||
renderProgressAnimation(manager, progress, config) {
|
||||
const { ctx } = manager;
|
||||
const { width, height } = manager.getSize();
|
||||
|
||||
const barHeight = config.barHeight || 10;
|
||||
const y = height / 2 - barHeight / 2;
|
||||
|
||||
// Background
|
||||
ctx.fillStyle = config.backgroundColor || 'rgba(255, 255, 255, 0.2)';
|
||||
ctx.fillRect(0, y, width, barHeight);
|
||||
|
||||
// Progress
|
||||
ctx.fillStyle = config.color || 'rgba(100, 150, 255, 0.8)';
|
||||
ctx.fillRect(0, y, width * progress, barHeight);
|
||||
},
|
||||
|
||||
/**
|
||||
* Render morphing shapes
|
||||
*/
|
||||
renderMorphAnimation(manager, progress, config) {
|
||||
const { ctx } = manager;
|
||||
const { width, height } = manager.getSize();
|
||||
|
||||
ctx.fillStyle = config.color || 'rgba(100, 150, 255, 0.6)';
|
||||
|
||||
const centerX = width / 2;
|
||||
const centerY = height / 2;
|
||||
const maxRadius = Math.min(width, height) / 3;
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
const points = config.points || 6;
|
||||
for (let i = 0; i <= points; i++) {
|
||||
const angle = (i / points) * Math.PI * 2;
|
||||
const radiusVariation = Math.sin(progress * Math.PI * 4 + angle * 3) * 0.3 + 1;
|
||||
const radius = maxRadius * progress * radiusVariation;
|
||||
|
||||
const x = centerX + Math.cos(angle) * radius;
|
||||
const y = centerY + Math.sin(angle) * radius;
|
||||
|
||||
if (i === 0) {
|
||||
ctx.moveTo(x, y);
|
||||
} else {
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user