support multiple animationFrames

+ break out spiral draw logic
This commit is contained in:
Felix Roos 2024-03-15 09:49:00 +01:00
parent a8712fd8ce
commit 6dce9d5deb
3 changed files with 58 additions and 54 deletions

View file

@ -29,12 +29,13 @@ export const getDrawContext = (id = 'test-canvas', options) => {
return canvas.getContext(contextType); return canvas.getContext(contextType);
}; };
Pattern.prototype.draw = function (callback, { from, to, onQuery, ctx } = {}) { let animationFrames = {};
Pattern.prototype.draw = function (callback, { id = 'std', from, to, onQuery, ctx } = {}) {
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
return this; return this;
} }
if (window.strudelAnimation) { if (animationFrames[id]) {
cancelAnimationFrame(window.strudelAnimation); cancelAnimationFrame(animationFrames[id]);
} }
ctx = ctx || getDrawContext(); ctx = ctx || getDrawContext();
let cycle, let cycle,
@ -56,7 +57,7 @@ Pattern.prototype.draw = function (callback, { from, to, onQuery, ctx } = {}) {
} }
} }
callback(ctx, events, t, time); callback(ctx, events, t, time);
window.strudelAnimation = requestAnimationFrame(animate); animationFrames[id] = requestAnimationFrame(animate);
}; };
requestAnimationFrame(animate); requestAnimationFrame(animate);
return this; return this;
@ -64,18 +65,18 @@ Pattern.prototype.draw = function (callback, { from, to, onQuery, ctx } = {}) {
// this is a more generic helper to get a rendering callback for the currently active haps // this is a more generic helper to get a rendering callback for the currently active haps
// TODO: this misses events that are prolonged with clip or duration (would need state) // TODO: this misses events that are prolonged with clip or duration (would need state)
Pattern.prototype.onFrame = function (fn, offset = 0) { Pattern.prototype.onFrame = function (id, fn, offset = 0) {
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
return this; return this;
} }
if (window.strudelAnimation) { if (animationFrames[id]) {
cancelAnimationFrame(window.strudelAnimation); cancelAnimationFrame(animationFrames[id]);
} }
const animate = () => { const animate = () => {
const t = getTime() + offset; const t = getTime() + offset;
const haps = this.queryArc(t, t); const haps = this.queryArc(t, t);
fn(haps, t, this); fn(haps, t, this);
window.strudelAnimation = requestAnimationFrame(animate); animationFrames[id] = requestAnimationFrame(animate);
}; };
requestAnimationFrame(animate); requestAnimationFrame(animate);
return this; return this;
@ -84,9 +85,7 @@ Pattern.prototype.onFrame = function (fn, offset = 0) {
export const cleanupDraw = (clearScreen = true) => { export const cleanupDraw = (clearScreen = true) => {
const ctx = getDrawContext(); const ctx = getDrawContext();
clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.width); clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.width);
if (window.strudelAnimation) { Object.values(animationFrames).forEach((id) => cancelAnimationFrame(id));
cancelAnimationFrame(window.strudelAnimation);
}
if (window.strudelScheduler) { if (window.strudelScheduler) {
clearInterval(window.strudelScheduler); clearInterval(window.strudelScheduler);
} }

View file

@ -30,7 +30,7 @@ const getValue = (e) => {
}; };
Pattern.prototype.pianoroll = function (options = {}) { Pattern.prototype.pianoroll = function (options = {}) {
let { cycles = 4, playhead = 0.5, overscan = 1, hideNegative = false, ctx } = options; let { cycles = 4, playhead = 0.5, overscan = 1, hideNegative = false, ctx, id } = options;
let from = -cycles * playhead; let from = -cycles * playhead;
let to = cycles * (1 - playhead); let to = cycles * (1 - playhead);
@ -50,6 +50,7 @@ Pattern.prototype.pianoroll = function (options = {}) {
from: from - overscan, from: from - overscan,
to: to + overscan, to: to + overscan,
ctx, ctx,
id,
}, },
); );
return this; return this;

View file

@ -49,7 +49,7 @@ function spiralSegment(options) {
ctx.stroke(); ctx.stroke();
} }
Pattern.prototype.spiral = function (options = {}) { function drawSpiral(options) {
const { const {
stretch = 1, stretch = 1,
size = 80, size = 80,
@ -65,9 +65,12 @@ Pattern.prototype.spiral = function (options = {}) {
colorizeInactive = 0, colorizeInactive = 0,
fade = true, fade = true,
// logSpiral = true, // logSpiral = true,
ctx,
time,
haps,
drawTime,
} = options; } = options;
function spiral({ ctx, time, haps, drawTime }) {
const [w, h] = [ctx.canvas.width, ctx.canvas.height]; const [w, h] = [ctx.canvas.width, ctx.canvas.height];
ctx.clearRect(0, 0, w * 2, h * 2); ctx.clearRect(0, 0, w * 2, h * 2);
const [cx, cy] = [w / 2, h / 2]; const [cx, cy] = [w / 2, h / 2];
@ -112,7 +115,8 @@ Pattern.prototype.spiral = function (options = {}) {
...playhead, ...playhead,
rotate, rotate,
}); });
} }
return this.onPaint((ctx, time, haps, drawTime) => spiral({ ctx, time, haps, drawTime })); Pattern.prototype.spiral = function (options = {}) {
return this.onPaint((ctx, time, haps, drawTime) => drawSpiral({ ctx, time, haps, drawTime, ...options }));
}; };