mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-24 03:58:53 +00:00
support multiple animationFrames
+ break out spiral draw logic
This commit is contained in:
parent
a8712fd8ce
commit
6dce9d5deb
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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,54 +65,58 @@ 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];
|
const settings = {
|
||||||
const settings = {
|
margin: size / stretch,
|
||||||
margin: size / stretch,
|
cx,
|
||||||
cx,
|
cy,
|
||||||
cy,
|
stretch,
|
||||||
stretch,
|
cap,
|
||||||
cap,
|
thickness,
|
||||||
thickness,
|
};
|
||||||
};
|
|
||||||
|
|
||||||
const playhead = {
|
const playhead = {
|
||||||
...settings,
|
...settings,
|
||||||
thickness: playheadThickness,
|
thickness: playheadThickness,
|
||||||
from: inset - playheadLength,
|
from: inset - playheadLength,
|
||||||
to: inset,
|
to: inset,
|
||||||
color: playheadColor,
|
color: playheadColor,
|
||||||
};
|
};
|
||||||
|
|
||||||
const [min] = drawTime;
|
const [min] = drawTime;
|
||||||
const rotate = steady * time;
|
const rotate = steady * time;
|
||||||
haps.forEach((hap) => {
|
haps.forEach((hap) => {
|
||||||
const isActive = hap.whole.begin <= time && hap.endClipped > time;
|
const isActive = hap.whole.begin <= time && hap.endClipped > time;
|
||||||
const from = hap.whole.begin - time + inset;
|
const from = hap.whole.begin - time + inset;
|
||||||
const to = hap.endClipped - time + inset - padding;
|
const to = hap.endClipped - time + inset - padding;
|
||||||
const { color } = hap.context;
|
const { color } = hap.context;
|
||||||
const opacity = fade ? 1 - Math.abs((hap.whole.begin - time) / min) : 1;
|
const opacity = fade ? 1 - Math.abs((hap.whole.begin - time) / min) : 1;
|
||||||
spiralSegment({
|
|
||||||
ctx,
|
|
||||||
...settings,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
rotate,
|
|
||||||
color: colorizeInactive || isActive ? color : inactiveColor,
|
|
||||||
fromOpacity: opacity,
|
|
||||||
toOpacity: opacity,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
spiralSegment({
|
spiralSegment({
|
||||||
ctx,
|
ctx,
|
||||||
...playhead,
|
...settings,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
rotate,
|
rotate,
|
||||||
|
color: colorizeInactive || isActive ? color : inactiveColor,
|
||||||
|
fromOpacity: opacity,
|
||||||
|
toOpacity: opacity,
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
spiralSegment({
|
||||||
|
ctx,
|
||||||
|
...playhead,
|
||||||
|
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 }));
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user