| | <!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> |