Adjust hero section positioning and standardize contact information

- Updated hero section CSS to position content lower on the page
- Changed #hero padding-top from 8rem to 4rem with !important flag
- Modified .hero-container to use align-items: flex-start with 10rem top padding
- Added cache-busting parameter to style.css link for browser refresh
- Standardized contact information across all pages:
  - Location: Pune, Maharashtra, India
  - Phone: +91 89491-35299
  - Email: info@gyannetra.com
- Updated footer contact sections in about.html and all service/industry pages
- Fixed CSS syntax error by removing extra closing brace
- Cleaned up unused CSS and JS files for better project organization
This commit is contained in:
2025-05-28 11:04:38 +05:30
parent 29ebb82cf8
commit 5361e2f800
36 changed files with 2884 additions and 5434 deletions

View File

@@ -1,761 +0,0 @@
/**
* Enhanced Unified Neural Network Animation and Data Node Interactive Effects
* This file handles both the canvas background animation and data node interactions
* with advanced interactive elements and dynamic visual effects
*/
// Neural Network Canvas Animation Class
class NeuralNetworkAnimation {
constructor() {
this.canvas = document.querySelector('.mesh-canvas');
this.ctx = this.canvas ? this.canvas.getContext('2d') : null;
this.nodes = [];
this.connections = [];
this.mousePos = { x: 0, y: 0 };
this.animationId = null;
if (this.ctx) {
this.init();
}
}
init() {
this.setupCanvas();
this.createNodes();
this.setupInteractions();
this.setupResize();
this.animate();
}
setupCanvas() {
const heroSection = document.getElementById('hero');
if (heroSection) {
const rect = heroSection.getBoundingClientRect();
this.canvas.width = rect.width;
this.canvas.height = rect.height;
this.canvas.style.width = '100%';
this.canvas.style.height = '100%';
}
}
setupResize() {
window.addEventListener('resize', () => {
this.setupCanvas();
this.nodes.forEach(node => {
node.x = Math.min(node.x, this.canvas.width);
node.y = Math.min(node.y, this.canvas.height);
});
});
}
createNodes() {
const nodeCount = 40;
this.nodes = [];
for (let i = 0; i < nodeCount; i++) {
this.nodes.push({
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
vx: (Math.random() - 0.5) * 0.5,
vy: (Math.random() - 0.5) * 0.5,
radius: Math.random() * 3 + 1,
opacity: Math.random() * 0.5 + 0.2,
pulsePhase: Math.random() * Math.PI * 2,
energy: Math.random()
});
}
}
updateNodes() {
this.nodes.forEach(node => {
// Update position
node.x += node.vx;
node.y += node.vy;
// Bounce off edges
if (node.x <= 0 || node.x >= this.canvas.width) node.vx *= -1;
if (node.y <= 0 || node.y >= this.canvas.height) node.vy *= -1;
// Keep nodes in bounds
node.x = Math.max(0, Math.min(this.canvas.width, node.x));
node.y = Math.max(0, Math.min(this.canvas.height, node.y));
// Update pulse
node.pulsePhase += 0.02;
node.energy = 0.5 + 0.5 * Math.sin(node.pulsePhase);
});
}
drawNodes() {
this.nodes.forEach(node => {
const gradient = this.ctx.createRadialGradient(
node.x, node.y, 0,
node.x, node.y, node.radius * 3
);
const alpha = node.opacity * node.energy;
gradient.addColorStop(0, `rgba(59, 130, 246, ${alpha})`);
gradient.addColorStop(0.5, `rgba(139, 92, 246, ${alpha * 0.7})`);
gradient.addColorStop(1, `rgba(236, 72, 153, 0)`);
this.ctx.beginPath();
this.ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
this.ctx.fillStyle = gradient;
this.ctx.fill();
// Core dot
this.ctx.beginPath();
this.ctx.arc(node.x, node.y, node.radius * 0.3, 0, Math.PI * 2);
this.ctx.fillStyle = `rgba(255, 255, 255, ${alpha * 0.8})`;
this.ctx.fill();
});
}
drawConnections() {
const maxDistance = 120;
for (let i = 0; i < this.nodes.length; i++) {
for (let j = i + 1; j < this.nodes.length; j++) {
const nodeA = this.nodes[i];
const nodeB = this.nodes[j];
const dx = nodeB.x - nodeA.x;
const dy = nodeB.y - nodeA.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < maxDistance) {
const opacity = (1 - distance / maxDistance) * 0.3;
const energyBoost = (nodeA.energy + nodeB.energy) / 2;
// Create dynamic gradient line
const gradient = this.ctx.createLinearGradient(
nodeA.x, nodeA.y, nodeB.x, nodeB.y
);
gradient.addColorStop(0, `rgba(59, 130, 246, ${opacity * energyBoost})`);
gradient.addColorStop(0.5, `rgba(139, 92, 246, ${opacity * energyBoost * 0.8})`);
gradient.addColorStop(1, `rgba(236, 72, 153, ${opacity * energyBoost * 0.6})`);
this.ctx.strokeStyle = gradient;
this.ctx.lineWidth = 1;
this.ctx.globalCompositeOperation = 'lighter';
this.ctx.beginPath();
this.ctx.moveTo(nodeA.x, nodeA.y);
this.ctx.lineTo(nodeB.x, nodeB.y);
this.ctx.stroke();
this.ctx.globalCompositeOperation = 'source-over';
// Data pulse along connection
if (Math.random() < 0.01) {
this.createDataPulse(nodeA, nodeB);
}
}
}
}
}
createDataPulse(nodeA, nodeB) {
const pulse = {
startX: nodeA.x,
startY: nodeA.y,
endX: nodeB.x,
endY: nodeB.y,
progress: 0,
speed: 0.02,
life: 1
};
this.dataPulses = this.dataPulses || [];
this.dataPulses.push(pulse);
}
updateDataPulses() {
if (!this.dataPulses) return;
this.dataPulses = this.dataPulses.filter(pulse => {
pulse.progress += pulse.speed;
pulse.life -= 0.01;
if (pulse.progress >= 1 || pulse.life <= 0) {
return false;
}
// Draw pulse
const x = pulse.startX + (pulse.endX - pulse.startX) * pulse.progress;
const y = pulse.startY + (pulse.endY - pulse.startY) * pulse.progress;
const gradient = this.ctx.createRadialGradient(x, y, 0, x, y, 6);
gradient.addColorStop(0, `rgba(255, 255, 255, ${pulse.life})`);
gradient.addColorStop(1, `rgba(59, 130, 246, 0)`);
this.ctx.beginPath();
this.ctx.arc(x, y, 4, 0, Math.PI * 2);
this.ctx.fillStyle = gradient;
this.ctx.fill();
return true;
});
}
handleMouseMove(e) {
const rect = this.canvas.getBoundingClientRect();
this.mousePos.x = e.clientX - rect.left;
this.mousePos.y = e.clientY - rect.top;
// Create attraction effect
this.nodes.forEach(node => {
const dx = this.mousePos.x - node.x;
const dy = this.mousePos.y - node.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
const force = (100 - distance) / 100 * 0.01;
node.vx += dx * force;
node.vy += dy * force;
node.energy = Math.min(1, node.energy + 0.1);
}
});
}
animate() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Add subtle background gradient
const bgGradient = this.ctx.createRadialGradient(
this.canvas.width / 2, this.canvas.height / 2, 0,
this.canvas.width / 2, this.canvas.height / 2, Math.max(this.canvas.width, this.canvas.height) / 2
);
bgGradient.addColorStop(0, 'rgba(59, 130, 246, 0.02)');
bgGradient.addColorStop(1, 'rgba(139, 92, 246, 0.01)');
this.ctx.fillStyle = bgGradient;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.updateNodes();
this.drawConnections();
this.drawNodes();
this.updateDataPulses();
this.animationId = requestAnimationFrame(() => this.animate());
}
setupInteractions() {
// Mouse interaction only - data node interactions handled by DataNodeInteractions class
this.canvas.addEventListener('mousemove', (e) => this.handleMouseMove(e));
}
destroy() {
if (this.animationId) {
cancelAnimationFrame(this.animationId);
}
}
}
// Data Node Interactive Effects Class
class DataNodeInteractions {
constructor() {
this.init();
}
init() {
// Wait for DOM to be fully loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
this.initializeInteractions();
});
} else {
this.initializeInteractions();
}
}
initializeInteractions() {
this.setupTooltips();
this.setupHoverEffects();
this.setupClickEffects();
this.addRequiredStyles();
}
setupTooltips() {
const dataNodes = document.querySelectorAll('.data-node');
// First, remove any existing tooltip elements
document.querySelectorAll('.data-node-tooltip').forEach(tooltip => {
if (tooltip.parentNode) {
tooltip.parentNode.removeChild(tooltip);
}
});
dataNodes.forEach((node, index) => {
// Create tooltip element
const tooltip = this.createTooltip(node);
document.body.appendChild(tooltip); // Append to body instead of node for better positioning
// Store reference to the tooltip on the node
node.tooltip = tooltip;
// Add hover events for tooltip
node.addEventListener('mouseenter', (e) => {
this.showTooltip(tooltip, node, e);
this.triggerHoverEffect(node);
});
node.addEventListener('mouseleave', () => {
this.hideTooltip(tooltip);
this.resetHoverEffect(node);
});
// Update tooltip position on mouse move - only if needed
node.addEventListener('mousemove', (e) => {
// Only update on significant mouse movement to prevent jitter
if (!node.lastMouseX || Math.abs(e.clientX - node.lastMouseX) > 5 ||
!node.lastMouseY || Math.abs(e.clientY - node.lastMouseY) > 5) {
this.updateTooltipPosition(tooltip, node, e);
node.lastMouseX = e.clientX;
node.lastMouseY = e.clientY;
}
});
});
}
createTooltip(node) {
const techType = node.getAttribute('data-tech');
const tooltip = document.createElement('div');
tooltip.className = 'data-node-tooltip';
// Enhanced concise descriptions for each technology
const descriptions = {
'Machine Learning': 'Building intelligent systems that learn from data to predict outcomes and automate decisions.',
'Generative AI': 'Creating novel content from text and images to code, unlocking new creative possibilities.',
'Data Analytics': 'Transforming raw data into actionable business insights to drive strategic decisions.',
'Automation': 'Designing intelligent workflows that increase efficiency and free up human resources.',
'Finance': 'Using AI for risk assessment, fraud detection, and optimized investment strategies.',
'Healthcare': 'Enabling faster diagnoses, personalized treatments, and improved patient care.',
'Retail': 'Powering personalized shopping experiences, inventory optimization, and demand forecasting.',
'Manufacturing': 'Enhancing production efficiency, quality control, and supply chain optimization.',
'Agentic AI': 'Developing autonomous AI agents that perceive environments and take goal-driven actions.',
'Marketing': 'Creating data-driven campaigns, customer segmentation, and conversion optimization.',
'Media & Entertainment': 'Enabling content creation, audience engagement, and personalized recommendations.',
'Travel': 'Implementing smart pricing strategies and enhancing customer travel experiences.',
'Education': 'Delivering personalized learning paths and educational content innovation.',
'Technology': 'Providing cutting-edge AI development and integration services for tech companies.'
};
tooltip.innerHTML = `
<div class="tooltip-title">${techType}</div>
<div class="tooltip-description">${descriptions[techType] || 'AI-powered solutions and innovations for business transformation.'}</div>
<div class="tooltip-arrow"></div>
`;
return tooltip;
}
showTooltip(tooltip, node, event) {
// Hide any other visible tooltips first
document.querySelectorAll('.data-node-tooltip').forEach(otherTooltip => {
if (otherTooltip !== tooltip && otherTooltip.style.visibility === 'visible') {
otherTooltip.style.opacity = '0';
otherTooltip.style.visibility = 'hidden';
otherTooltip.style.transform = 'scale(0.95)';
}
});
// Position the tooltip before showing it
this.updateTooltipPosition(tooltip, node, event);
// Reset any ongoing transitions with enhanced animation
tooltip.style.transition = 'all 0.3s cubic-bezier(0.2, 0, 0.2, 1)'; // Smoother easing
tooltip.style.opacity = '1';
tooltip.style.visibility = 'visible';
tooltip.style.transform = 'scale(1)';
// Add a subtle animation highlight
setTimeout(() => {
tooltip.style.boxShadow = '0 12px 35px rgba(0, 0, 0, 0.7), 0 0 20px rgba(79, 150, 255, 0.4)';
}, 50);
}
hideTooltip(tooltip) {
// Smooth fade out
tooltip.style.transition = 'all 0.25s cubic-bezier(0.4, 0, 1, 1)';
tooltip.style.opacity = '0';
tooltip.style.visibility = 'hidden';
tooltip.style.transform = 'scale(0.95)';
tooltip.style.boxShadow = '0 10px 30px rgba(0, 0, 0, 0.6), 0 0 15px rgba(59, 130, 246, 0.3)';
}
updateTooltipPosition(tooltip, node, event) {
const rect = node.getBoundingClientRect();
// Ensure the tooltip has proper dimensions for calculation
tooltip.style.visibility = 'hidden';
tooltip.style.opacity = '0';
tooltip.style.display = 'block';
const tooltipRect = tooltip.getBoundingClientRect();
// Position tooltip with a fixed offset from the node to avoid affecting flow
let left = rect.left + (rect.width / 2);
let top = rect.top - tooltipRect.height - 25; // Increased distance above node
// Adjust if tooltip goes off screen
const viewport = {
width: window.innerWidth,
height: window.innerHeight
};
// Check node position and adjust tooltip accordingly
const isRightSide = rect.left > (viewport.width / 2);
const isTopHalf = rect.top < (viewport.height / 2);
// Apply smart positioning based on quadrant location
if (isRightSide) {
left = Math.min(left + 20, viewport.width - tooltipRect.width - 20);
} else {
left = Math.max(left - 20, 20);
}
// Keep the tooltip centered relative to the node
left = rect.left + (rect.width / 2);
// Ensure tooltip stays within viewport bounds
const margin = 20;
if (left < margin) {
left = margin;
}
if (left + tooltipRect.width > viewport.width - margin) {
left = viewport.width - tooltipRect.width - margin;
}
// If not enough room above, show below
if (top < margin) {
top = rect.bottom + 25; // Place below with distance
tooltip.classList.add('tooltip-below');
} else {
tooltip.classList.remove('tooltip-below');
}
// Apply the positioning
tooltip.style.left = `${left}px`;
tooltip.style.top = `${top}px`;
// Reset visibility state
if (node.matches(':hover')) {
tooltip.style.visibility = 'visible';
tooltip.style.opacity = '1';
}
}
setupHoverEffects() {
const dataNodes = document.querySelectorAll('.data-node');
dataNodes.forEach((node, index) => {
node.addEventListener('mouseenter', () => {
this.triggerHoverEffect(node);
this.createRippleEffect(node);
});
node.addEventListener('mouseleave', () => {
this.resetHoverEffect(node);
});
});
}
triggerHoverEffect(node) {
// Enhanced glow effect - using smaller scale to maintain scattered flow
node.style.transform = 'scale(1.08)';
node.style.zIndex = '1000';
// Add glow to node core
const nodeCore = node.querySelector('.node-core');
if (nodeCore) {
nodeCore.style.boxShadow = '0 0 30px rgba(59, 130, 246, 0.8), 0 0 60px rgba(139, 92, 246, 0.6)';
nodeCore.style.background = 'radial-gradient(circle, rgba(59, 130, 246, 0.4), rgba(139, 92, 246, 0.3))';
}
// Enhance icon visibility
const nodeIcon = node.querySelector('.node-icon img');
if (nodeIcon) {
nodeIcon.style.filter = 'brightness(1.2) saturate(1.3) drop-shadow(0 0 10px rgba(255, 255, 255, 0.8))';
}
// Brighten label
const nodeLabel = node.querySelector('.node-label');
if (nodeLabel) {
nodeLabel.style.color = '#ffffff';
nodeLabel.style.textShadow = '0 0 10px rgba(59, 130, 246, 0.8)';
nodeLabel.style.fontWeight = '600';
}
}
resetHoverEffect(node) {
node.style.transform = '';
node.style.zIndex = '';
const nodeCore = node.querySelector('.node-core');
if (nodeCore) {
nodeCore.style.boxShadow = '';
nodeCore.style.background = '';
}
const nodeIcon = node.querySelector('.node-icon img');
if (nodeIcon) {
nodeIcon.style.filter = '';
}
const nodeLabel = node.querySelector('.node-label');
if (nodeLabel) {
nodeLabel.style.color = '';
nodeLabel.style.textShadow = '';
nodeLabel.style.fontWeight = '';
}
}
createRippleEffect(node) {
const ripple = document.createElement('div');
ripple.className = 'data-node-ripple';
const rect = node.getBoundingClientRect();
const size = Math.max(rect.width, rect.height) * 2;
ripple.style.width = `${size}px`;
ripple.style.height = `${size}px`;
ripple.style.left = `${rect.width / 2 - size / 2}px`;
ripple.style.top = `${rect.height / 2 - size / 2}px`;
node.appendChild(ripple);
// Remove ripple after animation
setTimeout(() => {
if (ripple.parentNode) {
ripple.parentNode.removeChild(ripple);
}
}, 600);
}
setupClickEffects() {
const dataNodes = document.querySelectorAll('.data-node');
dataNodes.forEach(node => {
node.addEventListener('click', () => {
this.triggerClickEffect(node);
this.createBurstEffect(node);
});
});
}
triggerClickEffect(node) {
// Create pulsating effect
node.style.animation = 'none';
setTimeout(() => {
node.style.animation = 'nodeClickPulse 0.6s ease-out';
}, 10);
// Reset animation after completion
setTimeout(() => {
node.style.animation = '';
}, 600);
}
createBurstEffect(node) {
const particles = 8;
const rect = node.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
for (let i = 0; i < particles; i++) {
const particle = document.createElement('div');
particle.className = 'data-node-particle';
const angle = (360 / particles) * i;
const distance = 50 + Math.random() * 30;
const endX = centerX + Math.cos(angle * Math.PI / 180) * distance;
const endY = centerY + Math.sin(angle * Math.PI / 180) * distance;
particle.style.left = `${centerX}px`;
particle.style.top = `${centerY}px`;
document.body.appendChild(particle);
// Animate particle
setTimeout(() => {
particle.style.transform = `translate(${endX - centerX}px, ${endY - centerY}px)`;
particle.style.opacity = '0';
}, 10);
// Remove particle
setTimeout(() => {
if (particle.parentNode) {
document.body.removeChild(particle);
}
}, 800);
}
}
addRequiredStyles() {
const styles = document.createElement('style');
styles.textContent = ` .data-node-tooltip {
position: fixed;
background: rgba(15, 31, 74, 0.95); /* Darker blue background */
color: #ffffff;
padding: 16px 20px; /* Increased padding */
border-radius: 10px; /* More rounded corners */
font-size: 0.9rem;
line-height: 1.5;
max-width: 300px; /* Slightly wider */
min-width: 220px;
z-index: 100000; /* Ensure tooltip is above everything */
opacity: 0;
visibility: hidden;
transform: scale(0.95);
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); /* Smoother animation */
backdrop-filter: blur(8px); /* Improved blur effect */
border: 1px solid rgba(79, 150, 255, 0.4); /* Brighter border for contrast */
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6), 0 0 15px rgba(59, 130, 246, 0.3); /* Enhanced shadow */
pointer-events: none;
text-align: left; /* Left-aligned text for card style */
transform-origin: center top;
}
.tooltip-title {
font-weight: 700;
font-size: 1.1rem; /* Larger title */
color: #ffffff;
margin-bottom: 10px;
font-family: 'Space Grotesk', sans-serif;
letter-spacing: 0.5px;
border-bottom: 1px solid rgba(79, 150, 255, 0.3); /* Separator line */
padding-bottom: 8px;
}
.tooltip-description {
color: rgba(255, 255, 255, 0.9); /* Brighter text */
font-size: 0.9rem;
font-family: 'Inter', sans-serif;
line-height: 1.6;
}
.tooltip-arrow {
position: absolute;
bottom: -7px;
left: 50%;
transform: translateX(-50%) rotate(45deg);
width: 12px;
height: 12px;
background: rgba(15, 31, 74, 0.95); /* Match tooltip background */
border: 1px solid rgba(79, 150, 255, 0.4); /* Match tooltip border */
border-top: none;
border-left: none;
}
.data-node-tooltip.tooltip-below .tooltip-arrow {
bottom: auto;
top: -6px;
transform: translateX(-50%) rotate(-135deg);
border: 1px solid rgba(79, 150, 255, 0.4); /* Match tooltip border */
border-bottom: none;
border-right: none;
}
.data-node-ripple {
position: absolute;
border: 2px solid rgba(59, 130, 246, 0.6);
border-radius: 50%;
transform: scale(0);
animation: dataRipple 0.6s ease-out;
pointer-events: none;
}
@keyframes dataRipple {
to {
transform: scale(1);
opacity: 0;
}
}
.data-node-particle {
position: fixed;
width: 4px;
height: 4px;
background: radial-gradient(circle, rgba(59, 130, 246, 0.8), rgba(139, 92, 246, 0.6));
border-radius: 50%;
pointer-events: none;
transition: all 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
z-index: 9999;
}
@keyframes nodeClickPulse {
0% { transform: scale(1); }
50% { transform: scale(1.3); }
100% { transform: scale(1); }
}
.data-node {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
cursor: pointer;
}
.data-node:hover {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Enhanced neural network container interactions */
.neural-network-container .data-node {
transform-origin: center;
}
.neural-network-container .data-node:hover {
animation-play-state: paused;
}
/* Enhanced hero animation data nodes */
.hero-animation .data-node {
transform-origin: center;
}
.hero-animation .data-node:hover {
animation-play-state: paused;
}
/* Card tooltip animation */
.data-node-tooltip {
animation: tooltipPulse 3s ease-in-out infinite;
animation-play-state: paused;
}
.data-node:hover .data-node-tooltip {
animation-play-state: running;
}
@keyframes tooltipPulse {
0%, 100% {
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6), 0 0 15px rgba(59, 130, 246, 0.3);
}
50% {
box-shadow: 0 12px 35px rgba(0, 0, 0, 0.7), 0 0 25px rgba(79, 150, 255, 0.5);
}
}
`;
document.head.appendChild(styles);
}
}
// Create a singleton instance to prevent duplicate initializations
let dataNodeInteractionsInstance = null;
function initializeDataNodeInteractions() {
if (!dataNodeInteractionsInstance) {
dataNodeInteractionsInstance = new DataNodeInteractions();
}
return dataNodeInteractionsInstance;
}
// Initialize data node interactions when DOM is loaded
document.addEventListener('DOMContentLoaded', initializeDataNodeInteractions);
// Also initialize immediately if DOM is already loaded
if (document.readyState !== 'loading') {
initializeDataNodeInteractions();
}
// Export for potential use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = DataNodeInteractions;
}

