plot = (f = (x) => Math.sin(x), options = {}) => {
let {
w = 400,
h = 400,
minX = -1,
maxX = 1,
minY = -1,
maxY = 1,
zoom = undefined,
play = true,
speed = 2
} = options
if(zoom) {
minX = minY = zoom[0]
maxX = maxY = zoom[1]
}
return p5(s => {
let mX, mY
s.setup = () => {
const canvas = s.createCanvas(w, h)
s.cursor(s.HAND)
mX = 0
mY = f(mX, s)
canvas.elt.addEventListener('click', e => {
play = !play
if(play) s.loop()
})
}
s.draw = () => {
let t = play ? (s.frameCount * speed / w) % 1.2 : 1.01
s.background(0)
s.noFill()
s.stroke(80)
s.strokeWeight(2)
const x0 = s.map(0, minX, maxX, 0, w)
s.line(x0, 0, x0, h)
const y0 = s.map(0, minY, maxY, h, 0)
s.line(0, y0, w, y0)
s.stroke(255, 0, 0)
s.strokeWeight(1)
let x = 0
let y = 0
s.beginShape()
for(x = 0; x < w * t; x ++) {
const X = s.map(x, 0, w, minX, maxX)
const Y = f(X, s)
y = s.map(Y, minY, maxY, h, 0)
s.vertex(x, y)
}
s.endShape()
s.noStroke()
s.fill('red')
s.circle(x, y, 5)
s.fill(255)
s.circle(s.map(mX, minX, maxX, 0, w), s.map(mY, minY, maxY, h, 0), 5)
s.noStroke()
s.fill(255)
s.textAlign(s.LEFT)
s.text(`X: [ ${(minX * 1000 | 0) / 1000}, ${(maxX * 1000 | 0) / 1000} ]`, 5, 15)
s.text(`Y: [ ${(minY * 1000 | 0) / 1000}, ${(maxY * 1000 | 0) / 1000} ]`, 5, 30)
s.textAlign(s.RIGHT)
s.text(`X: ${(mX * 1000 | 0) / 1000}`, s.width - 5, 15)
s.text(`Y: ${(mY * 1000 | 0) / 1000}`, s.width - 5, 30)
if(!play) s.noLoop()
}
s.mouseMoved = () => {
if(s.mouseX >= 0 && s.mouseX <= s.width && s.mouseY >= 0 && s.mouseY <= s.height) {
s.mouseX = s.constrain(s.mouseX, 0, w)
mX = s.map(s.mouseX, 0, w, minX, maxX)
mY = f(mX, s)
s.loop()
}
}
})
}