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
This commit is contained in:
486
js/drone-image-animation.js
Normal file
486
js/drone-image-animation.js
Normal file
@@ -0,0 +1,486 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user