View File

@@ -1,755 +0,0 @@
/**
* Enhanced Unified Neural Network Animation and Data Node Interactive Effects
* This file handles both the canvas background animation and data node interactions
* with advanced interactive elements and dynamic visual effects
*/
// Neural Network Canvas Animation Class
class NeuralNetworkAnimation {
constructor() {
this.canvas = document.querySelector('.mesh-canvas');
this.ctx = this.canvas ? this.canvas.getContext('2d') : null;
this.nodes = [];
this.connections = [];
this.mousePos = { x: 0, y: 0 };
this.animationId = null;
if (this.ctx) {
this.init();
}
}
init() {
this.setupCanvas();
this.createNodes();
this.setupInteractions();
this.setupResize();
this.animate();
}
setupCanvas() {
const heroSection = document.getElementById('hero');
if (heroSection) {
const rect = heroSection.getBoundingClientRect();
this.canvas.width = rect.width;
this.canvas.height = rect.height;
this.canvas.style.width = '100%';
this.canvas.style.height = '100%';
}
}
setupResize() {
window.addEventListener('resize', () => {
this.setupCanvas();
this.nodes.forEach(node => {
node.x = Math.min(node.x, this.canvas.width);
node.y = Math.min(node.y, this.canvas.height);
});
});
}
createNodes() {
const nodeCount = 40;
this.nodes = [];
for (let i = 0; i < nodeCount; i++) {
this.nodes.push({
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
vx: (Math.random() - 0.5) * 0.5,
vy: (Math.random() - 0.5) * 0.5,
radius: Math.random() * 3 + 1,
opacity: Math.random() * 0.5 + 0.2,
pulsePhase: Math.random() * Math.PI * 2,
energy: Math.random()
});
}
}
updateNodes() {
this.nodes.forEach(node => {
// Update position
node.x += node.vx;
node.y += node.vy;
// Bounce off edges
if (node.x <= 0 || node.x >= this.canvas.width) node.vx *= -1;
if (node.y <= 0 || node.y >= this.canvas.height) node.vy *= -1;
// Keep nodes in bounds
node.x = Math.max(0, Math.min(this.canvas.width, node.x));
node.y = Math.max(0, Math.min(this.canvas.height, node.y));
// Update pulse
node.pulsePhase += 0.02;
node.energy = 0.5 + 0.5 * Math.sin(node.pulsePhase);
});
}
drawNodes() {
this.nodes.forEach(node => {
const gradient = this.ctx.createRadialGradient(
node.x, node.y, 0,
node.x, node.y, node.radius * 3
);
const alpha = node.opacity * node.energy;
gradient.addColorStop(0, `rgba(59, 130, 246, ${alpha})`);
gradient.addColorStop(0.5, `rgba(139, 92, 246, ${alpha * 0.7})`);
gradient.addColorStop(1, `rgba(236, 72, 153, 0)`);
this.ctx.beginPath();
this.ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
this.ctx.fillStyle = gradient;
this.ctx.fill();
// Core dot
this.ctx.beginPath();
this.ctx.arc(node.x, node.y, node.radius * 0.3, 0, Math.PI * 2);
this.ctx.fillStyle = `rgba(255, 255, 255, ${alpha * 0.8})`;
this.ctx.fill();
});
}
drawConnections() {
const maxDistance = 120;
for (let i = 0; i < this.nodes.length; i++) {
for (let j = i + 1; j < this.nodes.length; j++) {
const nodeA = this.nodes[i];
const nodeB = this.nodes[j];
const dx = nodeB.x - nodeA.x;
const dy = nodeB.y - nodeA.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < maxDistance) {
const opacity = (1 - distance / maxDistance) * 0.3;
const energyBoost = (nodeA.energy + nodeB.energy) / 2;
// Create dynamic gradient line
const gradient = this.ctx.createLinearGradient(
nodeA.x, nodeA.y, nodeB.x, nodeB.y
);
gradient.addColorStop(0, `rgba(59, 130, 246, ${opacity * energyBoost})`);
gradient.addColorStop(0.5, `rgba(139, 92, 246, ${opacity * energyBoost * 0.8})`);
gradient.addColorStop(1, `rgba(236, 72, 153, ${opacity * energyBoost * 0.6})`);
this.ctx.strokeStyle = gradient;
this.ctx.lineWidth = 1;
this.ctx.globalCompositeOperation = 'lighter';
this.ctx.beginPath();
this.ctx.moveTo(nodeA.x, nodeA.y);
this.ctx.lineTo(nodeB.x, nodeB.y);
this.ctx.stroke();
this.ctx.globalCompositeOperation = 'source-over';
// Data pulse along connection
if (Math.random() < 0.01) {
this.createDataPulse(nodeA, nodeB);
}
}
}
}
}
createDataPulse(nodeA, nodeB) {
const pulse = {
startX: nodeA.x,
startY: nodeA.y,
endX: nodeB.x,
endY: nodeB.y,
progress: 0,
speed: 0.02,
life: 1
};
this.dataPulses = this.dataPulses || [];
this.dataPulses.push(pulse);
}
updateDataPulses() {
if (!this.dataPulses) return;
this.dataPulses = this.dataPulses.filter(pulse => {
pulse.progress += pulse.speed;
pulse.life -= 0.01;
if (pulse.progress >= 1 || pulse.life <= 0) {
return false;
}
// Draw pulse
const x = pulse.startX + (pulse.endX - pulse.startX) * pulse.progress;
const y = pulse.startY + (pulse.endY - pulse.startY) * pulse.progress;
const gradient = this.ctx.createRadialGradient(x, y, 0, x, y, 6);
gradient.addColorStop(0, `rgba(255, 255, 255, ${pulse.life})`);
gradient.addColorStop(1, `rgba(59, 130, 246, 0)`);
this.ctx.beginPath();
this.ctx.arc(x, y, 4, 0, Math.PI * 2);
this.ctx.fillStyle = gradient;
this.ctx.fill();
return true;
});
}
handleMouseMove(e) {
const rect = this.canvas.getBoundingClientRect();
this.mousePos.x = e.clientX - rect.left;
this.mousePos.y = e.clientY - rect.top;
// Create attraction effect
this.nodes.forEach(node => {
const dx = this.mousePos.x - node.x;
const dy = this.mousePos.y - node.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
const force = (100 - distance) / 100 * 0.01;
node.vx += dx * force;
node.vy += dy * force;
node.energy = Math.min(1, node.energy + 0.1);
}
});
}
animate() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Add subtle background gradient
const bgGradient = this.ctx.createRadialGradient(
this.canvas.width / 2, this.canvas.height / 2, 0,
this.canvas.width / 2, this.canvas.height / 2, Math.max(this.canvas.width, this.canvas.height) / 2
);
bgGradient.addColorStop(0, 'rgba(59, 130, 246, 0.02)');
bgGradient.addColorStop(1, 'rgba(139, 92, 246, 0.01)');
this.ctx.fillStyle = bgGradient;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.updateNodes();
this.drawConnections();
this.drawNodes();
this.updateDataPulses();
this.animationId = requestAnimationFrame(() => this.animate());
}
setupInteractions() {
// Mouse interaction only - data node interactions handled by DataNodeInteractions class
this.canvas.addEventListener('mousemove', (e) => this.handleMouseMove(e));
}
destroy() {
if (this.animationId) {
cancelAnimationFrame(this.animationId);
}
}
}
// Data Node Interactive Effects Class
class DataNodeInteractions {
constructor() {
this.init();
}
init() {
// Wait for DOM to be fully loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
this.initializeInteractions();
});
} else {
this.initializeInteractions();
}
}
initializeInteractions() {
this.setupTooltips();
this.setupHoverEffects();
this.setupClickEffects();
this.addRequiredStyles();
}
setupTooltips() {
const dataNodes = document.querySelectorAll('.data-node');
dataNodes.forEach((node, index) => {
// Create tooltip element
const tooltip = this.createTooltip(node);
document.body.appendChild(tooltip); // Append to body instead of node for better positioning
// Store reference to the tooltip on the node
node.tooltip = tooltip;
// Add hover events for tooltip
node.addEventListener('mouseenter', (e) => {
this.showTooltip(tooltip, node, e);
this.triggerHoverEffect(node);
});
node.addEventListener('mouseleave', () => {
this.hideTooltip(tooltip);
this.resetHoverEffect(node);
});
// Update tooltip position on mouse move - only if needed
node.addEventListener('mousemove', (e) => {
// Only update on significant mouse movement to prevent jitter
if (!node.lastMouseX || Math.abs(e.clientX - node.lastMouseX) > 5 ||
!node.lastMouseY || Math.abs(e.clientY - node.lastMouseY) > 5) {
this.updateTooltipPosition(tooltip, node, e);
node.lastMouseX = e.clientX;
node.lastMouseY = e.clientY;
}
});
});
}
createTooltip(node) {
const techType = node.getAttribute('data-tech');
const tooltip = document.createElement('div');
tooltip.className = 'data-node-tooltip';
// Enhanced concise descriptions for each technology
const descriptions = {
'Machine Learning': 'Building intelligent systems that learn from data to predict outcomes and automate decisions.',
'Generative AI': 'Creating novel content from text and images to code, unlocking new creative possibilities.',
'Data Analytics': 'Transforming raw data into actionable business insights to drive strategic decisions.',
'Automation': 'Designing intelligent workflows that increase efficiency and free up human resources.',
'Finance': 'Using AI for risk assessment, fraud detection, and optimized investment strategies.',
'Healthcare': 'Enabling faster diagnoses, personalized treatments, and improved patient care.',
'Retail': 'Powering personalized shopping experiences, inventory optimization, and demand forecasting.',
'Manufacturing': 'Enhancing production efficiency, quality control, and supply chain optimization.',
'Agentic AI': 'Developing autonomous AI agents that perceive environments and take goal-driven actions.',
'Marketing': 'Creating data-driven campaigns, customer segmentation, and conversion optimization.',
'Media & Entertainment': 'Enabling content creation, audience engagement, and personalized recommendations.',
'Travel': 'Implementing smart pricing strategies and enhancing customer travel experiences.',
'Education': 'Delivering personalized learning paths and educational content innovation.',
'Technology': 'Providing cutting-edge AI development and integration services for tech companies.'
};
tooltip.innerHTML = `
<div class="tooltip-title">${techType}</div>
<div class="tooltip-description">${descriptions[techType] || 'AI-powered solutions and innovations for business transformation.'}</div>
<div class="tooltip-arrow"></div>
`;
return tooltip;
}
showTooltip(tooltip, node, event) {
// Reset any ongoing transitions with enhanced animation
tooltip.style.transition = 'all 0.3s cubic-bezier(0.2, 0, 0.2, 1)'; // Smoother easing
tooltip.style.opacity = '1';
tooltip.style.visibility = 'visible';
tooltip.style.transform = 'translate(-50%, 0) scale(1)';
// Add a subtle animation highlight
setTimeout(() => {
tooltip.style.boxShadow = '0 12px 35px rgba(0, 0, 0, 0.7), 0 0 20px rgba(79, 150, 255, 0.4)';
}, 50);
this.updateTooltipPosition(tooltip, node, event);
// Hide any other visible tooltips
document.querySelectorAll('.data-node-tooltip').forEach(otherTooltip => {
if (otherTooltip !== tooltip && otherTooltip.style.visibility === 'visible') {
otherTooltip.style.opacity = '0';
otherTooltip.style.visibility = 'hidden';
}
});
}
hideTooltip(tooltip) {
// Smooth fade out
tooltip.style.transition = 'all 0.25s cubic-bezier(0.4, 0, 1, 1)';
tooltip.style.opacity = '0';
tooltip.style.visibility = 'hidden';
tooltip.style.transform = 'translate(-50%, 12px) scale(0.95)';
tooltip.style.boxShadow = '0 10px 30px rgba(0, 0, 0, 0.6), 0 0 15px rgba(59, 130, 246, 0.3)';
}
updateTooltipPosition(tooltip, node, event) {
const rect = node.getBoundingClientRect();
// Ensure the tooltip has proper dimensions for calculation
tooltip.style.visibility = 'hidden';
tooltip.style.opacity = '0';
tooltip.style.display = 'block';
const tooltipRect = tooltip.getBoundingClientRect();
// Position tooltip above the node with increased distance for card style
let left = rect.left + (rect.width / 2);
let top = rect.top - tooltipRect.height - 20; // Distance above node
// Adjust if tooltip goes off screen
const viewport = {
width: window.innerWidth,
height: window.innerHeight
};
// Check if we're on the right side of the screen (possibly overlapping hero content)
const isRightSide = rect.left > (viewport.width / 2);
// Position based on side of screen for better readability
if (isRightSide) {
// For nodes on right side, align to the right edge of the node
left = rect.right - tooltipRect.width/2;
} else {
// For left side nodes, align to the left edge of the node
left = rect.left + tooltipRect.width/2;
}
// Ensure tooltip stays within viewport bounds with margins
const margin = 25;
const maxLeft = viewport.width - tooltipRect.width - margin;
const minLeft = margin + tooltipRect.width/2;
left = Math.max(minLeft, Math.min(left, maxLeft));
// If not enough room above, show below
if (top < margin) {
top = rect.bottom + 20; // Place below with distance
tooltip.classList.add('tooltip-below');
} else {
tooltip.classList.remove('tooltip-below');
}
// Apply the positioning
tooltip.style.left = `${left}px`;
tooltip.style.top = `${top}px`;
// Reset visibility state to what it should be (it was set to hidden for calculations)
if (node.matches(':hover')) {
tooltip.style.visibility = 'visible';
tooltip.style.opacity = '1';
}
}
setupHoverEffects() {
const dataNodes = document.querySelectorAll('.data-node');
dataNodes.forEach((node, index) => {
node.addEventListener('mouseenter', () => {
this.triggerHoverEffect(node);
this.createRippleEffect(node);
});
node.addEventListener('mouseleave', () => {
this.resetHoverEffect(node);
});
});
}
triggerHoverEffect(node) {
// Enhanced glow effect
node.style.transform = 'scale(1.15)';
node.style.zIndex = '1000';
// Add glow to node core
const nodeCore = node.querySelector('.node-core');
if (nodeCore) {
nodeCore.style.boxShadow = '0 0 30px rgba(59, 130, 246, 0.8), 0 0 60px rgba(139, 92, 246, 0.6)';
nodeCore.style.background = 'radial-gradient(circle, rgba(59, 130, 246, 0.4), rgba(139, 92, 246, 0.3))';
}
// Enhance icon visibility
const nodeIcon = node.querySelector('.node-icon img');
if (nodeIcon) {
nodeIcon.style.filter = 'brightness(1.2) saturate(1.3) drop-shadow(0 0 10px rgba(255, 255, 255, 0.8))';
}
// Brighten label
const nodeLabel = node.querySelector('.node-label');
if (nodeLabel) {
nodeLabel.style.color = '#ffffff';
nodeLabel.style.textShadow = '0 0 10px rgba(59, 130, 246, 0.8)';
nodeLabel.style.fontWeight = '600';
}
}
resetHoverEffect(node) {
node.style.transform = '';
node.style.zIndex = '';
const nodeCore = node.querySelector('.node-core');
if (nodeCore) {
nodeCore.style.boxShadow = '';
nodeCore.style.background = '';
}
const nodeIcon = node.querySelector('.node-icon img');
if (nodeIcon) {
nodeIcon.style.filter = '';
}
const nodeLabel = node.querySelector('.node-label');
if (nodeLabel) {
nodeLabel.style.color = '';
nodeLabel.style.textShadow = '';
nodeLabel.style.fontWeight = '';
}
}
createRippleEffect(node) {
const ripple = document.createElement('div');
ripple.className = 'data-node-ripple';
const rect = node.getBoundingClientRect();
const size = Math.max(rect.width, rect.height) * 2;
ripple.style.width = `${size}px`;
ripple.style.height = `${size}px`;
ripple.style.left = `${rect.width / 2 - size / 2}px`;
ripple.style.top = `${rect.height / 2 - size / 2}px`;
node.appendChild(ripple);
// Remove ripple after animation
setTimeout(() => {
if (ripple.parentNode) {
ripple.parentNode.removeChild(ripple);
}
}, 600);
}
setupClickEffects() {
const dataNodes = document.querySelectorAll('.data-node');
dataNodes.forEach(node => {
node.addEventListener('click', () => {
this.triggerClickEffect(node);
this.createBurstEffect(node);
});
});
}
triggerClickEffect(node) {
// Create pulsating effect
node.style.animation = 'none';
setTimeout(() => {
node.style.animation = 'nodeClickPulse 0.6s ease-out';
}, 10);
// Reset animation after completion
setTimeout(() => {
node.style.animation = '';
}, 600);
}
createBurstEffect(node) {
const particles = 8;
const rect = node.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
for (let i = 0; i < particles; i++) {
const particle = document.createElement('div');
particle.className = 'data-node-particle';
const angle = (360 / particles) * i;
const distance = 50 + Math.random() * 30;
const endX = centerX + Math.cos(angle * Math.PI / 180) * distance;
const endY = centerY + Math.sin(angle * Math.PI / 180) * distance;
particle.style.left = `${centerX}px`;
particle.style.top = `${centerY}px`;
document.body.appendChild(particle);
// Animate particle
setTimeout(() => {
particle.style.transform = `translate(${endX - centerX}px, ${endY - centerY}px)`;
particle.style.opacity = '0';
}, 10);
// Remove particle
setTimeout(() => {
if (particle.parentNode) {
document.body.removeChild(particle);
}
}, 800);
}
}
addRequiredStyles() {
const styles = document.createElement('style');
styles.textContent = `
.data-node-tooltip {
position: fixed;
background: rgba(15, 31, 74, 0.95); /* Darker blue background */
color: #ffffff;
padding: 16px 20px; /* Increased padding */
border-radius: 10px; /* More rounded corners */
font-size: 0.9rem;
line-height: 1.5;
max-width: 300px; /* Slightly wider */
min-width: 220px;
z-index: 50000;
opacity: 0;
visibility: hidden;
transform: translateY(0) scale(0.95);
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); /* Smoother animation */
backdrop-filter: blur(8px); /* Improved blur effect */
border: 1px solid rgba(79, 150, 255, 0.4); /* Brighter border for contrast */
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6), 0 0 15px rgba(59, 130, 246, 0.3); /* Enhanced shadow */
pointer-events: none;
text-align: left; /* Left-aligned text for card style */
left: 50%;
transform-origin: bottom center;
}
.tooltip-title {
font-weight: 700;
font-size: 1.1rem; /* Larger title */
color: #ffffff;
margin-bottom: 10px;
font-family: 'Space Grotesk', sans-serif;
letter-spacing: 0.5px;
border-bottom: 1px solid rgba(79, 150, 255, 0.3); /* Separator line */
padding-bottom: 8px;
}
.tooltip-description {
color: rgba(255, 255, 255, 0.9); /* Brighter text */
font-size: 0.9rem;
font-family: 'Inter', sans-serif;
line-height: 1.6;
}
.tooltip-arrow {
position: absolute;
bottom: -7px;
left: 50%;
transform: translateX(-50%) rotate(45deg);
width: 12px;
height: 12px;
background: rgba(15, 31, 74, 0.95); /* Match tooltip background */
border: 1px solid rgba(79, 150, 255, 0.4); /* Match tooltip border */
border-top: none;
border-left: none;
}
.data-node-tooltip.tooltip-below .tooltip-arrow {
bottom: auto;
top: -6px;
transform: translateX(-50%) rotate(-135deg);
border: 1px solid rgba(79, 150, 255, 0.4); /* Match tooltip border */
border-bottom: none;
border-right: none;
}
.data-node-ripple {
position: absolute;
border: 2px solid rgba(59, 130, 246, 0.6);
border-radius: 50%;
transform: scale(0);
animation: dataRipple 0.6s ease-out;
pointer-events: none;
}
@keyframes dataRipple {
to {
transform: scale(1);
opacity: 0;
}
}
.data-node-particle {
position: fixed;
width: 4px;
height: 4px;
background: radial-gradient(circle, rgba(59, 130, 246, 0.8), rgba(139, 92, 246, 0.6));
border-radius: 50%;
pointer-events: none;
transition: all 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
z-index: 9999;
}
@keyframes nodeClickPulse {
0% { transform: scale(1); }
50% { transform: scale(1.3); }
100% { transform: scale(1); }
}
.data-node {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
cursor: pointer;
}
.data-node:hover {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Enhanced neural network container interactions */
.neural-network-container .data-node {
transform-origin: center;
}
.neural-network-container .data-node:hover {
animation-play-state: paused;
}
/* Enhanced hero animation data nodes */
.hero-animation .data-node {
transform-origin: center;
}
.hero-animation .data-node:hover {
animation-play-state: paused;
}
/* Card tooltip animation */
.data-node-tooltip {
animation: tooltipPulse 3s ease-in-out infinite;
animation-play-state: paused;
}
.data-node:hover .data-node-tooltip {
animation-play-state: running;
}
@keyframes tooltipPulse {
0%, 100% {
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6), 0 0 15px rgba(59, 130, 246, 0.3);
}
50% {
box-shadow: 0 12px 35px rgba(0, 0, 0, 0.7), 0 0 25px rgba(79, 150, 255, 0.5);
}
}
`;
document.head.appendChild(styles);
}
}
// Initialize data node interactions when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new DataNodeInteractions();
});
// Initialize when script loads
document.addEventListener('DOMContentLoaded', () => {
new DataNodeInteractions();
});
// Also initialize immediately if DOM is already loaded
if (document.readyState === 'loading') {
// Document is still loading, wait for DOMContentLoaded
} else {
// Document has already loaded
new DataNodeInteractions();
}
// Export for potential use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = DataNodeInteractions;
}

