danieldabush/namesphere-explorer
0
1// Sample names data2const names = [3 "Alex", "Jordan", "Taylor", "Morgan", "Casey", 4 "Riley", "Jamie", "Quinn", "Avery", "Peyton",5 "Skyler", "Dakota", "Emerson", "Finley", "Sawyer",6 "Rowan", "Elliot", "Rylan", "Hayden", "Reese",7 "Brooklyn", "Zion", "Phoenix", "Harper", "Sage",8 "Jules", "River", "Dallas", "Aspen", "Marley",9 "Remington", "Justice", "Arden", "Shiloh", "Tatum"10];11// Clear existing names and reset state12function clearNameSphere() {13 const container = document.getElementById('nameSphereContainer');14 container.innerHTML = '';15 translateX = 0;16 translateY = 0;17 scale = 1;18 rotationX = 0;19 rotationY = 0;20 if (animationId) {21 cancelAnimationFrame(animationId);22 }23}24 25document.addEventListener('DOMContentLoaded', () => {26const container = document.getElementById('nameSphereContainer');27 const zoomInBtn = document.getElementById('zoomIn');28 const zoomOutBtn = document.getElementById('zoomOut');29 const randomizeBtn = document.getElementById('randomize');30 let scale = 1;31 let isDragging = false;32 let startX, startY, translateX = 0, translateY = 0;33 let rotationX = 0;34 let rotationY = 0;35 let autoRotate = true;36 let rotationSpeedX = 0.001;37 let rotationSpeedY = 0.002;38 let animationId;39 // Animation loop for smooth rotation40 function animate() {41 if (autoRotate) {42 rotationX += rotationSpeedX;43 rotationY += rotationSpeedY;44 updatePositions();45 }46 animationId = requestAnimationFrame(animate);47 }48 // Initialize the name sphere49 function initNameSphere() {50 // Clear existing state51 clearNameSphere();52// Clear previous names53 container.innerHTML = '';54 55 // Create a sphere of names56 const numNames = 50;57 const radius = Math.min(window.innerWidth, window.innerHeight) * 0.3;58 59 for (let i = 0; i < numNames; i++) {60 // Random spherical coordinates61 const theta = (i / numNames) * Math.PI * 2;62 const phi = Math.acos(2 * (i / numNames) - 1);63// Convert to cartesian coordinates64 const x = radius * Math.sin(phi) * Math.cos(theta);65 const y = radius * Math.sin(phi) * Math.sin(theta);66 const z = radius * Math.cos(phi);67 68 // Create name element69 const nameElement = document.createElement('div');70 nameElement.className = 'name-tag';71 nameElement.textContent = names[Math.floor(Math.random() * names.length)];72 73 // Position the name in 3D space74 nameElement.style.transform = `translate3d(${x + translateX}px, ${y + translateY}px, ${z}px)`;75 76 // Add hover effect77 nameElement.addEventListener('mouseover', () => {78 nameElement.style.transform = `translate3d(${x + translateX}px, ${y + translateY}px, ${z}px) scale(2)`;79 nameElement.style.opacity = '1';80 });81 82 nameElement.addEventListener('mouseout', () => {83 nameElement.style.transform = `translate3d(${x + translateX}px, ${y + translateY}px, ${z}px)`;84 nameElement.style.opacity = '0.7';85 });86 87 container.appendChild(nameElement);88 }89 }90 91 // Handle drag to move the sphere92 container.addEventListener('mousedown', (e) => {93 isDragging = true;94 startX = e.clientX - translateX;95 startY = e.clientY - translateY;96 container.style.cursor = 'grabbing';97 });98 99 document.addEventListener('mousemove', (e) => {100 if (!isDragging) return;101 translateX = e.clientX - startX;102 translateY = e.clientY - startY;103 updatePositions();104 });105 106 document.addEventListener('mouseup', () => {107 isDragging = false;108 container.style.cursor = 'grab';109 });110 111 // Handle touch events for mobile112 container.addEventListener('touchstart', (e) => {113 isDragging = true;114 startX = e.touches[0].clientX - translateX;115 startY = e.touches[0].clientY - translateY;116 });117 118 document.addEventListener('touchmove', (e) => {119 if (!isDragging) return;120 e.preventDefault();121 translateX = e.touches[0].clientX - startX;122 translateY = e.touches[0].clientY - startY;123 updatePositions();124 });125 126 document.addEventListener('touchend', () => {127 isDragging = false;128 });129 130 // Update all name positions when dragged or zoomed131 function updatePositions() {132 const nameTags = document.querySelectorAll('.name-tag');133 const radius = Math.min(window.innerWidth, window.innerHeight) * 0.3 * scale;134 135 nameTags.forEach((tag, i) => {136 // Get original spherical coordinates from index137 // Calculate rotated coordinates138 const cosX = Math.cos(rotationX);139 const sinX = Math.sin(rotationX);140 const cosY = Math.cos(rotationY);141 const sinY = Math.sin(rotationY);142 143 // Original coordinates144 const theta = (i / nameTags.length) * Math.PI * 2;145 const phi = Math.acos(2 * (i / nameTags.length) - 1);146 147 let x = radius * Math.sin(phi) * Math.cos(theta);148 let y = radius * Math.sin(phi) * Math.sin(theta);149 let z = radius * Math.cos(phi);150 151 // Apply rotation around Y axis152 const x1 = x * cosY - z * sinY;153 const z1 = x * sinY + z * cosY;154 155 // Apply rotation around X axis156 const y1 = y * cosX - z1 * sinX;157 const z2 = y * sinX + z1 * cosX;158 159 x = x1;160 y = y1;161 z = z2;162// Check if we're hovering to maintain zoom163 const isHovered = tag.style.opacity === '1';164 const currentScale = isHovered ? 2 : 1;165 166 tag.style.transform = `translate3d(${x + translateX}px, ${y + translateY}px, ${z}px) scale(${currentScale})`;167 });168 }169 170 // Zoom controls171 zoomInBtn.addEventListener('click', () => {172 scale *= 1.2;173 updatePositions();174 });175 176 zoomOutBtn.addEventListener('click', () => {177 scale *= 0.8;178 updatePositions();179 });180 randomizeBtn.addEventListener('click', () => {181 clearNameSphere();182 initNameSphere();183 });184// Initialize and handle window resize185 initNameSphere();186 animate();187 window.addEventListener('resize', initNameSphere);188 189 // Pause auto-rotation when dragging190 container.addEventListener('mousedown', () => {191 autoRotate = false;192 });193 194 document.addEventListener('mouseup', () => {195 autoRotate = true;196 });197 198 container.addEventListener('touchstart', () => {199 autoRotate = false;200 });201 202 document.addEventListener('touchend', () => {203 autoRotate = true;204 });205});