mirror of https://github.com/mkrhere/pw2
				
				
			
				 2 changed files with 191 additions and 0 deletions
			
			
		@ -0,0 +1,176 @@ | 
				
			|||
<!DOCTYPE html> | 
				
			|||
<html> | 
				
			|||
	<head> | 
				
			|||
		<meta charset="utf-8" /> | 
				
			|||
		<meta | 
				
			|||
			name="viewport" | 
				
			|||
			content="width=device-width, initial-scale=1.0, user-scalable=no" | 
				
			|||
		/> | 
				
			|||
		<style> | 
				
			|||
			html, | 
				
			|||
			body { | 
				
			|||
				margin: 0; | 
				
			|||
				width: 100vw; | 
				
			|||
				height: 100vh; | 
				
			|||
				background: #111; | 
				
			|||
				overflow: hidden; | 
				
			|||
			} | 
				
			|||
			#card { | 
				
			|||
				width: 24rem; | 
				
			|||
				height: 16rem; | 
				
			|||
				background: linear-gradient(135deg, #ff9a9e, #fad0c4); | 
				
			|||
				border-radius: 20px; | 
				
			|||
				position: absolute; | 
				
			|||
				left: 0; | 
				
			|||
				top: 0; | 
				
			|||
				box-shadow: 0 30px 60px rgba(0, 0, 0, 0.3); | 
				
			|||
				transform-origin: center center; | 
				
			|||
				cursor: grab; | 
				
			|||
				/* touch-action: none; */ | 
				
			|||
			} | 
				
			|||
		</style> | 
				
			|||
	</head> | 
				
			|||
	<body> | 
				
			|||
		<div id="card"></div> | 
				
			|||
		<script> | 
				
			|||
			const card = document.getElementById("card"); | 
				
			|||
 | 
				
			|||
			function makeDraggable(card) { | 
				
			|||
				const rect = card.getBoundingClientRect(); | 
				
			|||
				let center = { | 
				
			|||
					x: rect.left + rect.width / 2, | 
				
			|||
					y: rect.top + rect.height / 2, | 
				
			|||
				}; | 
				
			|||
 | 
				
			|||
				let rotation = 0; | 
				
			|||
				let dragging = false; | 
				
			|||
				let offsetLocal = { x: 0, y: 0 }; | 
				
			|||
 | 
				
			|||
				let velocity = { x: 0, y: 0 }; | 
				
			|||
				let angularVelocity = 0; | 
				
			|||
 | 
				
			|||
				const dampingFactor = 0.7; | 
				
			|||
				const springFactor = 0.2; | 
				
			|||
				const maxAngularVelocity = 0.95; | 
				
			|||
				const momentumDampening = 0.98; | 
				
			|||
 | 
				
			|||
				let lastMousePosition = { x: 0, y: 0 }; | 
				
			|||
				let activePointerId = null; | 
				
			|||
 | 
				
			|||
				function clamp(value, min, max) { | 
				
			|||
					return Math.min(Math.max(value, min), max); | 
				
			|||
				} | 
				
			|||
 | 
				
			|||
				const down = e => { | 
				
			|||
					if (activePointerId !== null) return; | 
				
			|||
 | 
				
			|||
					dragging = true; | 
				
			|||
					activePointerId = e.pointerId; | 
				
			|||
 | 
				
			|||
					card.setPointerCapture(e.pointerId); | 
				
			|||
 | 
				
			|||
					velocity = { x: 0, y: 0 }; | 
				
			|||
 | 
				
			|||
					const dx = e.pageX - center.x; | 
				
			|||
					const dy = e.pageY - center.y; | 
				
			|||
 | 
				
			|||
					const cos = Math.cos(-rotation); | 
				
			|||
					const sin = Math.sin(-rotation); | 
				
			|||
 | 
				
			|||
					offsetLocal = { | 
				
			|||
						x: dx * cos - dy * sin, | 
				
			|||
						y: dx * sin + dy * cos, | 
				
			|||
					}; | 
				
			|||
 | 
				
			|||
					console.log(offsetLocal); | 
				
			|||
 | 
				
			|||
					lastMousePosition = { x: e.pageX, y: e.pageY }; | 
				
			|||
				}; | 
				
			|||
 | 
				
			|||
				const move = e => { | 
				
			|||
					if (!dragging || e.pointerId !== activePointerId) return; | 
				
			|||
 | 
				
			|||
					const mx = e.pageX; | 
				
			|||
					const my = e.pageY; | 
				
			|||
 | 
				
			|||
					velocity = { | 
				
			|||
						x: mx - lastMousePosition.x, | 
				
			|||
						y: my - lastMousePosition.y, | 
				
			|||
					}; | 
				
			|||
 | 
				
			|||
					lastMousePosition = { x: mx, y: my }; | 
				
			|||
 | 
				
			|||
					const px = offsetLocal.x; | 
				
			|||
					const py = offsetLocal.y; | 
				
			|||
 | 
				
			|||
					const targetRotation = | 
				
			|||
						Math.atan2(my - center.y, mx - center.x) - Math.atan2(py, px); | 
				
			|||
 | 
				
			|||
					angularVelocity += (targetRotation - rotation) * springFactor; | 
				
			|||
					angularVelocity *= dampingFactor; | 
				
			|||
					angularVelocity = clamp( | 
				
			|||
						angularVelocity, | 
				
			|||
						-maxAngularVelocity, | 
				
			|||
						maxAngularVelocity, | 
				
			|||
					); | 
				
			|||
 | 
				
			|||
					rotation += angularVelocity; | 
				
			|||
 | 
				
			|||
					const cos = Math.cos(rotation); | 
				
			|||
					const sin = Math.sin(rotation); | 
				
			|||
 | 
				
			|||
					const rx = px * cos - py * sin; | 
				
			|||
					const ry = px * sin + py * cos; | 
				
			|||
 | 
				
			|||
					center = { | 
				
			|||
						x: mx - rx, | 
				
			|||
						y: my - ry, | 
				
			|||
					}; | 
				
			|||
				}; | 
				
			|||
 | 
				
			|||
				const up = e => { | 
				
			|||
					if (e.pointerId === activePointerId) { | 
				
			|||
						dragging = false; | 
				
			|||
						activePointerId = null; | 
				
			|||
					} | 
				
			|||
				}; | 
				
			|||
 | 
				
			|||
				card.addEventListener("pointerdown", down, { passive: false }); | 
				
			|||
				window.addEventListener("pointermove", move, { passive: false }); | 
				
			|||
				window.addEventListener("pointerup", up, { passive: false }); | 
				
			|||
 | 
				
			|||
				function render() { | 
				
			|||
					if (!dragging) { | 
				
			|||
						if (Math.abs(angularVelocity) > 0.01) { | 
				
			|||
							rotation += angularVelocity; | 
				
			|||
							angularVelocity *= momentumDampening; | 
				
			|||
						} | 
				
			|||
 | 
				
			|||
						const speed = Math.sqrt( | 
				
			|||
							velocity.x * velocity.x + velocity.y * velocity.y, | 
				
			|||
						); | 
				
			|||
 | 
				
			|||
						if (speed > 0.01) { | 
				
			|||
							center.x += velocity.x * 0.4; | 
				
			|||
							center.y += velocity.y * 0.4; | 
				
			|||
							velocity.x *= momentumDampening; | 
				
			|||
							velocity.y *= momentumDampening; | 
				
			|||
						} | 
				
			|||
					} | 
				
			|||
 | 
				
			|||
					card.style.transform = ` | 
				
			|||
						translate(${center.x}px, ${center.y}px) | 
				
			|||
						translate(-50%, -50%) | 
				
			|||
						rotate(${rotation}rad) | 
				
			|||
					`; | 
				
			|||
 | 
				
			|||
					requestAnimationFrame(render); | 
				
			|||
				} | 
				
			|||
 | 
				
			|||
				render(); | 
				
			|||
			} | 
				
			|||
 | 
				
			|||
			makeDraggable(card); | 
				
			|||
		</script> | 
				
			|||
	</body> | 
				
			|||
</html> | 
				
			|||
@ -0,0 +1,15 @@ | 
				
			|||
import { defineConfig } from "vite"; | 
				
			|||
import { resolve } from "path"; | 
				
			|||
 | 
				
			|||
// https://vitejs.dev/config/
 | 
				
			|||
export default defineConfig({ | 
				
			|||
	server: { port: 10000, allowedHosts: ["dev.mkr.thefeathers.co"] }, | 
				
			|||
	plugins: [], | 
				
			|||
	build: { | 
				
			|||
		rollupOptions: { | 
				
			|||
			input: { | 
				
			|||
				main: resolve(__dirname, "index.html"), | 
				
			|||
			}, | 
				
			|||
		}, | 
				
			|||
	}, | 
				
			|||
}); | 
				
			|||
					Loading…
					
					
				
		Reference in new issue