View File

@@ -1,273 +0,0 @@
/**
* Hero Animation - Neural network visualization and interactive node effects
*/
document.addEventListener('DOMContentLoaded', function() {
// Initialize neural mesh canvas
initNeuralMesh();
// Initialize data nodes interaction
initDataNodes();
// Initialize morphing shapes animation
initMorphingShapes();
// Initialize data streams animation
initDataStreams();
});
// Create neural mesh network visualization
function initNeuralMesh() {
const canvas = document.querySelector('.mesh-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
// Neural network settings
const nodeCount = 120;
const nodes = [];
const connections = [];
const connectionDistance = 150;
const nodeSize = 2;
// Create nodes
for (let i = 0; i < nodeCount; i++) {
nodes.push({
x: Math.random() * width,
y: Math.random() * height,
vx: (Math.random() - 0.5) * 0.5,
vy: (Math.random() - 0.5) * 0.5,
size: Math.random() * nodeSize + 1,
color: `rgba(255, 255, 255, ${Math.random() * 0.5 + 0.1})`
});
}
// Animation loop
function animate() {
// Clear canvas
ctx.clearRect(0, 0, width, height);
// Draw connections
connections.length = 0;
for (let i = 0; i < nodes.length; i++) {
const nodeA = nodes[i];
for (let j = i + 1; j < nodes.length; j++) {
const nodeB = nodes[j];
const dx = nodeB.x - nodeA.x;
const dy = nodeB.y - nodeA.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < connectionDistance) {
const opacity = 1 - (distance / connectionDistance);
connections.push({
x1: nodeA.x,
y1: nodeA.y,
x2: nodeB.x,
y2: nodeB.y,
opacity
});
}
}
}
// Draw connections
for (const connection of connections) {
ctx.beginPath();
ctx.moveTo(connection.x1, connection.y1);
ctx.lineTo(connection.x2, connection.y2);
ctx.strokeStyle = `rgba(80, 200, 255, ${connection.opacity * 0.3})`;
ctx.lineWidth = 0.5;
ctx.stroke();
}
// Draw and update nodes
for (const node of nodes) {
ctx.beginPath();
ctx.arc(node.x, node.y, node.size, 0, Math.PI * 2);
ctx.fillStyle = node.color;
ctx.fill();
// Update position
node.x += node.vx;
node.y += node.vy;
// Bounce off edges
if (node.x < 0 || node.x > width) node.vx *= -1;
if (node.y < 0 || node.y > height) node.vy *= -1;
}
requestAnimationFrame(animate);
}
// Start animation
animate();
// Add mouse interaction
canvas.addEventListener('mousemove', function(e) {
const rect = canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
// Add attraction to mouse position for nearby nodes
for (const node of nodes) {
const dx = mouseX - node.x;
const dy = mouseY - node.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
node.x += dx * 0.02;
node.y += dy * 0.02;
}
}
});
}
// Initialize interactive data nodes
function initDataNodes() {
const nodes = document.querySelectorAll('.data-node');
nodes.forEach(node => { // Add hover effects
node.addEventListener('mouseenter', function() {
// Highlight node
this.classList.add('node-hover');
// Create connecting lines to related nodes
const tech = this.getAttribute('data-tech');
const connectedTech = getRelatedTechnologies(tech);
nodes.forEach(otherNode => {
const otherTech = otherNode.getAttribute('data-tech');
if (otherTech && connectedTech.includes(otherTech)) {
otherNode.classList.add('node-connected');
}
});
});
// Remove effects on mouse leave
node.addEventListener('mouseleave', function() {
// Remove highlight
this.classList.remove('node-hover');
// Remove connecting lines
nodes.forEach(otherNode => {
otherNode.classList.remove('node-connected');
});
});
// Add click interaction
node.addEventListener('click', function() {
const tech = this.getAttribute('data-tech');
if (!tech) return;
// Get corresponding URL for the technology
const url = getTechnologyPageUrl(tech);
if (url) {
// Create click pulse effect
const pulse = document.createElement('div');
pulse.className = 'node-pulse';
this.appendChild(pulse);
// Navigate after animation
setTimeout(() => {
window.location.href = url;
}, 300);
}
});
});
// Add pulsing animation to core nodes
const coreNodes = document.querySelectorAll('.node-core');
coreNodes.forEach(node => {
setInterval(() => {
node.classList.add('core-pulse-active');
setTimeout(() => {
node.classList.remove('core-pulse-active');
}, 1500);
}, 3000 + Math.random() * 2000); // Randomize timing for natural effect
});
}
// Map technology names to related technologies
function getRelatedTechnologies(tech) {
const techMap = {
'Machine Learning': ['Data Analytics', 'Generative AI', 'Agentic AI'],
'Generative AI': ['Machine Learning', 'Data Analytics', 'Media & Entertainment'],
'Data Analytics': ['Machine Learning', 'Finance', 'Retail'],
'Automation': ['Agentic AI', 'Manufacturing', 'Healthcare'],
'Finance': ['Data Analytics', 'Machine Learning'],
'Healthcare': ['Machine Learning', 'Automation'],
'Retail': ['Data Analytics', 'Machine Learning'],
'Manufacturing': ['Automation', 'Data Analytics'],
'Agentic AI': ['Machine Learning', 'Automation'],
'Marketing': ['Data Analytics', 'Generative AI'],
'Media & Entertainment': ['Generative AI', 'Data Analytics'],
'Travel': ['Data Analytics', 'Automation'],
'Education': ['Generative AI', 'Machine Learning'],
'Technology': ['Machine Learning', 'Agentic AI', 'Data Analytics', 'Automation']
};
return techMap[tech] || [];
}
// Map technology names to page URLs
function getTechnologyPageUrl(tech) {
const urlMap = {
'Machine Learning': 'Services/machine-learning.html',
'Generative AI': 'Services/generative-ai.html',
'Data Analytics': 'Services/data-analysis.html',
'Automation': 'Services/automation-flows.html',
'Agentic AI': 'Services/agentic-ai.html',
'Finance': 'Industries/finance.html',
'Healthcare': 'Industries/healthcare.html',
'Retail': 'Industries/retail.html',
'Manufacturing': 'Industries/manufacturing.html',
'Marketing': 'Industries/marketing.html',
'Media & Entertainment': 'Industries/media-entertainment.html',
'Travel': 'Industries/travel.html',
'Education': 'Education/workshops.html',
'Technology': 'about.html'
};
return urlMap[tech] || null;
}
// Initialize morphing geometric shapes
function initMorphingShapes() {
const morphShapes = document.querySelectorAll('.morph-shape');
morphShapes.forEach(shape => {
// Random initial properties
const size = Math.random() * 100 + 50;
const opacity = Math.random() * 0.15 + 0.05;
const rotation = Math.random() * 360;
const duration = Math.random() * 10 + 15;
const delay = Math.random() * 5;
// Set initial style
shape.style.width = `${size}px`;
shape.style.height = `${size}px`;
shape.style.opacity = opacity;
shape.style.transform = `rotate(${rotation}deg)`;
shape.style.animationDuration = `${duration}s`;
shape.style.animationDelay = `${delay}s`;
});
}
// Initialize data streams animation
function initDataStreams() {
const streams = document.querySelectorAll('.stream, .stream-horizontal, .stream-diagonal');
streams.forEach(stream => {
// Random animation properties
const duration = Math.random() * 8 + 4;
const delay = Math.random() * 3;
// Apply animation with random timing
stream.style.animationDuration = `${duration}s`;
stream.style.animationDelay = `${delay}s`;
});
}

