jevstrudel.git / packages / draw / animate.mjs
1import { Pattern, silence, register, pure, createParams } from '@strudel/core';
2import { getDrawContext } from './draw.mjs';
3
4let clearColor = '#22222210';
5
6Pattern.prototype.animate = function ({ callback, sync = false, smear = 0.5 } = {}) {
7  window.frame && cancelAnimationFrame(window.frame);
8  const ctx = getDrawContext();
9  let { clientWidth: ww, clientHeight: wh } = ctx.canvas;
10  ww *= window.devicePixelRatio;
11  wh *= window.devicePixelRatio;
12  let smearPart = smear === 0 ? '99' : Number((1 - smear) * 100).toFixed(0);
13  smearPart = smearPart.length === 1 ? `0${smearPart}` : smearPart;
14  clearColor = `#200010${smearPart}`;
15  const render = (t) => {
16    let frame;
17    /*     if (sync) {
18      t = scheduler.now();
19      frame = this.queryArc(t, t);
20    } else { */
21    t = Math.round(t);
22    frame = this.slow(1000).queryArc(t, t);
23    // }
24    ctx.fillStyle = clearColor;
25    ctx.fillRect(0, 0, ww, wh);
26    frame.forEach((f) => {
27      let { x, y, w, h, s, r, angle = 0, fill = 'darkseagreen' } = f.value;
28      w *= ww;
29      h *= wh;
30      if (r !== undefined && angle !== undefined) {
31        const radians = angle * 2 * Math.PI;
32        const [cx, cy] = [(ww - w) / 2, (wh - h) / 2];
33        x = cx + Math.cos(radians) * r * cx;
34        y = cy + Math.sin(radians) * r * cy;
35      } else {
36        x *= ww - w;
37        y *= wh - h;
38      }
39      const val = { ...f.value, x, y, w, h };
40      ctx.fillStyle = fill;
41      if (s === 'rect') {
42        ctx.fillRect(x, y, w, h);
43      } else if (s === 'ellipse') {
44        ctx.beginPath();
45        ctx.ellipse(x + w / 2, y + h / 2, w / 2, h / 2, 0, 0, 2 * Math.PI);
46        ctx.fill();
47      }
48      callback && callback(ctx, val, f);
49    });
50    window.frame = requestAnimationFrame(render);
51  };
52  window.frame = requestAnimationFrame(render);
53  return silence;
54};
55
56export const { x, y, w, h, angle, r, fill, smear } = createParams('x', 'y', 'w', 'h', 'angle', 'r', 'fill', 'smear');
57
58export const rescale = register('rescale', function (f, pat) {
59  return pat.mul(x(f).w(f).y(f).h(f));
60});
61
62export const moveXY = register('moveXY', function (dx, dy, pat) {
63  return pat.add(x(dx).y(dy));
64});
65
66export const zoomIn = register('zoomIn', function (f, pat) {
67  const d = pure(1).sub(f).div(2);
68  return pat.rescale(f).move(d, d);
69});