File size: 1,633 Bytes
c9e39f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/** Quintic paths retain velocity when interrupted; arc and acceleration settle to zero. */
export function sampleMotion(motion, now) {
  const t = Math.max(0, Math.min(1, (now - motion.started) / motion.duration));
  const t2 = t * t, t3 = t2 * t, t4 = t3 * t, t5 = t4 * t;
  const ease = 10 * t3 - 15 * t4 + 6 * t5;
  const carry = t - 6 * t3 + 8 * t4 - 3 * t5;
  const arch = 64 * t3 * (1 - t) ** 3;
  const de = 30 * t2 * (1 - t) ** 2;
  const dc = 1 - 18 * t2 + 32 * t3 - 15 * t4;
  const da = 192 * t2 * (1 - t) ** 2 * (1 - 2 * t);
  const seconds = motion.duration / 1000;
  const value = {}, velocity = {};
  for (const key of ['x', 'y', 'scale']) {
    const delta = motion.to[key] - motion.from[key];
    const v = motion.velocity[key] || 0;
    const bend = motion.arc[key] || 0;
    value[key] = motion.from[key] + delta * ease + v * seconds * carry + bend * arch;
    velocity[key] = delta * de / seconds + v * dc + bend * da / seconds;
  }
  return { value, velocity, done: t === 1 };
}

export function transition(node, target, now, immediate = false) {
  const current = node.motion ? sampleMotion(node.motion, now) : { value: node, velocity: {} };
  const from = { x: current.value.x, y: current.value.y, scale: current.value.scale };
  const dx = target.x - from.x, dy = target.y - from.y;
  const distance = Math.hypot(dx, dy);
  const bend = Math.min(36, distance * 0.055);
  node.motion = {
    from, to: target, velocity: current.velocity,
    arc: { x: -dy / (distance || 1) * bend, y: dx / (distance || 1) * bend },
    started: now,
    duration: immediate ? 1 : Math.min(950, 600 + distance * 0.22),
  };
}