View File

@@ -68,7 +68,7 @@ function initSectionTransitions() {
// Custom cursor effects for interactive elements
function initCursorEffects() {
const interactiveElements = document.querySelectorAll('a, button, .data-node, .tech-marquee-item');
const interactiveElements = document.querySelectorAll('a, button, .data-node, .tech-card');
const body = document.body;
// Create custom cursor elements

View File

@@ -1,6 +1,46 @@
// Fallback: Enhance dropdowns with fade/slide effect if not handled elsewhere
// (dropdown.js already handles logic, so this is for extra UI polish)
document.addEventListener('DOMContentLoaded', function() {
// Hamburger menu functionality
const hamburgerMenu = document.querySelector('.hamburger-menu');
const navLinks = document.querySelector('.nav-links');
if (hamburgerMenu && navLinks) {
hamburgerMenu.addEventListener('click', function() {
hamburgerMenu.classList.toggle('active');
navLinks.classList.toggle('active');
// Prevent body scrolling when menu is open
if (navLinks.classList.contains('active')) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
});
// Close menu when clicking on nav links
navLinks.addEventListener('click', function(e) {
if (e.target.classList.contains('nav-link') && !e.target.closest('.dropdown')) {
hamburgerMenu.classList.remove('active');
navLinks.classList.remove('active');
document.body.style.overflow = '';
}
});
// Handle dropdown toggles in mobile menu
const dropdownToggles = document.querySelectorAll('.dropdown > .nav-link');
dropdownToggles.forEach(toggle => {
toggle.addEventListener('click', function(e) {
if (window.innerWidth <= 768) {
e.preventDefault();
const dropdownMenu = this.nextElementSibling;
dropdownMenu.classList.toggle('show');
}
});
});
}
// Original dropdown enhancement code
document.querySelectorAll('.dropdown-menu').forEach(menu => {
menu.addEventListener('transitionend', function() {
if (!menu.classList.contains('show')) {

View File

@@ -1,27 +1,26 @@
// Tech Marquee Animation Enhancement
// Tech Cards Animation Enhancement
document.addEventListener('DOMContentLoaded', function() {
const techMarqueeContents = document.querySelectorAll('.tech-marquee-content');
const techItems = document.querySelectorAll('.tech-marquee-item');
const techCardsContainer = document.querySelector('.tech-cards-container');
const techCards = document.querySelectorAll('.tech-card');
// Adjust animation speed for each marquee
techMarqueeContents.forEach((marquee, index) => {
const isReversed = marquee.classList.contains('tech-marquee-content-reversed');
const marqueeItems = marquee.querySelectorAll('.tech-marquee-item');
const itemCount = marqueeItems.length / 2; // Account for duplicated items
// No animation delay or dancing effects
techCards.forEach((card) => {
// Just add basic hover interaction
card.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-10px)';
});
// Set slightly different speeds for each marquee
const baseSpeed = isReversed ? 65 : 60;
const animationDuration = Math.max(30, Math.min(70, itemCount * 5)); // Between 30s and 70s
marquee.style.animationDuration = `${baseSpeed + (index * 10)}s`;
});
// Add 3D tilt effect on mouse move for each tech icon
techItems.forEach(item => {
const iconContainer = item.querySelector('.tech-icon-container');
card.addEventListener('mouseleave', function() {
this.style.transform = '';
});
});
// Add 3D tilt effect on mouse move for each tech card
techCards.forEach(card => {
const iconWrapper = card.querySelector('.tech-icon-wrapper');
if (iconContainer) {
item.addEventListener('mousemove', function(e) {
const rect = iconContainer.getBoundingClientRect();
if (iconWrapper) {
card.addEventListener('mousemove', function(e) {
const rect = iconWrapper.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
@@ -31,37 +30,40 @@ document.addEventListener('DOMContentLoaded', function() {
const tiltX = (centerX - x) / 10;
const tiltY = (y - centerY) / 10;
iconContainer.style.transform = `perspective(500px) rotateX(${tiltY}deg) rotateY(${-tiltX}deg) scale3d(1.05, 1.05, 1.05)`;
iconWrapper.style.transform = `perspective(500px) rotateX(${tiltY}deg) rotateY(${-tiltX}deg) scale3d(1.1, 1.1, 1.1)`;
});
item.addEventListener('mouseleave', function() {
iconContainer.style.transform = '';
card.addEventListener('mouseleave', function() {
iconWrapper.style.transform = '';
});
}
});
// Removed pulse effects functionality - displaying raw icons without glow effects
// Add a parallax effect to create depth between the two marquees
// Add a parallax effect to create depth in the tech cards container
window.addEventListener('mousemove', function(e) {
const containers = document.querySelectorAll('.tech-marquee-container');
containers.forEach((container, index) => {
const isReversed = container.classList.contains('tech-marquee-reversed');
const depth = isReversed ? 25 : 15; // Reduced sensitivity due to full width
if (techCardsContainer) {
const depth = 20;
const moveX = (e.clientX - window.innerWidth / 2) / depth;
const moveY = (e.clientY - window.innerHeight / 2) / depth;
// Limit the movement for a subtler effect with the full-width design
const maxMove = 10;
// Limit the movement for a subtler effect
const maxMove = 5;
const limitedMoveX = Math.max(-maxMove, Math.min(maxMove, moveX));
const limitedMoveY = Math.max(-maxMove, Math.min(maxMove, moveY));
container.style.transform = `translate(${limitedMoveX}px, ${limitedMoveY}px)`;
});
techCardsContainer.style.transform = `translate(${limitedMoveX}px, ${limitedMoveY}px)`;
}
});
// Add entrance animation for each tech item
const allMarquees = document.querySelectorAll('.tech-marquee-container');
allMarquees.forEach((marquee, marqueeIndex) => {
marquee.style.animationDelay = `${marqueeIndex * 0.2}s`;
});
// Add entrance animation for the tech cards container
if (techCardsContainer) {
techCardsContainer.style.opacity = '0';
techCardsContainer.style.transform = 'translateY(20px)';
setTimeout(() => {
techCardsContainer.style.transition = 'opacity 0.8s ease-out, transform 0.8s ease-out';
techCardsContainer.style.opacity = '1';
techCardsContainer.style.transform = 'translateY(0)';
}, 200);
}
});

View File

@@ -1,813 +0,0 @@
/**
* Enhanced Unified Neural Network Animation and Data Node Interactive Effects
* This file provides advanced visual effects and interactive animations for the neural network and data nodes
* with optimized performance and responsive behavior across devices
*/
// Neural Network Canvas Animation Class
class NeuralNetworkAnimation {
constructor() {
this.canvas = document.querySelector('.mesh-canvas');
this.ctx = this.canvas ? this.canvas.getContext('2d') : null;
this.nodes = [];
this.connections = [];
this.mousePos = { x: 0, y: 0 };
this.animationId = null;
if (this.ctx) {
this.init();
}
}
init() {
this.setupCanvas();
this.createNodes();
this.setupInteractions();
this.setupResize();
this.animate();
}
setupCanvas() {
const heroSection = document.getElementById('hero');
if (heroSection) {
const rect = heroSection.getBoundingClientRect();
this.canvas.width = rect.width;
this.canvas.height = rect.height;
this.canvas.style.width = '100%';
this.canvas.style.height = '100%';
}
}
setupResize() {
window.addEventListener('resize', () => {
this.setupCanvas();
this.nodes.forEach(node => {
node.x = Math.min(node.x, this.canvas.width);
node.y = Math.min(node.y, this.canvas.height);
});
});
}
createNodes() {
const nodeCount = 40;
this.nodes = [];
for (let i = 0; i < nodeCount; i++) {
this.nodes.push({
x: Math.random() * this.canvas.width,
y: Math.random() * this.canvas.height,
vx: (Math.random() - 0.5) * 0.5,
vy: (Math.random() - 0.5) * 0.5,
radius: Math.random() * 3 + 1,
opacity: Math.random() * 0.5 + 0.2,
pulsePhase: Math.random() * Math.PI * 2,
energy: Math.random()
});
}
}
updateNodes() {
this.nodes.forEach(node => {
// Update position
node.x += node.vx;
node.y += node.vy;
// Bounce off edges
if (node.x <= 0 || node.x >= this.canvas.width) node.vx *= -1;
if (node.y <= 0 || node.y >= this.canvas.height) node.vy *= -1;
// Keep nodes in bounds
node.x = Math.max(0, Math.min(this.canvas.width, node.x));
node.y = Math.max(0, Math.min(this.canvas.height, node.y));
// Update pulse
node.pulsePhase += 0.02;
node.energy = 0.5 + 0.5 * Math.sin(node.pulsePhase);
});
}
drawNodes() {
this.nodes.forEach(node => {
const gradient = this.ctx.createRadialGradient(
node.x, node.y, 0,
node.x, node.y, node.radius * 3
);
const alpha = node.opacity * node.energy;
gradient.addColorStop(0, `rgba(59, 130, 246, ${alpha})`);
gradient.addColorStop(0.5, `rgba(139, 92, 246, ${alpha * 0.7})`);
gradient.addColorStop(1, `rgba(236, 72, 153, 0)`);
this.ctx.beginPath();
this.ctx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
this.ctx.fillStyle = gradient;
this.ctx.fill();
// Core dot
this.ctx.beginPath();
this.ctx.arc(node.x, node.y, node.radius * 0.3, 0, Math.PI * 2);
this.ctx.fillStyle = `rgba(255, 255, 255, ${alpha * 0.8})`;
this.ctx.fill();
});
}
drawConnections() {
const maxDistance = 120;
for (let i = 0; i < this.nodes.length; i++) {
for (let j = i + 1; j < this.nodes.length; j++) {
const nodeA = this.nodes[i];
const nodeB = this.nodes[j];
const dx = nodeB.x - nodeA.x;
const dy = nodeB.y - nodeA.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < maxDistance) {
const opacity = (1 - distance / maxDistance) * 0.3;
const energyBoost = (nodeA.energy + nodeB.energy) / 2;
// Create dynamic gradient line
const gradient = this.ctx.createLinearGradient(
nodeA.x, nodeA.y, nodeB.x, nodeB.y
);
gradient.addColorStop(0, `rgba(59, 130, 246, ${opacity * energyBoost})`);
gradient.addColorStop(0.5, `rgba(139, 92, 246, ${opacity * energyBoost * 0.8})`);
gradient.addColorStop(1, `rgba(236, 72, 153, ${opacity * energyBoost * 0.6})`);
this.ctx.strokeStyle = gradient;
this.ctx.lineWidth = 1;
this.ctx.globalCompositeOperation = 'lighter';
this.ctx.beginPath();
this.ctx.moveTo(nodeA.x, nodeA.y);
this.ctx.lineTo(nodeB.x, nodeB.y);
this.ctx.stroke();
this.ctx.globalCompositeOperation = 'source-over';
// Data pulse along connection
if (Math.random() < 0.01) {
this.createDataPulse(nodeA, nodeB);
}
}
}
}
}
createDataPulse(nodeA, nodeB) {
const pulse = {
startX: nodeA.x,
startY: nodeA.y,
endX: nodeB.x,
endY: nodeB.y,
progress: 0,
speed: 0.02,
life: 1
};
this.dataPulses = this.dataPulses || [];
this.dataPulses.push(pulse);
}
updateDataPulses() {
if (!this.dataPulses) return;
this.dataPulses = this.dataPulses.filter(pulse => {
pulse.progress += pulse.speed;
pulse.life -= 0.01;
if (pulse.progress >= 1 || pulse.life <= 0) {
return false;
}
// Draw pulse
const x = pulse.startX + (pulse.endX - pulse.startX) * pulse.progress;
const y = pulse.startY + (pulse.endY - pulse.startY) * pulse.progress;
const gradient = this.ctx.createRadialGradient(x, y, 0, x, y, 6);
gradient.addColorStop(0, `rgba(255, 255, 255, ${pulse.life})`);
gradient.addColorStop(1, `rgba(59, 130, 246, 0)`);
this.ctx.beginPath();
this.ctx.arc(x, y, 4, 0, Math.PI * 2);
this.ctx.fillStyle = gradient;
this.ctx.fill();
return true;
});
}
handleMouseMove(e) {
const rect = this.canvas.getBoundingClientRect();
this.mousePos.x = e.clientX - rect.left;
this.mousePos.y = e.clientY - rect.top;
// Create attraction effect
this.nodes.forEach(node => {
const dx = this.mousePos.x - node.x;
const dy = this.mousePos.y - node.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
const force = (100 - distance) / 100 * 0.01;
node.vx += dx * force;
node.vy += dy * force;
node.energy = Math.min(1, node.energy + 0.1);
}
});
}
animate() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Add subtle background gradient
const bgGradient = this.ctx.createRadialGradient(
this.canvas.width / 2, this.canvas.height / 2, 0,
this.canvas.width / 2, this.canvas.height / 2, Math.max(this.canvas.width, this.canvas.height) / 2
);
bgGradient.addColorStop(0, 'rgba(59, 130, 246, 0.02)');
bgGradient.addColorStop(1, 'rgba(139, 92, 246, 0.01)');
this.ctx.fillStyle = bgGradient;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.updateNodes();
this.drawConnections();
this.drawNodes();
this.updateDataPulses();
this.animationId = requestAnimationFrame(() => this.animate());
}
setupInteractions() {
// Mouse interaction only - data node interactions handled by DataNodeInteractions class
this.canvas.addEventListener('mousemove', (e) => this.handleMouseMove(e));
}
destroy() {
if (this.animationId) {
cancelAnimationFrame(this.animationId);
}
}
}
// Data Node Interactive Effects Class
class DataNodeInteractions {
constructor() {
this.tooltips = new Map();
this.initializeInteractions();
this.addStyles();
} initializeInteractions() {
console.log('Initializing data node interactions...');
// Look for data nodes in both containers
const neuralNetworkNodes = document.querySelectorAll('.neural-network-container .data-node');
const heroAnimationNodes = document.querySelectorAll('.hero-animation .data-node');
console.log(`Found ${neuralNetworkNodes.length} data nodes in neural-network-container`);
console.log(`Found ${heroAnimationNodes.length} data nodes in hero-animation`);
// Debug: Check computed styles and verify they're interactive
console.log('=== NEURAL NETWORK NODES ===');
neuralNetworkNodes.forEach((node, index) => {
const label = node.querySelector('.node-label')?.textContent?.trim();
const classes = node.className;
const computedStyle = window.getComputedStyle(node);
const zIndex = computedStyle.zIndex;
const pointerEvents = computedStyle.pointerEvents;
console.log(`Neural Node ${index + 1}: "${label}" (z-index: ${zIndex}, pointer-events: ${pointerEvents})`);
// Add visual debug indicator for 5 seconds
node.style.border = '3px solid red';
node.style.boxShadow = '0 0 10px red';
setTimeout(() => {
node.style.border = '';
node.style.boxShadow = '';
}, 5000);
});
console.log('=== HERO ANIMATION NODES ===');
heroAnimationNodes.forEach((node, index) => {
const label = node.querySelector('.node-label')?.textContent?.trim();
const classes = node.className;
const computedStyle = window.getComputedStyle(node);
const zIndex = computedStyle.zIndex;
const pointerEvents = computedStyle.pointerEvents;
console.log(`Hero Node ${index + 1}: "${label}" (z-index: ${zIndex}, pointer-events: ${pointerEvents})`);
// Add visual debug indicator for 5 seconds
node.style.border = '3px solid blue';
node.style.boxShadow = '0 0 10px blue';
setTimeout(() => {
node.style.border = '';
node.style.boxShadow = '';
}, 5000);
});
// Combine all data nodes
const allDataNodes = [...neuralNetworkNodes, ...heroAnimationNodes];
console.log(`Total data nodes found: ${allDataNodes.length}`);
// Verify no overlapping elements are blocking the neural network nodes
if (neuralNetworkNodes.length > 0) {
console.log('=== CHECKING FOR BLOCKING ELEMENTS ===');
neuralNetworkNodes.forEach((node, index) => {
const rect = node.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const elementAtPoint = document.elementFromPoint(centerX, centerY);
if (elementAtPoint !== node && !node.contains(elementAtPoint)) {
console.warn(`Node ${index + 1} may be blocked by:`, elementAtPoint);
} else {
console.log(`Node ${index + 1} is accessible at coordinates (${centerX}, ${centerY})`);
}
});
}
allDataNodes.forEach((node, index) => {
const nodeTextElement = node.querySelector('.node-text') || node.querySelector('.node-label');
const nodeText = nodeTextElement?.textContent?.trim();
console.log(`Setting up interactions for node ${index + 1}: "${nodeText}"`);
// Create and setup tooltip
this.setupTooltip(node);
// Add hover effects
this.setupHoverEffects(node);
// Add click effects
this.setupClickEffects(node);
});
console.log('Data node interactions initialization complete');
}
setupTooltip(node) {
// Check for both .node-text and .node-label structures
const nodeTextElement = node.querySelector('.node-text') || node.querySelector('.node-label');
const nodeText = nodeTextElement?.textContent?.trim();
if (!nodeText) return;
// Create tooltip element
const tooltip = document.createElement('div');
tooltip.className = 'data-node-tooltip';
tooltip.innerHTML = `
<div class="tooltip-header">${nodeText}</div>
<div class="tooltip-content">${this.getTooltipContent(nodeText)}</div>
`;
document.body.appendChild(tooltip);
this.tooltips.set(node, tooltip);
// Show tooltip on hover
node.addEventListener('mouseenter', (e) => {
this.showTooltip(node, e);
});
// Update tooltip position on mouse move
node.addEventListener('mousemove', (e) => {
this.updateTooltipPosition(node, e);
});
// Hide tooltip on leave
node.addEventListener('mouseleave', () => {
this.hideTooltip(node);
});
} getTooltipContent(nodeText) {
const tooltipMap = {
'ML': 'Machine Learning algorithms for pattern recognition, predictive analytics, and automated decision-making across industries.',
'Gen AI': 'Generative AI for content creation, code generation, and innovative solutions using advanced language models.',
'Analytics': 'Advanced analytics and business intelligence for data-driven insights and strategic decision making.',
'Automation': 'Intelligent process automation to streamline workflows, reduce costs, and improve operational efficiency.',
'Finance': 'AI-powered financial services including algorithmic trading, risk assessment, and fraud detection.',
'Healthcare': 'Medical AI for diagnosis, treatment optimization, drug discovery, and personalized patient care.',
'Retail': 'E-commerce optimization, inventory management, and personalized customer experiences.',
'Manufacturing': 'Smart manufacturing with predictive maintenance, quality control, and supply chain optimization.',
'Agentic AI': 'Advanced autonomous AI agents that can perform complex tasks and make decisions independently.',
'Marketing': 'AI-powered marketing automation, customer segmentation, and campaign optimization.',
'Media': 'Content creation, recommendation systems, and audience engagement optimization.',
'Travel': 'Smart travel planning, booking optimization, and personalized travel experiences.',
'Education': 'Personalized learning platforms, educational content generation, and student performance analytics.',
'Technology': 'Cutting-edge AI technology solutions and infrastructure for modern business needs.',
'Data Analytics': 'Advanced analytics and business intelligence for data-driven insights and strategic decision making.',
'Predictive': 'Predictive modeling and forecasting to anticipate trends, behaviors, and future outcomes.',
'Media & Entertainment': 'Content creation, recommendation systems, and audience engagement optimization.',
'Supply Chain': 'AI-driven supply chain optimization, demand forecasting, and inventory management solutions.',
'Risk Mgmt': 'Advanced risk assessment and management systems using AI to identify, analyze, and mitigate business risks.'
};
return tooltipMap[nodeText] || 'Advanced AI technology solutions for modern business challenges.';
}
showTooltip(node, event) {
const tooltip = this.tooltips.get(node);
if (!tooltip) return;
tooltip.style.opacity = '1';
tooltip.style.visibility = 'visible';
tooltip.style.pointerEvents = 'none';
this.updateTooltipPosition(node, event);
}
updateTooltipPosition(node, event) {
const tooltip = this.tooltips.get(node);
if (!tooltip) return;
const tooltipRect = tooltip.getBoundingClientRect();
const viewport = {
width: window.innerWidth,
height: window.innerHeight
};
let left = event.clientX + 15;
let top = event.clientY - tooltipRect.height - 10;
// Adjust if tooltip goes outside viewport
if (left + tooltipRect.width > viewport.width - 10) {
left = event.clientX - tooltipRect.width - 15;
}
if (top < 10) {
top = event.clientY + 15;
}
tooltip.style.left = `${left}px`;
tooltip.style.top = `${top}px`;
}
hideTooltip(node) {
const tooltip = this.tooltips.get(node);
if (!tooltip) return;
tooltip.style.opacity = '0';
tooltip.style.visibility = 'hidden';
}
setupHoverEffects(node) {
// Get all data nodes from both containers for the dimming effect
const allDataNodes = [
...document.querySelectorAll('.neural-network-container .data-node'),
...document.querySelectorAll('.hero-animation .data-node')
];
node.addEventListener('mouseenter', () => {
// Enhanced scaling and glow
node.style.transform = 'scale(1.15)';
node.style.filter = 'brightness(1.2) drop-shadow(0 0 15px rgba(59, 130, 246, 0.6))';
node.style.zIndex = '100';
// Enhanced icon effects
const nodeIcon = node.querySelector('.node-icon img');
if (nodeIcon) {
nodeIcon.style.transform = 'scale(1.1)';
nodeIcon.style.filter = 'brightness(1.3) saturate(1.2)';
}
// Enhanced text effects
const nodeText = node.querySelector('.node-text') || node.querySelector('.node-label');
if (nodeText) {
nodeText.style.color = '#60a5fa';
nodeText.style.textShadow = '0 0 8px rgba(96, 165, 250, 0.5)';
nodeText.style.transform = 'scale(1.05)';
}
// Enhanced core glow
const nodeCore = node.querySelector('.node-core');
if (nodeCore) {
nodeCore.style.boxShadow = '0 0 20px rgba(59, 130, 246, 0.8), inset 0 0 20px rgba(139, 92, 246, 0.3)';
nodeCore.style.background = 'radial-gradient(circle, rgba(59, 130, 246, 0.3), rgba(139, 92, 246, 0.2))';
}
// Dim other nodes for focus effect
allDataNodes.forEach(otherNode => {
if (otherNode !== node) {
otherNode.style.opacity = '0.3';
otherNode.style.filter = 'blur(1px)';
}
});
// Create ripple effect
this.createRippleEffect(node);
});
node.addEventListener('mouseleave', () => {
// Reset node
node.style.transform = '';
node.style.filter = '';
node.style.zIndex = '';
// Reset icon
const nodeIcon = node.querySelector('.node-icon img');
if (nodeIcon) {
nodeIcon.style.transform = '';
nodeIcon.style.filter = '';
}
// Reset text
const nodeText = node.querySelector('.node-text') || node.querySelector('.node-label');
if (nodeText) {
nodeText.style.color = '';
nodeText.style.textShadow = '';
nodeText.style.transform = '';
}
// Reset core
const nodeCore = node.querySelector('.node-core');
if (nodeCore) {
nodeCore.style.boxShadow = '';
nodeCore.style.background = '';
}
// Restore other nodes
allDataNodes.forEach(otherNode => {
otherNode.style.opacity = '';
otherNode.style.filter = '';
});
});
}
createRippleEffect(node) {
const ripple = document.createElement('div');
const rect = node.getBoundingClientRect();
const size = Math.max(rect.width, rect.height) * 2;
ripple.style.cssText = `
position: absolute;
border-radius: 50%;
background: radial-gradient(circle, rgba(59, 130, 246, 0.3), transparent 70%);
transform: scale(0);
animation: rippleEffect 0.8s ease-out;
pointer-events: none;
z-index: 1000;
`;
ripple.style.width = `${size}px`;
ripple.style.height = `${size}px`;
ripple.style.left = `${rect.left + rect.width/2 - size/2}px`;
ripple.style.top = `${rect.top + rect.height/2 - size/2}px`;
document.body.appendChild(ripple);
setTimeout(() => ripple.remove(), 800);
}
setupClickEffects(node) {
node.addEventListener('click', (e) => {
e.preventDefault();
// Create particle burst effect
this.createParticleBurst(node);
// Enhanced click feedback
node.style.transform = 'scale(0.95)';
setTimeout(() => {
node.style.transform = 'scale(1.15)';
}, 100);
});
}
createParticleBurst(node) {
const rect = node.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
for (let i = 0; i < 12; i++) {
const particle = document.createElement('div');
const angle = (i / 12) * Math.PI * 2;
const velocity = 50 + Math.random() * 30;
particle.style.cssText = `
position: fixed;
width: 4px;
height: 4px;
background: linear-gradient(45deg, #3b82f6, #8b5cf6);
border-radius: 50%;
pointer-events: none;
z-index: 1001;
left: ${centerX}px;
top: ${centerY}px;
`;
document.body.appendChild(particle);
// Animate particle
const endX = centerX + Math.cos(angle) * velocity;
const endY = centerY + Math.sin(angle) * velocity;
particle.animate([
{ transform: 'translate(0, 0) scale(1)', opacity: 1 },
{ transform: `translate(${endX - centerX}px, ${endY - centerY}px) scale(0)`, opacity: 0 }
], {
duration: 800,
easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)'
}).onfinish = () => particle.remove();
}
}
addStyles() {
if (document.getElementById('data-node-styles')) return;
const styles = document.createElement('style');
styles.id = 'data-node-styles';
styles.textContent = `
/* Data Node Tooltip Styles */
.data-node-tooltip {
position: fixed;
background: linear-gradient(135deg, rgba(15, 23, 42, 0.95), rgba(30, 41, 59, 0.95));
border: 1px solid rgba(59, 130, 246, 0.3);
border-radius: 12px;
padding: 12px 16px;
max-width: 280px;
font-size: 14px;
color: #e2e8f0;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.3), 0 10px 10px -5px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(10px);
z-index: 10000;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
pointer-events: none;
}
.tooltip-header {
font-weight: 600;
color: #60a5fa;
margin-bottom: 6px;
font-size: 15px;
}
.tooltip-content {
line-height: 1.4;
color: #cbd5e1;
}
/* Ripple Effect Animation */
@keyframes rippleEffect {
to {
transform: scale(1);
opacity: 0;
}
}
/* Enhanced Data Node Interactions */
.data-node {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
cursor: pointer;
}
.data-node:hover {
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Enhanced neural network container interactions */
.neural-network-container .data-node {
transform-origin: center;
}
.neural-network-container .data-node:hover {
animation-play-state: paused;
}
/* Enhanced hero animation data nodes */
.hero-animation .data-node {
transform-origin: center;
}
.hero-animation .data-node:hover {
animation-play-state: paused;
}
/* Neural Network Canvas Animation Styles */
@keyframes neuralRipple {
to {
transform: scale(2);
opacity: 0;
}
}
@keyframes neuralPulse {
0%, 100% {
transform: scale(1);
opacity: 0.7;
}
50% {
transform: scale(1.2);
opacity: 0.3;
}
}
@keyframes neuralTrailFade {
0% {
transform: scale(1);
opacity: 0.8;
}
100% {
transform: scale(0);
opacity: 0;
}
}
`;
document.head.appendChild(styles);
}
}
// Mouse Trail Effect for Neural Network
function createNeuralTrail(x, y) {
const trail = document.createElement('div');
trail.style.cssText = `
position: fixed;
left: ${x}px;
top: ${y}px;
width: 6px;
height: 6px;
background: radial-gradient(circle, rgba(59, 130, 246, 0.8), transparent);
border-radius: 50%;
pointer-events: none;
z-index: 1000;
animation: neuralTrailFade 1.5s ease-out forwards;
`;
document.body.appendChild(trail);
setTimeout(() => trail.remove(), 1500);
}
// Global mouse trail for hero section
document.addEventListener('mousemove', (e) => {
const heroSection = document.querySelector('#hero');
if (!heroSection) return;
const rect = heroSection.getBoundingClientRect();
if (e.clientY >= rect.top && e.clientY <= rect.bottom) {
if (Math.random() < 0.1) { // Reduced frequency
createNeuralTrail(e.clientX, e.clientY);
}
}
});
// Initialize everything when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
// Add a small delay to ensure all elements are fully rendered
setTimeout(() => {
console.log('Initializing unified neural network and data node interactions...');
// Debug: Check what data nodes exist
console.log('=== DEBUG: Checking data node structure ===');
const neuralNodes = document.querySelectorAll('.neural-network-container .data-node');
const heroNodes = document.querySelectorAll('.hero-animation .data-node');
const allNodes = document.querySelectorAll('.data-node');
console.log(`Total .data-node elements found: ${allNodes.length}`);
console.log(`Neural network container nodes: ${neuralNodes.length}`);
console.log(`Hero animation nodes: ${heroNodes.length}`);
// Log each node's details
allNodes.forEach((node, index) => {
const label = node.querySelector('.node-label')?.textContent?.trim() || 'No label';
const text = node.querySelector('.node-text')?.textContent?.trim() || 'No text';
const container = node.closest('.neural-network-container') ? 'neural-network' :
node.closest('.hero-animation') ? 'hero-animation' : 'other';
console.log(`Node ${index + 1}: "${label}" (text: "${text}") in ${container}`);
});
console.log('=== END DEBUG ===');
// Initialize neural network animation
const neuralAnimation = new NeuralNetworkAnimation();
// Initialize data node interactions
const dataNodeInteractions = new DataNodeInteractions();
// Handle resize for neural network
window.addEventListener('resize', () => {
neuralAnimation.setupCanvas();
neuralAnimation.createNodes();
});
// Cleanup on page unload
window.addEventListener('beforeunload', () => {
neuralAnimation.destroy();
});
console.log('Unified system initialized successfully');
}, 100); // Small delay to ensure DOM is fully rendered
});
// Immediate test function to verify script loading
console.log('🚀 Unified Neural Interactions script loaded!');
// Test function to manually check data nodes
window.testDataNodes = function() {
const allNodes = document.querySelectorAll('.data-node');
console.log(`Found ${allNodes.length} data nodes:`);
allNodes.forEach((node, i) => {
const label = node.querySelector('.node-label')?.textContent || 'No label';
console.log(`${i + 1}. ${label}`);
});
return allNodes;
};
// Export for potential use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = { NeuralNetworkAnimation, DataNodeInteractions };
}