You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.1 KiB
JavaScript

import { useEffect, useRef, useState } from 'preact/hooks'
import { simplifyCurve } from '../../lib/math/curves.js'
class KnotSimulation {
constructor(knotRef) {
this.knotRef = knotRef
this.ghostPath = null
}
onMouseDrag(x, y) {
if (!this.ghostPath) {
this.ghostPath = []
}
this.ghostPath.push([x, y])
}
onMouseUp() {
this.knotRef.current.points = simplifyCurve(this.ghostPath, 15)
this.ghostPath = null
}
update() {}
/** @param {CanvasRenderingContext2D} g */
render(g) {
const w = g.canvas.width
const h = g.canvas.height
const knot = this.knotRef.current
g.clearRect(0, 0, w, h)
g.lineWidth = 3
g.lineCap = 'round'
g.lineJoin = 'round'
g.strokeStyle = '#333'
if (this.ghostPath && this.ghostPath.length > 0) {
g.strokeStyle = '#888'
g.beginPath()
{
const [x0, y0] = this.ghostPath[0]
g.moveTo(x0, y0)
for (const [x, y] of this.ghostPath) {
g.lineTo(x, y)
}
}
g.stroke()
} else if (knot.points.length > 0) {
g.beginPath()
const [x0, y0] = knot.points[0]
g.moveTo(x0, y0)
for (const [x, y] of knot.points) {
g.lineTo(x, y)
}
g.stroke()
g.fillStyle = '#080'
for (const [x, y] of knot.points) {
g.beginPath()
g.ellipse(x, y, 3, 3, 0, 0, Math.PI * 2)
g.fill()
}
}
}
}
export const KnotLayer = ({ knotRef }) => {
const canvasRef = useRef(null)
const [knotSim] = useState(() => new KnotSimulation(knotRef))
useEffect(() => {
window.addEventListener('resize', () => {
// trigger repaint and get a new context
})
}, [])
useEffect(() => {
let simTimerHandle
if (canvasRef.current) {
canvasRef.current.width = canvasRef.current.offsetWidth
canvasRef.current.height = canvasRef.current.offsetHeight
const g = canvasRef.current.getContext('2d')
simTimerHandle = setInterval(() => {
knotSim.update()
requestAnimationFrame(() => knotSim.render(g))
console.log('Prova')
}, 1000 / 30)
}
return () => {
if (simTimerHandle) {
clearInterval(simTimerHandle)
}
}
}, [canvasRef.current])
return (
<canvas
ref={canvasRef}
onMouseDown={e => {
if (e.buttons === 1) {
knotSim.onMouseDrag(e.offsetX, e.offsetY)
}
}}
onMouseMove={e => {
if (e.buttons === 1) {
knotSim.onMouseDrag(e.offsetX, e.offsetY)
}
}}
onMouseUp={e => {
knotSim.onMouseUp()
}}
/>
)
}