Spaces:
Running
Running
| <html> | |
| <head> | |
| <title>Rotating Arrows System</title> | |
| <style> | |
| body { | |
| margin: 0; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| min-height: 100vh; | |
| background: #1a1a1a; | |
| font-family: Arial, sans-serif; | |
| color: white; | |
| } | |
| #container { | |
| position: relative; | |
| text-align: center; | |
| } | |
| .screen { | |
| display: none; | |
| margin-bottom: 20px; | |
| } | |
| .active { | |
| display: block; | |
| } | |
| .arrow-config { | |
| background: rgba(255, 255, 255, 0.1); | |
| padding: 15px; | |
| margin: 10px; | |
| border-radius: 8px; | |
| } | |
| button { | |
| padding: 10px 20px; | |
| margin: 5px; | |
| font-size: 16px; | |
| background: #4a90e2; | |
| border: none; | |
| border-radius: 5px; | |
| color: white; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| button:hover { | |
| background: #357abd; | |
| transform: translateY(-2px); | |
| } | |
| input { | |
| width: 60px; | |
| padding: 5px; | |
| margin: 5px; | |
| border: none; | |
| border-radius: 3px; | |
| background: rgba(255, 255, 255, 0.2); | |
| color: white; | |
| } | |
| input:focus { | |
| outline: none; | |
| background: rgba(255, 255, 255, 0.3); | |
| } | |
| canvas { | |
| background: #333; | |
| border-radius: 8px; | |
| margin-top: 20px; | |
| } | |
| #resetBtn { | |
| position: fixed; | |
| top: 20px; | |
| right: 20px; | |
| background: #e74c3c; | |
| } | |
| #resetBtn:hover { | |
| background: #c0392b; | |
| } | |
| .controls { | |
| margin-top: 20px; | |
| } | |
| h2 { | |
| color: #4a90e2; | |
| margin-bottom: 20px; | |
| } | |
| .arrow-config label { | |
| display: inline-block; | |
| width: 60px; | |
| text-align: right; | |
| margin-right: 10px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <button id="resetBtn" onclick="reset()" style="display: none;">Reset</button> | |
| <div id="container"> | |
| <div id="startScreen" class="screen active"> | |
| <h2>Select Number of Arrows</h2> | |
| <div> | |
| <button onclick="selectArrows(2)">2 Arrows</button> | |
| <button onclick="selectArrows(3)">3 Arrows</button> | |
| <button onclick="selectArrows(4)">4 Arrows</button> | |
| <button onclick="selectArrows(5)">5 Arrows</button> | |
| </div> | |
| </div> | |
| <div id="configScreen" class="screen"> | |
| <h2>Configure Arrows</h2> | |
| <div id="arrowConfigs"></div> | |
| <button onclick="startAnimation()">Start Animation</button> | |
| </div> | |
| <canvas id="canvas" width="800" height="600" style="display: none;"></canvas> | |
| </div> | |
| <script> | |
| let arrows = []; | |
| let animationId = null; | |
| let canvas, ctx; | |
| let pathPoints = []; | |
| class Arrow { | |
| constructor(length, speed) { | |
| this.length = length * 50; | |
| this.speed = speed; | |
| this.angle = 0; | |
| } | |
| } | |
| function selectArrows(num) { | |
| document.getElementById('startScreen').classList.remove('active'); | |
| document.getElementById('configScreen').classList.add('active'); | |
| document.getElementById('resetBtn').style.display = 'block'; | |
| const configsDiv = document.getElementById('arrowConfigs'); | |
| configsDiv.innerHTML = ''; | |
| for(let i = 0; i < num; i++) { | |
| const speed = (Math.random() * 4 + 1).toFixed(1); | |
| const length = (Math.random() * 4 + 1).toFixed(1); | |
| const config = document.createElement('div'); | |
| config.className = 'arrow-config'; | |
| config.innerHTML = ` | |
| <h3>Arrow ${i + 1}</h3> | |
| <div> | |
| <label>Speed:</label> | |
| <input type="number" min="0.1" max="5" step="0.1" value="${speed}" id="speed${i}"> | |
| </div> | |
| <div> | |
| <label>Length:</label> | |
| <input type="number" min="0.1" max="5" step="0.1" value="${length}" id="length${i}"> | |
| </div> | |
| `; | |
| configsDiv.appendChild(config); | |
| } | |
| } | |
| function startAnimation() { | |
| arrows = []; | |
| const inputs = document.querySelectorAll('.arrow-config input'); | |
| for(let i = 0; i < inputs.length/2; i++) { | |
| const speed = parseFloat(document.getElementById(`speed${i}`).value); | |
| const length = parseFloat(document.getElementById(`length${i}`).value); | |
| arrows.push(new Arrow(length, speed)); | |
| } | |
| document.getElementById('configScreen').classList.remove('active'); | |
| canvas = document.getElementById('canvas'); | |
| canvas.style.display = 'block'; | |
| ctx = canvas.getContext('2d'); | |
| pathPoints = []; | |
| if(animationId) cancelAnimationFrame(animationId); | |
| animate(); | |
| } | |
| function animate() { | |
| // Clear canvas | |
| ctx.fillStyle = '#333'; | |
| ctx.fillRect(0, 0, canvas.width, canvas.height); | |
| // Start from center | |
| let x = canvas.width / 2; | |
| let y = canvas.height / 2; | |
| let totalAngle = 0; | |
| // Draw arrows | |
| for(let i = 0; i < arrows.length; i++) { | |
| const arrow = arrows[i]; | |
| arrow.angle += arrow.speed * 0.02; | |
| totalAngle += arrow.angle; | |
| // Draw arrow line | |
| ctx.beginPath(); | |
| ctx.moveTo(x, y); | |
| const endX = x + Math.cos(totalAngle) * arrow.length; | |
| const endY = y + Math.sin(totalAngle) * arrow.length; | |
| ctx.lineTo(endX, endY); | |
| ctx.strokeStyle = '#4a90e2'; | |
| ctx.lineWidth = 3; | |
| ctx.stroke(); | |
| // Draw joint | |
| ctx.beginPath(); | |
| ctx.arc(x, y, 5, 0, Math.PI * 2); | |
| ctx.fillStyle = '#2ecc71'; | |
| ctx.fill(); | |
| // Update start point for next arrow | |
| x = endX; | |
| y = endY; | |
| // Store path point for last arrow | |
| if(i === arrows.length - 1) { | |
| pathPoints.push({x, y}); | |
| if(pathPoints.length > 200) pathPoints.shift(); | |
| } | |
| } | |
| // Draw path | |
| if(pathPoints.length > 1) { | |
| ctx.beginPath(); | |
| ctx.moveTo(pathPoints[0].x, pathPoints[0].y); | |
| for(let i = 1; i < pathPoints.length; i++) { | |
| const point = pathPoints[i]; | |
| ctx.lineTo(point.x, point.y); | |
| } | |
| ctx.strokeStyle = '#e74c3c'; | |
| ctx.lineWidth = 2; | |
| ctx.stroke(); | |
| } | |
| animationId = requestAnimationFrame(animate); | |
| } | |
| function reset() { | |
| if(animationId) { | |
| cancelAnimationFrame(animationId); | |
| animationId = null; | |
| } | |
| arrows = []; | |
| pathPoints = []; | |
| document.getElementById('startScreen').classList.add('active'); | |
| document.getElementById('configScreen').classList.remove('active'); | |
| document.getElementById('canvas').style.display = 'none'; | |
| document.getElementById('resetBtn').style.display = 'none'; | |
| const configsDiv = document.getElementById('arrowConfigs'); | |
| configsDiv.innerHTML = ''; | |
| } | |
| // Initialize | |
| window.onload = () => { | |
| canvas = document.getElementById('canvas'); | |
| ctx = canvas.getContext('2d'); | |
| }; | |
| </script> | |
| </body> | |
| </html><script async data-explicit-opt-in="true" data-cookie-opt-in="true" src="https://vercel.live/_next-live/feedback/feedback.js"></script> |