MediaWiki:Common.js: Difference between revisions
Appearance
SuperAdmin1 (talk | contribs) Fix 3D CEO cloud rendering - proper centering, Fibonacci sphere distribution, Wikipedia font, better visibility |
SuperAdmin1 (talk | contribs) Transform 3D cloud to horizontal ellipsoid with enhanced interactivity: scroll zoom, keyboard controls, depth perception, smooth animations |
||
| Line 13: | Line 13: | ||
}); | }); | ||
/* 3D CEO | /* 3D CEO Cloud - Horizontal Ellipsoid - Wikipedia Style */ | ||
$(document).ready(function() { | $(document).ready(function() { | ||
var placeholder = document.getElementById('ceocloud-placeholder'); | var placeholder = document.getElementById('ceocloud-placeholder'); | ||
| Line 46: | Line 46: | ||
cloud.style.position = 'relative'; | cloud.style.position = 'relative'; | ||
cloud.style.width = '100%'; | cloud.style.width = '100%'; | ||
cloud.style.height = ' | cloud.style.height = '500px'; | ||
cloud.style.overflow = 'hidden'; | cloud.style.overflow = 'hidden'; | ||
cloud.style.cursor = 'grab'; | |||
// Create inner sphere container | // Create inner sphere container | ||
| Line 57: | Line 58: | ||
sphere.style.height = '1px'; | sphere.style.height = '1px'; | ||
sphere.style.transformStyle = 'preserve-3d'; | sphere.style.transformStyle = 'preserve-3d'; | ||
sphere.style.transition = 'transform 0. | sphere.style.transition = 'transform 0.3s ease-out'; | ||
// Horizontal ellipsoid parameters - much wider than tall | |||
var radiusX = 380; // Width | |||
var radiusY = 120; // Height (much smaller for horizontal spread) | |||
var radiusZ = 280; // Depth | |||
var phi = Math.PI * (3 - Math.sqrt(5)); // Golden angle in radians | var phi = Math.PI * (3 - Math.sqrt(5)); // Golden angle in radians | ||
var ceoElements = []; | |||
tags.forEach(function(tag, i) { | tags.forEach(function(tag, i) { | ||
| Line 72: | Line 77: | ||
var z = Math.sin(theta) * radiusAtY; | var z = Math.sin(theta) * radiusAtY; | ||
// Scale to | // Scale to ellipsoid - WIDE horizontally | ||
var posX = x * | var posX = x * radiusX; | ||
var posY = y * | var posY = y * radiusY; | ||
var posZ = z * | var posZ = z * radiusZ; | ||
// Create link element | // Create link element | ||
| Line 90: | Line 95: | ||
link.style.fontFamily = '"Linux Libertine", Georgia, "Times New Roman", Times, serif'; | link.style.fontFamily = '"Linux Libertine", Georgia, "Times New Roman", Times, serif'; | ||
link.style.whiteSpace = 'nowrap'; | link.style.whiteSpace = 'nowrap'; | ||
link.style.transition = 'all 0.3s ease'; | link.style.transition = 'all 0.3s ease, transform 0.2s ease'; | ||
link.style.textShadow = '0 2px | link.style.textShadow = '0 2px 10px rgba(0,0,0,0.9), 0 0 30px rgba(0,0,0,0.6)'; | ||
link.style.cursor = 'pointer'; | link.style.cursor = 'pointer'; | ||
link.style.transformStyle = 'preserve-3d'; | link.style.transformStyle = 'preserve-3d'; | ||
link.style.transform = 'translate3d(' + posX + 'px, ' + posY + 'px, ' + posZ + 'px) translate(-50%, -50%)'; | link.style.transform = 'translate3d(' + posX + 'px, ' + posY + 'px, ' + posZ + 'px) translate(-50%, -50%)'; | ||
link.style.backfaceVisibility = 'hidden'; | link.style.backfaceVisibility = 'hidden'; | ||
link.style.userSelect = 'none'; | |||
// Store original position | // Store original position and data | ||
link.dataset.x = posX; | link.dataset.x = posX; | ||
link.dataset.y = posY; | link.dataset.y = posY; | ||
| Line 103: | Line 109: | ||
link.dataset.originalSize = tag.size; | link.dataset.originalSize = tag.size; | ||
// Hover effects | // Hover effects with depth perception | ||
link.addEventListener('mouseenter', function() { | link.addEventListener('mouseenter', function() { | ||
this.style.color = '#fbbf24'; | this.style.color = '#fbbf24'; | ||
this.style.fontWeight = '700'; | this.style.fontWeight = '700'; | ||
var scale = 1. | var scale = 1.4; | ||
this.style.fontSize = (parseFloat(this.dataset.originalSize) * scale) + 'px'; | this.style.fontSize = (parseFloat(this.dataset.originalSize) * scale) + 'px'; | ||
this.style.textShadow = '0 | this.style.textShadow = '0 3px 20px rgba(251, 191, 36, 1), 0 0 50px rgba(251, 191, 36, 0.8), 0 0 80px rgba(251, 191, 36, 0.4)'; | ||
this.style.zIndex = '1000'; | this.style.zIndex = '1000'; | ||
this.style.filter = 'brightness(1.3)'; | |||
}); | }); | ||
| Line 117: | Line 124: | ||
this.style.fontWeight = '400'; | this.style.fontWeight = '400'; | ||
this.style.fontSize = this.dataset.originalSize + 'px'; | this.style.fontSize = this.dataset.originalSize + 'px'; | ||
this.style.textShadow = '0 2px | this.style.textShadow = '0 2px 10px rgba(0,0,0,0.9), 0 0 30px rgba(0,0,0,0.6)'; | ||
this.style.zIndex = 'auto'; | this.style.zIndex = 'auto'; | ||
this.style.filter = 'brightness(1)'; | |||
}); | |||
// Click animation | |||
link.addEventListener('click', function(e) { | |||
this.style.transform = 'translate3d(' + posX + 'px, ' + posY + 'px, ' + (posZ + 100) + 'px) translate(-50%, -50%) scale(1.5)'; | |||
this.style.transition = 'all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)'; | |||
}); | |||
ceoElements.push({ | |||
element: link, | |||
x: posX, | |||
y: posY, | |||
z: posZ | |||
}); | }); | ||
| Line 128: | Line 149: | ||
placeholder.appendChild(cloud); | placeholder.appendChild(cloud); | ||
// | // Animation variables | ||
var angleX = | var angleX = 10; // Start with slight tilt | ||
var angleY = 0; | var angleY = 0; | ||
var autoRotate = true; | var autoRotate = true; | ||
var targetAngleX = | var targetAngleX = 10; | ||
var targetAngleY = 0; | var targetAngleY = 0; | ||
var rotationSpeed = 0.15; // Slower, smoother rotation | |||
var zoom = 1; | |||
var targetZoom = 1; | |||
// Update depth-based opacity and size | |||
function updateDepth() { | |||
var transform = sphere.style.transform; | |||
var matrix = new WebKitCSSMatrix(window.getComputedStyle(sphere).transform); | |||
ceoElements.forEach(function(ceo) { | |||
// Calculate Z position after rotation | |||
var x = parseFloat(ceo.x); | |||
var y = parseFloat(ceo.y); | |||
var z = parseFloat(ceo.z); | |||
// Simple rotation math for depth | |||
var rad = angleY * Math.PI / 180; | |||
var newZ = z * Math.cos(rad) - x * Math.sin(rad); | |||
// Depth-based effects | |||
var depthFactor = (newZ + radiusZ) / (radiusZ * 2); // 0 to 1 | |||
var opacity = 0.3 + (depthFactor * 0.7); // 0.3 to 1.0 | |||
var scale = 0.7 + (depthFactor * 0.3); // 0.7 to 1.0 | |||
ceo.element.style.opacity = opacity; | |||
ceo.element.style.filter = 'brightness(' + (0.6 + depthFactor * 0.4) + ')'; | |||
// Update z-index for proper layering | |||
ceo.element.style.zIndex = Math.round(depthFactor * 100); | |||
}); | |||
} | |||
function animate() { | function animate() { | ||
if (autoRotate) { | if (autoRotate) { | ||
targetAngleY += | targetAngleY += rotationSpeed; | ||
} | } | ||
// Smooth interpolation | // Smooth interpolation | ||
angleX += (targetAngleX - angleX) * 0. | angleX += (targetAngleX - angleX) * 0.1; | ||
angleY += (targetAngleY - angleY) * 0. | angleY += (targetAngleY - angleY) * 0.1; | ||
zoom += (targetZoom - zoom) * 0.1; | |||
sphere.style.transform = 'rotateX(' + angleX + 'deg) rotateY(' + angleY + 'deg)'; | sphere.style.transform = 'scale(' + zoom + ') rotateX(' + angleX + 'deg) rotateY(' + angleY + 'deg)'; | ||
updateDepth(); | |||
requestAnimationFrame(animate); | requestAnimationFrame(animate); | ||
} | } | ||
| Line 156: | Line 211: | ||
cloud.addEventListener('mousedown', function(e) { | cloud.addEventListener('mousedown', function(e) { | ||
isDragging = true; | if (e.target.tagName.toLowerCase() !== 'a') { | ||
isDragging = true; | |||
autoRotate = false; | |||
previousMouseX = e.clientX; | |||
previousMouseY = e.clientY; | |||
cloud.style.cursor = 'grabbing'; | |||
e.preventDefault(); | |||
} | |||
}); | }); | ||
| Line 169: | Line 227: | ||
targetAngleY += deltaX * 0.5; | targetAngleY += deltaX * 0.5; | ||
targetAngleX -= deltaY * 0. | targetAngleX -= deltaY * 0.3; | ||
// Limit vertical rotation | // Limit vertical rotation | ||
targetAngleX = Math.max(- | targetAngleX = Math.max(-40, Math.min(40, targetAngleX)); | ||
previousMouseX = e.clientX; | previousMouseX = e.clientX; | ||
| Line 182: | Line 240: | ||
if (isDragging) { | if (isDragging) { | ||
isDragging = false; | isDragging = false; | ||
cloud.style.cursor = 'grab'; | |||
setTimeout(function() { | setTimeout(function() { | ||
autoRotate = true; | autoRotate = true; | ||
}, 2000); // Resume auto-rotation after 2 seconds | }, 2000); // Resume auto-rotation after 2 seconds | ||
} | } | ||
}); | |||
// Mouse wheel zoom | |||
cloud.addEventListener('wheel', function(e) { | |||
e.preventDefault(); | |||
var delta = e.deltaY > 0 ? -0.1 : 0.1; | |||
targetZoom = Math.max(0.5, Math.min(1.5, targetZoom + delta)); | |||
autoRotate = false; | |||
clearTimeout(cloud.zoomTimeout); | |||
cloud.zoomTimeout = setTimeout(function() { | |||
autoRotate = true; | |||
}, 1500); | |||
}); | }); | ||
// Touch support for mobile | // Touch support for mobile | ||
var touchStartX = 0; | |||
var touchStartY = 0; | |||
cloud.addEventListener('touchstart', function(e) { | cloud.addEventListener('touchstart', function(e) { | ||
if (e.touches.length === 1) { | if (e.touches.length === 1) { | ||
isDragging = true; | isDragging = true; | ||
autoRotate = false; | autoRotate = false; | ||
touchStartX = e.touches[0].clientX; | |||
touchStartY = e.touches[0].clientY; | |||
previousMouseX = touchStartX; | |||
previousMouseY = touchStartY; | |||
e.preventDefault(); | e.preventDefault(); | ||
} | } | ||
| Line 205: | Line 282: | ||
targetAngleY += deltaX * 0.5; | targetAngleY += deltaX * 0.5; | ||
targetAngleX -= deltaY * 0. | targetAngleX -= deltaY * 0.3; | ||
targetAngleX = Math.max(- | targetAngleX = Math.max(-40, Math.min(40, targetAngleX)); | ||
previousMouseX = e.touches[0].clientX; | previousMouseX = e.touches[0].clientX; | ||
| Line 222: | Line 299: | ||
}); | }); | ||
console.log('CEO Cloud: Successfully initialized'); | // Keyboard controls | ||
document.addEventListener('keydown', function(e) { | |||
if (placeholder.contains(document.activeElement) || document.activeElement === document.body) { | |||
switch(e.key) { | |||
case 'ArrowLeft': | |||
targetAngleY -= 10; | |||
autoRotate = false; | |||
e.preventDefault(); | |||
break; | |||
case 'ArrowRight': | |||
targetAngleY += 10; | |||
autoRotate = false; | |||
e.preventDefault(); | |||
break; | |||
case 'ArrowUp': | |||
targetAngleX = Math.max(-40, targetAngleX - 10); | |||
autoRotate = false; | |||
e.preventDefault(); | |||
break; | |||
case 'ArrowDown': | |||
targetAngleX = Math.min(40, targetAngleX + 10); | |||
autoRotate = false; | |||
e.preventDefault(); | |||
break; | |||
case '+': | |||
case '=': | |||
targetZoom = Math.min(1.5, targetZoom + 0.1); | |||
autoRotate = false; | |||
e.preventDefault(); | |||
break; | |||
case '-': | |||
case '_': | |||
targetZoom = Math.max(0.5, targetZoom - 0.1); | |||
autoRotate = false; | |||
e.preventDefault(); | |||
break; | |||
case ' ': | |||
autoRotate = !autoRotate; | |||
e.preventDefault(); | |||
break; | |||
} | |||
} | |||
}); | |||
// Double-click to focus on CEO | |||
sphere.addEventListener('dblclick', function(e) { | |||
if (e.target.tagName.toLowerCase() === 'a') { | |||
e.preventDefault(); | |||
targetZoom = 1.3; | |||
autoRotate = false; | |||
setTimeout(function() { | |||
window.location.href = e.target.href; | |||
}, 300); | |||
} | |||
}); | |||
// Add control hints | |||
var hints = document.createElement('div'); | |||
hints.style.position = 'absolute'; | |||
hints.style.bottom = '10px'; | |||
hints.style.left = '50%'; | |||
hints.style.transform = 'translateX(-50%)'; | |||
hints.style.color = 'rgba(255,255,255,0.6)'; | |||
hints.style.fontSize = '12px'; | |||
hints.style.textAlign = 'center'; | |||
hints.style.pointerEvents = 'none'; | |||
hints.style.fontFamily = 'sans-serif'; | |||
hints.innerHTML = '🖱️ Drag to rotate • 🔍 Scroll to zoom • ⌨️ Arrow keys to navigate • Space to pause'; | |||
cloud.appendChild(hints); | |||
console.log('CEO Cloud: Successfully initialized with horizontal ellipsoid'); | |||
}); | }); | ||
Revision as of 05:23, 22 October 2025
/* Common.js - Site-wide JavaScript */
/* Add copyright footer at the very bottom of page - single occurrence only */
$(document).ready(function() {
// Remove any existing copyright footers first to prevent duplicates
$('#footer-info-copyright, .ceo-copyright-footer').remove();
// Create the copyright footer
var copyright = '<div class="ceo-copyright-footer" id="footer-info-copyright" style="text-align: center; padding: 20px; background: #f8f9fa; border-top: 1px solid #ddd; margin-top: 40px; font-size: 0.85em; line-height: 1.6;">Text is available under the <a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="nofollow">Creative Commons Attribution-ShareAlike 4.0 License</a>; additional terms may apply. By using this site, you agree to the <a href="/wiki/CEO.wiki:Terms_of_Use">Terms of Use</a>, <a href="/wiki/CEO.wiki:Privacy_Policy">Privacy Policy</a>, and all <a href="/wiki/CEO.wiki:General_disclaimer">disclaimers</a>. CEO.wiki is operated as an independent collaborative encyclopedia project and is not affiliated with Wikipedia or the Wikimedia Foundation. See our <a href="/wiki/CEO.wiki:Takedown_Request_Policy">Takedown Request Policy</a> for content concerns.</div>';
// Append to the very bottom of the body
$('body').append(copyright);
});
/* 3D CEO Cloud - Horizontal Ellipsoid - Wikipedia Style */
$(document).ready(function() {
var placeholder = document.getElementById('ceocloud-placeholder');
if (!placeholder) {
console.log('CEO Cloud: placeholder not found');
return;
}
// Get CEO data from the parser function
var ceoDataEl = document.getElementById('ceo-data');
if (!ceoDataEl) {
console.log('CEO Cloud: ceo-data element not found');
return;
}
var ceoDataJson = ceoDataEl.getAttribute('data-ceos');
if (!ceoDataJson) {
console.log('CEO Cloud: data-ceos attribute empty');
return;
}
var tags = JSON.parse(ceoDataJson);
if (!tags || tags.length === 0) {
console.log('CEO Cloud: no tags found');
return;
}
console.log('CEO Cloud: Initializing with ' + tags.length + ' CEOs');
// Create cloud container with proper centering
var cloud = document.createElement('div');
cloud.style.position = 'relative';
cloud.style.width = '100%';
cloud.style.height = '500px';
cloud.style.overflow = 'hidden';
cloud.style.cursor = 'grab';
// Create inner sphere container
var sphere = document.createElement('div');
sphere.style.position = 'absolute';
sphere.style.left = '50%';
sphere.style.top = '50%';
sphere.style.width = '1px';
sphere.style.height = '1px';
sphere.style.transformStyle = 'preserve-3d';
sphere.style.transition = 'transform 0.3s ease-out';
// Horizontal ellipsoid parameters - much wider than tall
var radiusX = 380; // Width
var radiusY = 120; // Height (much smaller for horizontal spread)
var radiusZ = 280; // Depth
var phi = Math.PI * (3 - Math.sqrt(5)); // Golden angle in radians
var ceoElements = [];
tags.forEach(function(tag, i) {
// Fibonacci sphere distribution
var y = 1 - (i / (tags.length - 1)) * 2; // y goes from 1 to -1
var radiusAtY = Math.sqrt(1 - y * y); // radius at y
var theta = phi * i; // golden angle increment
var x = Math.cos(theta) * radiusAtY;
var z = Math.sin(theta) * radiusAtY;
// Scale to ellipsoid - WIDE horizontally
var posX = x * radiusX;
var posY = y * radiusY;
var posZ = z * radiusZ;
// Create link element
var link = document.createElement('a');
link.href = tag.url;
link.textContent = tag.text;
link.style.position = 'absolute';
link.style.left = '0';
link.style.top = '0';
link.style.color = '#ffffff';
link.style.textDecoration = 'none';
link.style.fontSize = tag.size + 'px';
link.style.fontWeight = '400';
link.style.fontFamily = '"Linux Libertine", Georgia, "Times New Roman", Times, serif';
link.style.whiteSpace = 'nowrap';
link.style.transition = 'all 0.3s ease, transform 0.2s ease';
link.style.textShadow = '0 2px 10px rgba(0,0,0,0.9), 0 0 30px rgba(0,0,0,0.6)';
link.style.cursor = 'pointer';
link.style.transformStyle = 'preserve-3d';
link.style.transform = 'translate3d(' + posX + 'px, ' + posY + 'px, ' + posZ + 'px) translate(-50%, -50%)';
link.style.backfaceVisibility = 'hidden';
link.style.userSelect = 'none';
// Store original position and data
link.dataset.x = posX;
link.dataset.y = posY;
link.dataset.z = posZ;
link.dataset.originalSize = tag.size;
// Hover effects with depth perception
link.addEventListener('mouseenter', function() {
this.style.color = '#fbbf24';
this.style.fontWeight = '700';
var scale = 1.4;
this.style.fontSize = (parseFloat(this.dataset.originalSize) * scale) + 'px';
this.style.textShadow = '0 3px 20px rgba(251, 191, 36, 1), 0 0 50px rgba(251, 191, 36, 0.8), 0 0 80px rgba(251, 191, 36, 0.4)';
this.style.zIndex = '1000';
this.style.filter = 'brightness(1.3)';
});
link.addEventListener('mouseleave', function() {
this.style.color = '#ffffff';
this.style.fontWeight = '400';
this.style.fontSize = this.dataset.originalSize + 'px';
this.style.textShadow = '0 2px 10px rgba(0,0,0,0.9), 0 0 30px rgba(0,0,0,0.6)';
this.style.zIndex = 'auto';
this.style.filter = 'brightness(1)';
});
// Click animation
link.addEventListener('click', function(e) {
this.style.transform = 'translate3d(' + posX + 'px, ' + posY + 'px, ' + (posZ + 100) + 'px) translate(-50%, -50%) scale(1.5)';
this.style.transition = 'all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
ceoElements.push({
element: link,
x: posX,
y: posY,
z: posZ
});
sphere.appendChild(link);
});
cloud.appendChild(sphere);
placeholder.innerHTML = ''; // Clear placeholder
placeholder.appendChild(cloud);
// Animation variables
var angleX = 10; // Start with slight tilt
var angleY = 0;
var autoRotate = true;
var targetAngleX = 10;
var targetAngleY = 0;
var rotationSpeed = 0.15; // Slower, smoother rotation
var zoom = 1;
var targetZoom = 1;
// Update depth-based opacity and size
function updateDepth() {
var transform = sphere.style.transform;
var matrix = new WebKitCSSMatrix(window.getComputedStyle(sphere).transform);
ceoElements.forEach(function(ceo) {
// Calculate Z position after rotation
var x = parseFloat(ceo.x);
var y = parseFloat(ceo.y);
var z = parseFloat(ceo.z);
// Simple rotation math for depth
var rad = angleY * Math.PI / 180;
var newZ = z * Math.cos(rad) - x * Math.sin(rad);
// Depth-based effects
var depthFactor = (newZ + radiusZ) / (radiusZ * 2); // 0 to 1
var opacity = 0.3 + (depthFactor * 0.7); // 0.3 to 1.0
var scale = 0.7 + (depthFactor * 0.3); // 0.7 to 1.0
ceo.element.style.opacity = opacity;
ceo.element.style.filter = 'brightness(' + (0.6 + depthFactor * 0.4) + ')';
// Update z-index for proper layering
ceo.element.style.zIndex = Math.round(depthFactor * 100);
});
}
function animate() {
if (autoRotate) {
targetAngleY += rotationSpeed;
}
// Smooth interpolation
angleX += (targetAngleX - angleX) * 0.1;
angleY += (targetAngleY - angleY) * 0.1;
zoom += (targetZoom - zoom) * 0.1;
sphere.style.transform = 'scale(' + zoom + ') rotateX(' + angleX + 'deg) rotateY(' + angleY + 'deg)';
updateDepth();
requestAnimationFrame(animate);
}
animate();
// Interactive controls
var isDragging = false;
var previousMouseX = 0;
var previousMouseY = 0;
cloud.addEventListener('mousedown', function(e) {
if (e.target.tagName.toLowerCase() !== 'a') {
isDragging = true;
autoRotate = false;
previousMouseX = e.clientX;
previousMouseY = e.clientY;
cloud.style.cursor = 'grabbing';
e.preventDefault();
}
});
document.addEventListener('mousemove', function(e) {
if (isDragging) {
var deltaX = e.clientX - previousMouseX;
var deltaY = e.clientY - previousMouseY;
targetAngleY += deltaX * 0.5;
targetAngleX -= deltaY * 0.3;
// Limit vertical rotation
targetAngleX = Math.max(-40, Math.min(40, targetAngleX));
previousMouseX = e.clientX;
previousMouseY = e.clientY;
}
});
document.addEventListener('mouseup', function() {
if (isDragging) {
isDragging = false;
cloud.style.cursor = 'grab';
setTimeout(function() {
autoRotate = true;
}, 2000); // Resume auto-rotation after 2 seconds
}
});
// Mouse wheel zoom
cloud.addEventListener('wheel', function(e) {
e.preventDefault();
var delta = e.deltaY > 0 ? -0.1 : 0.1;
targetZoom = Math.max(0.5, Math.min(1.5, targetZoom + delta));
autoRotate = false;
clearTimeout(cloud.zoomTimeout);
cloud.zoomTimeout = setTimeout(function() {
autoRotate = true;
}, 1500);
});
// Touch support for mobile
var touchStartX = 0;
var touchStartY = 0;
cloud.addEventListener('touchstart', function(e) {
if (e.touches.length === 1) {
isDragging = true;
autoRotate = false;
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
previousMouseX = touchStartX;
previousMouseY = touchStartY;
e.preventDefault();
}
});
document.addEventListener('touchmove', function(e) {
if (isDragging && e.touches.length === 1) {
var deltaX = e.touches[0].clientX - previousMouseX;
var deltaY = e.touches[0].clientY - previousMouseY;
targetAngleY += deltaX * 0.5;
targetAngleX -= deltaY * 0.3;
targetAngleX = Math.max(-40, Math.min(40, targetAngleX));
previousMouseX = e.touches[0].clientX;
previousMouseY = e.touches[0].clientY;
}
});
document.addEventListener('touchend', function() {
if (isDragging) {
isDragging = false;
setTimeout(function() {
autoRotate = true;
}, 2000);
}
});
// Keyboard controls
document.addEventListener('keydown', function(e) {
if (placeholder.contains(document.activeElement) || document.activeElement === document.body) {
switch(e.key) {
case 'ArrowLeft':
targetAngleY -= 10;
autoRotate = false;
e.preventDefault();
break;
case 'ArrowRight':
targetAngleY += 10;
autoRotate = false;
e.preventDefault();
break;
case 'ArrowUp':
targetAngleX = Math.max(-40, targetAngleX - 10);
autoRotate = false;
e.preventDefault();
break;
case 'ArrowDown':
targetAngleX = Math.min(40, targetAngleX + 10);
autoRotate = false;
e.preventDefault();
break;
case '+':
case '=':
targetZoom = Math.min(1.5, targetZoom + 0.1);
autoRotate = false;
e.preventDefault();
break;
case '-':
case '_':
targetZoom = Math.max(0.5, targetZoom - 0.1);
autoRotate = false;
e.preventDefault();
break;
case ' ':
autoRotate = !autoRotate;
e.preventDefault();
break;
}
}
});
// Double-click to focus on CEO
sphere.addEventListener('dblclick', function(e) {
if (e.target.tagName.toLowerCase() === 'a') {
e.preventDefault();
targetZoom = 1.3;
autoRotate = false;
setTimeout(function() {
window.location.href = e.target.href;
}, 300);
}
});
// Add control hints
var hints = document.createElement('div');
hints.style.position = 'absolute';
hints.style.bottom = '10px';
hints.style.left = '50%';
hints.style.transform = 'translateX(-50%)';
hints.style.color = 'rgba(255,255,255,0.6)';
hints.style.fontSize = '12px';
hints.style.textAlign = 'center';
hints.style.pointerEvents = 'none';
hints.style.fontFamily = 'sans-serif';
hints.innerHTML = '🖱️ Drag to rotate • 🔍 Scroll to zoom • ⌨️ Arrow keys to navigate • Space to pause';
cloud.appendChild(hints);
console.log('CEO Cloud: Successfully initialized with horizontal ellipsoid');
});