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