simplify draw plumbing

This commit is contained in:
Felix Roos 2024-03-28 06:25:24 +01:00
parent 1a0dff4081
commit 04a0952a22
6 changed files with 15 additions and 36 deletions

View File

@ -128,6 +128,7 @@ export class StrudelMirror {
id, id,
initialCode = '', initialCode = '',
onDraw, onDraw,
drawContext,
drawTime = [0, 0], drawTime = [0, 0],
autodraw, autodraw,
prebake, prebake,
@ -140,13 +141,14 @@ export class StrudelMirror {
this.widgets = []; this.widgets = [];
this.painters = []; this.painters = [];
this.drawTime = drawTime; this.drawTime = drawTime;
this.onDraw = onDraw; this.drawContext = drawContext;
this.onDraw = onDraw || this.draw;
this.id = id || s4(); this.id = id || s4();
this.drawer = new Drawer((haps, time) => { this.drawer = new Drawer((haps, time) => {
const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.endClipped); const currentFrame = haps.filter((hap) => hap.isActive(time));
this.highlight(currentFrame, time); this.highlight(currentFrame, time);
this.onDraw?.(haps, time, currentFrame, this.painters); this.onDraw(haps, time, this.painters);
}, drawTime); }, drawTime);
this.prebaked = prebake(); this.prebaked = prebake();
@ -236,6 +238,9 @@ export class StrudelMirror {
// when no painters are set, [0,0] is enough (just highlighting) // when no painters are set, [0,0] is enough (just highlighting)
this.drawer.setDrawTime(this.painters.length ? this.drawTime : [0, 0]); this.drawer.setDrawTime(this.painters.length ? this.drawTime : [0, 0]);
} }
draw(haps, time) {
this.painters?.forEach((painter) => painter(this.drawContext, time, haps, this.drawTime));
}
async drawFirstFrame() { async drawFirstFrame() {
if (!this.onDraw) { if (!this.onDraw) {
return; return;
@ -246,7 +251,7 @@ export class StrudelMirror {
await this.repl.evaluate(this.code, false); await this.repl.evaluate(this.code, false);
this.drawer.invalidate(this.repl.scheduler, -0.001); this.drawer.invalidate(this.repl.scheduler, -0.001);
// draw at -0.001 to avoid haps at 0 to be visualized as active // draw at -0.001 to avoid haps at 0 to be visualized as active
this.onDraw?.(this.drawer.visibleHaps, -0.001, [], this.painters); this.onDraw?.(this.drawer.visibleHaps, -0.001, this.painters);
} catch (err) { } catch (err) {
console.warn('first frame could not be painted'); console.warn('first frame could not be painted');
} }

View File

@ -50,7 +50,7 @@ export class Hap {
} }
isActive(currentTime) { isActive(currentTime) {
return this.whole.begin <= currentTime && this.endClipped > currentTime; return this.whole.begin <= currentTime && this.endClipped >= currentTime;
} }
isInPast(currentTime) { isInPast(currentTime) {

View File

@ -277,8 +277,8 @@ export function getDrawOptions(drawTime, options = {}) {
export const getPunchcardPainter = export const getPunchcardPainter =
(options = {}) => (options = {}) =>
(ctx, time, haps, drawTime, paintOptions = {}) => (ctx, time, haps, drawTime) =>
pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, { ...paintOptions, ...options }) }); pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, options) });
Pattern.prototype.punchcard = function (options) { Pattern.prototype.punchcard = function (options) {
return this.onPaint(getPunchcardPainter(options)); return this.onPaint(getPunchcardPainter(options));

View File

@ -41,17 +41,8 @@ if (typeof HTMLElement !== 'undefined') {
initialCode: '// LOADING', initialCode: '// LOADING',
pattern: silence, pattern: silence,
drawTime, drawTime,
onDraw: (haps, time, frame, painters) => { drawContext,
painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2);
painters?.forEach((painter) => {
// ctx time haps drawTime paintOptions
painter(drawContext, time, haps, drawTime, { clear: false });
});
},
prebake, prebake,
afterEval: ({ code }) => {
// window.location.hash = '#' + code2hash(code);
},
onUpdateState: (state) => { onUpdateState: (state) => {
const event = new CustomEvent('update', { const event = new CustomEvent('update', {
detail: state, detail: state,

View File

@ -39,16 +39,6 @@ export function MiniRepl({
const init = useCallback(({ code, shouldDraw }) => { const init = useCallback(({ code, shouldDraw }) => {
const drawContext = shouldDraw ? document.querySelector('#' + canvasId)?.getContext('2d') : null; const drawContext = shouldDraw ? document.querySelector('#' + canvasId)?.getContext('2d') : null;
let onDraw;
if (shouldDraw) {
onDraw = (haps, time, frame, painters) => {
painters.length && drawContext?.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2);
painters?.forEach((painter) => {
// ctx time haps drawTime paintOptions
painter(drawContext, time, haps, drawTime, { clear: false });
});
};
}
const editor = new StrudelMirror({ const editor = new StrudelMirror({
id, id,
@ -60,7 +50,7 @@ export function MiniRepl({
initialCode: '// LOADING', initialCode: '// LOADING',
pattern: silence, pattern: silence,
drawTime, drawTime,
onDraw, drawContext,
editPattern: (pat, id) => { editPattern: (pat, id) => {
if (onTrigger) { if (onTrigger) {
pat = pat.onTrigger(onTrigger, false); pat = pat.onTrigger(onTrigger, false);

View File

@ -65,13 +65,6 @@ export function Repl({ embedded = false }) {
const init = useCallback(() => { const init = useCallback(() => {
const drawTime = [-2, 2]; const drawTime = [-2, 2];
const drawContext = getDrawContext(); const drawContext = getDrawContext();
const onDraw = (haps, time, frame, painters) => {
painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2);
painters?.forEach((painter) => {
// ctx time haps drawTime paintOptions
painter(drawContext, time, haps, drawTime, { clear: false });
});
};
const editor = new StrudelMirror({ const editor = new StrudelMirror({
sync: true, sync: true,
defaultOutput: webaudioOutput, defaultOutput: webaudioOutput,
@ -84,7 +77,7 @@ export function Repl({ embedded = false }) {
initialCode: '// LOADING', initialCode: '// LOADING',
pattern: silence, pattern: silence,
drawTime, drawTime,
onDraw, drawContext,
prebake: async () => Promise.all([modulesLoading, presets]), prebake: async () => Promise.all([modulesLoading, presets]),
onUpdateState: (state) => { onUpdateState: (state) => {
setReplState({ ...state }); setReplState({ ...state });