Files
luftglanz/js/drone-image-animation.js
Luftglanz ac7088c5ca Initial commit: Luftglanz drone website with integrated AI chat assistant
Features:
- Complete Luftglanz drone cleaning website
- AI chat assistant integrated with OpenAI API
- Expert product advice for AGO Quart and Mellerud cleaning products
- Formal German language support (Sie form)
- Secure PHP backend for API calls
- Responsive design with mobile support
- Product-specific knowledge base
- Safety statements from manufacturers
- Multi-page integration (index, products, services, contact)

Technical components:
- AI chat widget (js/ai-chat.js)
- Chat styling (css/components/ai-chat.css)
- Backend API (ai-chat-api.php)
- Product knowledge base with detailed specifications
- Demo and documentation files
2025-07-08 11:54:37 +02:00

487 lines
22 KiB
JavaScript

/**
* Drone Image Animation with New Background
* Uses a single image background with the drone flying over the roof
*/
(function() {
document.addEventListener('DOMContentLoaded', function() {
// Only run on pages that have a hero section
const heroSection = document.querySelector('.hero');
if (heroSection) {
// Remove any existing backgrounds or animations
if (heroSection.style.backgroundImage) {
heroSection.style.backgroundImage = 'none';
}
// Remove any existing animation containers
const existingAnimations = heroSection.querySelectorAll('.drone-animation-container, .animation-container, .roof-cleaning-animation');
existingAnimations.forEach(el => el.remove());
// Create our animation with the new background
createAnimationWithSingleBackground(heroSection);
}
});
function createAnimationWithSingleBackground(container) {
// Create animation container with more aggressive full-width styling
const animationContainer = document.createElement('div');
animationContainer.className = 'drone-animation-container';
// Position absolutely with negative margins to escape any parent padding
animationContainer.style.position = 'absolute';
animationContainer.style.top = '0';
animationContainer.style.left = '0';
animationContainer.style.right = '0'; // Add right: 0 to ensure full width
animationContainer.style.width = '100vw'; // Use viewport width
animationContainer.style.maxWidth = '100vw'; // Override any max-width restrictions
animationContainer.style.marginLeft = 'calc(50% - 50vw)'; // Center regardless of parent padding
animationContainer.style.marginRight = 'calc(50% - 50vw)'; // Center regardless of parent padding
animationContainer.style.height = '100%';
animationContainer.style.overflow = 'hidden';
animationContainer.style.pointerEvents = 'none';
animationContainer.style.zIndex = '1';
// Add CSS to fix any scrollbar issues
const styleFixForScrollbar = document.createElement('style');
styleFixForScrollbar.textContent = `
html, body {
overflow-x: hidden;
width: 100%;
position: relative;
}
.hero {
width: 100%;
max-width: 100%;
overflow: hidden;
padding-left: 0 !important;
padding-right: 0 !important;
}
`;
document.head.appendChild(styleFixForScrollbar);
// Fix mobile white space by adjusting the parent container on mobile
if (window.innerWidth <= 768) {
// Remove potential white space in parent container
container.style.paddingBottom = '0';
container.style.marginBottom = '0';
}
// Create background using the new image
createFullBackground(animationContainer);
// Create drone elements that will fly over the roof
createFlyingDrones(animationContainer);
// Add everything to the container
container.appendChild(animationContainer);
// Add animation styles
addAnimationStyles();
// Add resize listener to adjust for screen size changes
window.addEventListener('resize', function() {
adjustForScreenSize(animationContainer);
});
// Initial adjustment for screen size
adjustForScreenSize(animationContainer);
// Position the hero content (text) in the sky area
positionHeroContent(container);
}
function createFullBackground(container) {
// Create the full background with enhanced full-width styling
const backgroundElement = document.createElement('div');
backgroundElement.className = 'animation-background';
backgroundElement.style.position = 'absolute';
backgroundElement.style.top = '0';
backgroundElement.style.left = '0';
backgroundElement.style.right = '0'; // Add right: 0
backgroundElement.style.width = '100vw'; // Use viewport width
backgroundElement.style.maxWidth = 'none'; // No max width restrictions
backgroundElement.style.height = '100%';
backgroundElement.style.backgroundImage = 'url("images/animation_background1.png")';
backgroundElement.style.backgroundSize = 'cover';
backgroundElement.style.backgroundPosition = 'center center';
backgroundElement.style.backgroundRepeat = 'no-repeat';
backgroundElement.style.backgroundColor = '#75b0cc';
backgroundElement.style.zIndex = '1';
// Add subtle overlay to improve text visibility
const overlay = document.createElement('div');
overlay.style.position = 'absolute';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.1)'; /* Subtle darkening */
overlay.style.zIndex = '2';
backgroundElement.appendChild(overlay);
container.appendChild(backgroundElement);
// Add resize event listener for responsive adjustments
window.addEventListener('resize', function() {
adjustBackground(backgroundElement);
});
// Initial adjustment
adjustBackground(backgroundElement);
}
function adjustBackground(backgroundElement) {
const isMobile = window.innerWidth <= 768;
const isPortrait = window.innerHeight > window.innerWidth;
if (isMobile) {
if (isPortrait) {
// Portrait mobile - fix grey area by using cover and adjusting transform
backgroundElement.style.backgroundSize = 'cover';
backgroundElement.style.transform = 'translateY(-15%)'; // Move image up instead of using background-position
backgroundElement.style.height = '100%'; // Ensure full height
} else {
// Landscape mobile - also fix using transform
backgroundElement.style.backgroundSize = 'cover';
backgroundElement.style.transform = 'translateY(-10%)';
backgroundElement.style.height = '100%';
}
} else {
// Desktop - standard positioning
backgroundElement.style.backgroundSize = 'cover';
backgroundElement.style.transform = 'none';
backgroundElement.style.backgroundPosition = 'center center';
}
}
function positionHeroContent(container) {
// Get the hero content (text)
const heroContent = container.querySelector('.hero-content');
if (heroContent) {
// Split the content: Title in sky, rest at top of roof
const headline = heroContent.querySelector('h2');
const otherContent = document.createElement('div');
otherContent.className = 'hero-secondary-content';
// Get all other elements except the headline
const subheading = heroContent.querySelector('p');
const ctaButton = heroContent.querySelector('.btn-primary');
// Set styles for the main container
heroContent.style.position = 'relative';
heroContent.style.zIndex = '5';
heroContent.style.display = 'flex';
heroContent.style.flexDirection = 'column';
heroContent.style.alignItems = 'center';
heroContent.style.justifyContent = 'space-between';
heroContent.style.height = '100%';
heroContent.style.textShadow = '0 2px 4px rgba(0, 0, 0, 0.3)';
// Style headline to be in sky - make consistent across all views
if (headline) {
headline.style.color = '#ffffff';
headline.style.margin = '0 auto 2rem';
headline.style.maxWidth = '100%'; // Changed from 90% to 100% for better text wrapping
headline.style.textAlign = 'center';
headline.style.position = 'relative';
headline.style.zIndex = '6';
headline.style.fontSize = window.innerWidth <= 480 ? '1.5rem' : (window.innerWidth <= 768 ? '1.8rem' : '3rem'); // Reduced from 1.7rem to 1.5rem for smallest screens
headline.style.lineHeight = '1.3'; // Add line height for better text spacing
headline.style.width = '100%'; // Ensure full width
headline.style.wordWrap = 'break-word'; // Improve word wrapping
headline.style.hyphens = 'none'; // Changed from 'auto' to 'none'
headline.style.wordBreak = 'keep-all'; // Prevent words from breaking
headline.style.whiteSpace = 'normal'; // Allow normal wrapping but prevent word splitting
// More mobile-friendly initial positioning
headline.style.marginTop = window.innerWidth <= 768 ? '-3rem' : '-8rem';
}
// Move other content to a separate container
if (subheading && ctaButton) {
// Remove elements from their current position
subheading.remove();
ctaButton.remove();
// Add them to the new container
otherContent.appendChild(subheading);
otherContent.appendChild(ctaButton);
// Style the subheading
subheading.style.color = '#ffffff';
subheading.style.marginBottom = '1.5rem';
// Style the container for other content
otherContent.style.display = 'flex';
otherContent.style.flexDirection = 'column';
otherContent.style.alignItems = 'center';
otherContent.style.position = 'relative';
otherContent.style.zIndex = '6';
// Add the container to the hero content
heroContent.appendChild(otherContent);
}
// Adjust positions for different screen sizes
adjustHeroContentPositioning(heroContent, headline, otherContent);
window.addEventListener('resize', function() {
adjustHeroContentPositioning(heroContent, headline, otherContent);
});
}
}
function adjustHeroContentPositioning(heroContent, headline, otherContent) {
const isMobile = window.innerWidth <= 768;
const isPortrait = window.innerHeight > window.innerWidth;
const isSmallPhone = window.innerWidth <= 480;
// Apply different positioning based on device type and size
if (headline) {
if (isMobile) {
if (isPortrait) {
// Portrait mobile - adjust based on device height
const viewportHeight = window.innerHeight;
if (viewportHeight <= 600) {
// Very small device
headline.style.marginTop = '-1rem';
} else if (viewportHeight <= 800) {
// Medium device
headline.style.marginTop = '-2rem';
} else {
// Larger device
headline.style.marginTop = '-3rem';
}
} else {
// Landscape mobile
headline.style.marginTop = '-2rem';
}
} else {
// Desktop - keep as is
headline.style.marginTop = '-8rem';
}
}
if (otherContent) {
otherContent.style.marginTop = 'auto';
if (isMobile) {
if (isPortrait) {
// Portrait mobile - adjust based on device height
const viewportHeight = window.innerHeight;
if (viewportHeight <= 600) {
// More compact spacing for small devices
otherContent.style.marginBottom = '3rem';
} else if (viewportHeight <= 800) {
otherContent.style.marginBottom = '4rem';
} else {
otherContent.style.marginBottom = '5rem';
}
// Adjust spacing between elements for small devices
if (isSmallPhone) {
const subheading = otherContent.querySelector('p');
if (subheading) {
subheading.style.marginBottom = '1rem';
}
}
} else {
// Landscape mobile
otherContent.style.marginBottom = '3rem';
}
} else {
// Desktop
otherContent.style.marginBottom = '5rem';
}
}
}
function adjustHeroContent(heroContent) {
// This function is replaced by the more specific positioning function above
// Keep it for compatibility but it no longer needs to do anything
}
function createFlyingDrones(container) {
// Create drone path container
const dronePathContainer = document.createElement('div');
dronePathContainer.className = 'drone-path-container';
dronePathContainer.style.position = 'absolute';
dronePathContainer.style.top = '0';
dronePathContainer.style.left = '0';
dronePathContainer.style.width = '100%';
dronePathContainer.style.height = '100%';
dronePathContainer.style.zIndex = '10';
container.appendChild(dronePathContainer);
// Create drone with responsive sizing
createDrone(dronePathContainer, 'drone-path-1', 0);
}
function createDrone(container, pathClass, startDelay = 0, duration = 30) {
// Create drone element using the specified drone image
const droneElement = document.createElement('div');
droneElement.className = `animated-drone ${pathClass}`;
droneElement.style.position = 'absolute';
droneElement.style.width = '440px'; // Will be adjusted for mobile
droneElement.style.height = '300px'; // Will be adjusted for mobile
droneElement.style.top = '45%'; // Position for new background
droneElement.style.left = '-450px';
droneElement.style.zIndex = '15'; // Above all other elements
droneElement.style.animation = `${pathClass} ${duration}s linear infinite`;
droneElement.style.animationDelay = `${startDelay}s`;
// Add the drone image
const droneImage = document.createElement('img');
droneImage.src = 'images/spraying_drone4.png';
droneImage.alt = 'Dachreinigungsdrohne';
droneImage.style.width = '100%';
droneImage.style.height = 'auto';
droneImage.style.filter = 'drop-shadow(0 15px 30px rgba(0,0,0,0.25))';
droneElement.appendChild(droneImage);
container.appendChild(droneElement);
}
function adjustForScreenSize(container) {
const isMobile = window.innerWidth <= 768;
const isPortrait = window.innerHeight > window.innerWidth;
// Fix white space issue on mobile
if (isMobile) {
// Adjust parent container (hero section)
const heroSection = container.closest('.hero');
if (heroSection) {
heroSection.style.paddingBottom = '0';
heroSection.style.marginBottom = '0';
// Ensure full height to bottom of viewport on mobile
container.style.minHeight = '100%';
}
// Adjust the main background element to extend fully
const backgroundEl = container.querySelector('.animation-background');
if (backgroundEl) {
backgroundEl.style.bottom = '0';
backgroundEl.style.height = '100%';
// Add extra height to cover any potential gaps
backgroundEl.style.marginBottom = '-2px';
}
}
const drones = container.querySelectorAll('.animated-drone');
// Adjust drone sizes
drones.forEach(drone => {
if (isMobile) {
if (isPortrait) {
// Portrait mobile - smaller drone
drone.style.width = '150px';
drone.style.height = '100px';
} else {
// Landscape mobile
drone.style.width = '180px';
drone.style.height = '120px';
}
} else {
// Desktop size
drone.style.width = '440px';
drone.style.height = '300px';
}
});
// Adjust background
const background = container.querySelector('.animation-background');
if (background) {
adjustBackground(background);
}
// Add headline adjustment on resize
const headline = document.querySelector('.hero-content h2');
if (headline) {
// Adjust font size based on screen width for better text wrapping
if (window.innerWidth <= 480) {
headline.style.fontSize = '1.5rem';
headline.style.lineHeight = '1.3';
headline.style.maxWidth = '100%';
headline.style.padding = '0 0.5rem'; // Add padding for smallest screens
headline.style.hyphens = 'none';
headline.style.wordBreak = 'keep-all';
headline.style.whiteSpace = 'normal';
} else if (window.innerWidth <= 768) {
headline.style.fontSize = '1.8rem';
headline.style.lineHeight = '1.3';
headline.style.maxWidth = '100%';
headline.style.hyphens = 'none';
headline.style.wordBreak = 'keep-all';
headline.style.whiteSpace = 'normal';
} else {
headline.style.fontSize = '3rem';
headline.style.lineHeight = '1.2';
headline.style.maxWidth = '90%';
headline.style.hyphens = 'none';
headline.style.wordBreak = 'keep-all';
headline.style.whiteSpace = 'normal';
}
}
}
// Add a resize event listener to handle orientation changes
window.addEventListener('resize', function() {
const animationContainer = document.querySelector('.drone-animation-container');
if (animationContainer) {
adjustForScreenSize(animationContainer);
}
});
function addAnimationStyles() {
// Create style element if it doesn't exist
if (!document.getElementById('drone-animation-styles')) {
const styleElement = document.createElement('style');
styleElement.id = 'drone-animation-styles';
// Add responsive animations with adjusted drone path to match new background
styleElement.innerHTML = `
@keyframes drone-path-1 {
/* First half - path adjusted for new background */
0% { left: -450px; top: 45%; transform: rotate(0deg); }
5% { left: 10%; top: 43%; transform: rotate(-5deg); }
10% { left: 20%; top: 45%; transform: rotate(0deg); }
15% { left: 30%; top: 47%; transform: rotate(5deg); }
20% { left: 40%; top: 45%; transform: rotate(0deg); }
25% { left: 50%; top: 48%; transform: rotate(-3deg); }
30% { left: 60%; top: 50%; transform: rotate(0deg); }
35% { left: 70%; top: 52%; transform: rotate(3deg); }
40% { left: 80%; top: 50%; transform: rotate(0deg); }
45% { left: 90%; top: 48%; transform: rotate(-5deg); }
50% { left: 100%; top: 45%; transform: rotate(-10deg); }
/* Second half - return path */
55% { left: 90%; top: 48%; transform: rotate(-5deg) scaleX(-1); }
60% { left: 80%; top: 50%; transform: rotate(0deg) scaleX(-1); }
65% { left: 70%; top: 52%; transform: rotate(3deg) scaleX(-1); }
70% { left: 60%; top: 50%; transform: rotate(0deg) scaleX(-1); }
75% { left: 50%; top: 48%; transform: rotate(-3deg) scaleX(-1); }
80% { left: 40%; top: 45%; transform: rotate(0deg) scaleX(-1); }
85% { left: 30%; top: 47%; transform: rotate(5deg) scaleX(-1); }
90% { left: 20%; top: 45%; transform: rotate(0deg) scaleX(-1); }
95% { left: 10%; top: 43%; transform: rotate(-5deg) scaleX(-1); }
100% { left: -450px; top: 45%; transform: rotate(0deg) scaleX(-1); }
}
/* Mobile-specific animations */
@media (max-width: 768px) {
@keyframes drone-path-1 {
/* Adjusted path for mobile - fly higher to match the shifted background */
0% { left: -220px; top: 45%; transform: rotate(0deg); }
20% { left: 30%; top: 43%; transform: rotate(-5deg); }
40% { left: 70%; top: 47%; transform: rotate(5deg); }
50% { left: 100%; top: 45%; transform: rotate(-5deg); }
60% { left: 70%; top: 47%; transform: rotate(5deg) scaleX(-1); }
80% { left: 30%; top: 43%; transform: rotate(-5deg) scaleX(-1); }
100% { left: -220px; top: 45%; transform: rotate(0deg) scaleX(-1); }
}
}
`;
document.head.appendChild(styleElement);
}
}
})();