Draw ripples on mousemove as well

This commit is contained in:
arne 2024-01-27 09:47:37 +01:00
commit 398aa43338
9 changed files with 36 additions and 11 deletions

View file

View file

@ -4,6 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ripples | compost.party</title> <title>ripples | compost.party</title>
<link rel="stylesheet" href="/src/style.css" type="text/css" media="screen" />
</head> </head>
<body> <body>
<canvas id="canvas"></canvas> <canvas id="canvas"></canvas>

View file

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before After
Before After

View file

@ -1,20 +1,22 @@
import './style.css'
const canvas = document.querySelector<HTMLCanvasElement>('#canvas')! const canvas = document.querySelector<HTMLCanvasElement>('#canvas')!
const ctx = canvas.getContext('2d')! const ctx = canvas.getContext('2d')!
const MIN_RADIUS = 20 const MIN_RADIUS = 20
const MAX_RADIUS = 200 const MAX_RADIUS = 200
const MAX_AGE = 5000 // in milliseconds const MAX_AGE = 1000 // in milliseconds
type Point = [number, number]
type Particle = { type Particle = {
position: [number, number], position: Point
age: number age: number
maxRadius: number
} }
const createParticle = (x: number, y: number): Particle => ({ const createParticle = (position: [number, number], maxRadius: number): Particle => ({
position: [x, y], position,
maxRadius,
age: 0, age: 0,
}) })
@ -24,12 +26,35 @@ let state = {
type State = typeof state type State = typeof state
canvas.addEventListener('click', (e) => { canvas.addEventListener('mousedown', (e) => {
// TODO Normalize x and y coords // TODO Normalize x and y coords
const particle = createParticle(e.clientX, e.clientY) const particle = createParticle([e.clientX, e.clientY], MAX_RADIUS)
state.particles.push(particle) state.particles.push(particle)
}) })
function* minDist(dist: number) {
let prev: Point
while (true) {
yield (cur: Point) => {
if (prev == null || Math.sqrt(Math.pow(prev[0]-cur[0], 2) + Math.pow(prev[1]-cur[1], 2)) >= dist) {
prev = cur
return true
}
return false
}
}
}
const hasSpace = minDist(70)
canvas.addEventListener('mousemove', (e) => {
const shouldSpawn = hasSpace.next().value!
if (shouldSpawn([e.clientX, e.clientY])) {
const particle = createParticle([e.clientX, e.clientY], MAX_RADIUS / 3*2)
state.particles.push(particle)
}
})
const update = (state: State, deltaTime: number): State => ({ const update = (state: State, deltaTime: number): State => ({
particles: state.particles particles: state.particles
.map(p => ({ .map(p => ({
@ -44,12 +69,12 @@ const render = (state: State, ctx: CanvasRenderingContext2D) => {
for (const particle of state.particles) { for (const particle of state.particles) {
const progress = (particle.age / MAX_AGE) const progress = (particle.age / MAX_AGE)
const opacity = Math.min(1, (1-progress)*(1-progress)) const opacity = Math.min(1, Math.pow(1-progress, 3)) * (particle.maxRadius / MAX_RADIUS)
ctx.beginPath() ctx.beginPath()
ctx.strokeStyle = `rgba(40, 40, 40, ${opacity})` ctx.strokeStyle = `rgba(40, 40, 40, ${opacity})`
const [x, y] = particle.position const [x, y] = particle.position
const radius = (progress * (MAX_RADIUS - MIN_RADIUS)) + MIN_RADIUS const radius = (progress * (particle.maxRadius - MIN_RADIUS)) + MIN_RADIUS
ctx.ellipse(x, y, radius, radius, 0, 0, Math.PI * 2) ctx.ellipse(x, y, radius, radius, 0, 0, Math.PI * 2)
ctx.stroke() ctx.stroke()
} }

View file

@ -7,5 +7,4 @@ body {
} }
canvas { canvas {
} }