| <!DOCTYPE html> |
| <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() { |
| |
| ctx.fillStyle = '#333'; |
| ctx.fillRect(0, 0, canvas.width, canvas.height); |
| |
| |
| let x = canvas.width / 2; |
| let y = canvas.height / 2; |
| let totalAngle = 0; |
| |
| |
| for(let i = 0; i < arrows.length; i++) { |
| const arrow = arrows[i]; |
| arrow.angle += arrow.speed * 0.02; |
| totalAngle += arrow.angle; |
| |
| |
| 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(); |
| |
| |
| ctx.beginPath(); |
| ctx.arc(x, y, 5, 0, Math.PI * 2); |
| ctx.fillStyle = '#2ecc71'; |
| ctx.fill(); |
| |
| |
| x = endX; |
| y = endY; |
| |
| |
| if(i === arrows.length - 1) { |
| pathPoints.push({x, y}); |
| if(pathPoints.length > 200) pathPoints.shift(); |
| } |
| } |
| |
| |
| 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 = ''; |
| } |
| |
| |
| 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> |