mirror of https://github.com/mkrhere/pw2
1 changed files with 218 additions and 0 deletions
@ -0,0 +1,218 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|||
<title>Document</title> |
|||
</head> |
|||
<body> |
|||
<div id="container"> |
|||
<div id="rectangle"></div> |
|||
</div> |
|||
|
|||
<style> |
|||
#container { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 600px; |
|||
overflow: hidden; |
|||
background-color: #f0f0f0; |
|||
} |
|||
|
|||
#rectangle { |
|||
position: absolute; |
|||
width: 200px; |
|||
height: 120px; |
|||
background-color: #3498db; |
|||
border-radius: 8px; |
|||
cursor: grab; |
|||
user-select: none; |
|||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); |
|||
transform-origin: center; |
|||
transition: box-shadow 0.2s ease; |
|||
} |
|||
|
|||
#rectangle:active { |
|||
cursor: grabbing; |
|||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); |
|||
} |
|||
</style> |
|||
|
|||
<script> |
|||
document.addEventListener("DOMContentLoaded", function () { |
|||
const rectangle = document.getElementById("rectangle"); |
|||
const container = document.getElementById("container"); |
|||
|
|||
// Position and movement state |
|||
let isDragging = false; |
|||
let currentX = 50; |
|||
let currentY = 50; |
|||
let rotation = 0; |
|||
|
|||
// Drag state tracking |
|||
let dragPointX = 0; |
|||
let dragPointY = 0; |
|||
let prevMouseX = 0; |
|||
let prevMouseY = 0; |
|||
|
|||
// Physics constants |
|||
const friction = 0.95; // General friction (higher = less friction) |
|||
const rotationFactor = 0.1; // How much rotation is applied (lower = less rotation) |
|||
|
|||
// Momentum tracking |
|||
let momentumX = 0; |
|||
let momentumY = 0; |
|||
let angularMomentum = 0; |
|||
let momentumAnimationId = null; |
|||
|
|||
// Initialize position |
|||
setTransform(currentX, currentY, rotation); |
|||
|
|||
function setTransform(x, y, rot) { |
|||
currentX = x; |
|||
currentY = y; |
|||
rotation = rot; |
|||
rectangle.style.transform = `translate(${x}px, ${y}px) rotate(${rot}deg)`; |
|||
} |
|||
|
|||
function getRectCenter() { |
|||
const rect = rectangle.getBoundingClientRect(); |
|||
return { |
|||
x: rect.left + rect.width / 2, |
|||
y: rect.top + rect.height / 2, |
|||
}; |
|||
} |
|||
|
|||
// Start dragging |
|||
rectangle.addEventListener("mousedown", dragStart); |
|||
rectangle.addEventListener("touchstart", dragStart, { passive: false }); |
|||
|
|||
function dragStart(e) { |
|||
e.preventDefault(); |
|||
if (momentumAnimationId !== null) { |
|||
cancelAnimationFrame(momentumAnimationId); |
|||
momentumAnimationId = null; |
|||
} |
|||
|
|||
// Get event coordinates |
|||
const eventX = |
|||
e.type === "touchstart" ? e.touches[0].clientX : e.clientX; |
|||
const eventY = |
|||
e.type === "touchstart" ? e.touches[0].clientY : e.clientY; |
|||
|
|||
// Record where on the card we're dragging from (relative to its center) |
|||
const center = getRectCenter(); |
|||
dragPointX = eventX - center.x; |
|||
dragPointY = eventY - center.y; |
|||
|
|||
// Initialize previous mouse position for momentum calculations |
|||
prevMouseX = eventX; |
|||
prevMouseY = eventY; |
|||
|
|||
isDragging = true; |
|||
momentumX = 0; |
|||
momentumY = 0; |
|||
angularMomentum = 0; |
|||
} |
|||
|
|||
// Drag movement |
|||
document.addEventListener("mousemove", drag); |
|||
document.addEventListener("touchmove", drag, { passive: false }); |
|||
|
|||
function drag(e) { |
|||
if (!isDragging) return; |
|||
e.preventDefault(); |
|||
|
|||
// Get event coordinates |
|||
const eventX = |
|||
e.type === "touchmove" ? e.touches[0].clientX : e.clientX; |
|||
const eventY = |
|||
e.type === "touchmove" ? e.touches[0].clientY : e.clientY; |
|||
|
|||
// Calculate movement delta |
|||
const dx = eventX - prevMouseX; |
|||
const dy = eventY - prevMouseY; |
|||
|
|||
// Update position based on direct movement |
|||
const newX = currentX + dx; |
|||
const newY = currentY + dy; |
|||
|
|||
// Calculate rotation based on the movement direction and drag point |
|||
// The further from center, the more leverage for rotation |
|||
const dragDistance = Math.sqrt( |
|||
dragPointX * dragPointX + dragPointY * dragPointY, |
|||
); |
|||
|
|||
// Calculate the tangential component of movement |
|||
// We use the cross product to determine how much the movement is perpendicular to the radius |
|||
const tangentialForce = |
|||
(dx * dragPointY - dy * dragPointX) / (dragDistance || 1); |
|||
|
|||
// Apply rotation with distance-based scaling |
|||
// This mimics the lever effect - further from center = more rotation |
|||
const rotationDelta = |
|||
tangentialForce * rotationFactor * (dragDistance / 100 + 0.5); |
|||
const newRotation = rotation + rotationDelta; |
|||
|
|||
// Update momentum for after drag ends |
|||
momentumX = dx * 0.9; // Reduced to prevent excessive sliding |
|||
momentumY = dy * 0.9; |
|||
angularMomentum = rotationDelta * 0.9; |
|||
|
|||
// Apply the transforms |
|||
setTransform(newX, newY, newRotation); |
|||
|
|||
// Update previous mouse position |
|||
prevMouseX = eventX; |
|||
prevMouseY = eventY; |
|||
} |
|||
|
|||
// End dragging |
|||
document.addEventListener("mouseup", dragEnd); |
|||
document.addEventListener("touchend", dragEnd); |
|||
|
|||
function dragEnd() { |
|||
if (isDragging) { |
|||
isDragging = false; |
|||
applyMomentum(); |
|||
} |
|||
} |
|||
|
|||
// Apply momentum after release with friction |
|||
function applyMomentum() { |
|||
if ( |
|||
Math.abs(momentumX) < 0.1 && |
|||
Math.abs(momentumY) < 0.1 && |
|||
Math.abs(angularMomentum) < 0.01 |
|||
) { |
|||
momentumAnimationId = null; |
|||
return; // Stop if momentum is very small |
|||
} |
|||
|
|||
// Apply friction |
|||
momentumX *= friction; |
|||
momentumY *= friction; |
|||
angularMomentum *= friction; |
|||
|
|||
// Apply momentum |
|||
setTransform( |
|||
currentX + momentumX, |
|||
currentY + momentumY, |
|||
rotation + angularMomentum, |
|||
); |
|||
|
|||
// Continue applying momentum |
|||
momentumAnimationId = requestAnimationFrame(applyMomentum); |
|||
} |
|||
|
|||
// Handle edge cases |
|||
document.addEventListener("mouseleave", function () { |
|||
if (isDragging) { |
|||
isDragging = false; |
|||
applyMomentum(); |
|||
} |
|||
}); |
|||
}); |
|||
</script> |
|||
</body> |
|||
</html> |
Loading…
Reference in new issue