renderMovers = function*(
{ visibility, height = 200, speed = 1, overflow = 'wrap', trace = false },
...movers
) {
const ctx = DOM.context2d(width, height);
let trailsCtx;
const srcDim = [0, 0, width * devicePixelRatio, height * devicePixelRatio];
const destDim = [0, 0, width, height];
if (trace) {
trailsCtx = DOM.context2d(width, height);
trailsCtx.strokeStyle = '#00f';
trailsCtx.lineWidth = 1;
trailsCtx.globalAlpha = 0.2;
}
const mouse = {
pos: null,
down: false,
shift: false
};
ctx.canvas.onmousemove = e => {
mouse.pos = new THREE.Vector2(e.offsetX, e.offsetY);
};
ctx.canvas.onmouseleave = e => {
mouse.pos = null;
mouse.down = false;
mouse.shift = false;
};
ctx.canvas.onmousedown = e => {
mouse.down = true;
mouse.shift = e.shiftKey;
};
ctx.canvas.onmouseup = e => {
mouse.down = false;
mouse.shift = false;
};
const update = mover => {
const start = [mover.x, mover.y];
mover.update({
mouse
});
const end = [mover.x, mover.y];
switch (overflow) {
case 'wrap':
mover.x = wrap(mover.x, 0, width);
mover.y = wrap(mover.y, 0, height);
break;
}
if (trace) {
trailsCtx.beginPath();
trailsCtx.moveTo(...start);
trailsCtx.lineTo(...end);
trailsCtx.stroke();
trailsCtx.closePath();
}
};
while (true) {
repeat(() => movers.forEach(update), speed);
ctx.clearRect(0, 0, width, height);
if (trace) {
ctx.drawImage(trailsCtx.canvas, ...srcDim, ...destDim);
}
movers.forEach(mover => mover.display(ctx));
yield visibility(ctx.canvas);
}
}