pie
ExamplesDocs

Topics

  • Canvas
  • Reactivity
  • Broadcasting
  • Autodiff
  • Animation
  • Python
unitgridOpacitycanvasColor

Animation

  • A line folds into a circle
  • Bubble sort

Four calls change a node that is already on the canvas:

  • pie.translate_point_to(p, x, y) moves point p to (x, y).
  • pie.translate_point_by(p, dx, dy) moves it by (dx, dy).
  • pie.translate_scalar_to(s, value) sets number s to value.
  • pie.translate_scalar_by(s, delta) adds delta to it.

Normally the change is instant. Add animate=True and it glides there over half a second instead. Everything built from the node follows along. Each call waits until its move ends, so a loop of them plays one move after another. Pass an array of points and they all move at the same time.

Only scalars and points can be animated. This is done on purpose: the entire animation set up should be built in a way that it depends on scalars and points. Moving them is just a matter of moving these scalars and points. Eg to move a circle, just move its center. Reactivity will ensure that the circle also moves along.

A line folds into a circle

Twelve points start on a line. Each side of the shape joins two of them, so the sides follow the points as they move.

pie.clear()
import math
n = 12
ps = pie.point([i - 5.5 for i in range(n)], 0, fill='crimson')
for i in range(n):
    pie.line(ps[i], ps[(i + 1) % n], stroke='teal')

def ring(radius):
    """Where each point goes: around a circle. `radius` is one number, or one per point."""
    radii = radius if isinstance(radius, list) else [radius] * n
    angles = [math.pi / 2 + 2 * math.pi * i / n for i in range(n)]
    xs = [r * math.cos(t) for r, t in zip(radii, angles)]
    ys = [r * math.sin(t) for r, t in zip(radii, angles)]
    return xs, ys

pie.translate_point_to(ps, *ring(3), animate=True)

ps, xs and ys each have 12 items, so one call moves all 12 points together.

Now a star, by giving every other point a smaller radius, and then back to the line:

pie.translate_point_to(ps, *ring([3 if i % 2 == 0 else 1.2 for i in range(n)]), animate=True)
pie.translate_point_to(ps, *ring(3), animate=True)
pie.translate_point_to(ps, [i - 5.5 for i in range(n)], 0, animate=True)

Bubble sort

Bubble sort walks along a row of bars and swaps every pair of neighbors that is in the wrong order. After each pass the tallest bar left has reached its place at the end. Each bar is a line between two points, so a swap moves the four points of the two bars.

pie.clear()
pie.text('#1c1917', out='canvasColor')  # a dark canvas
pie.scalar(0, out='gridOpacity')        # no grid
gray, amber, teal = '#a8a29e', '#fcd34d', '#5eead4'

heights = [5, 2, 6, 1, 4, 7, 3]
n = len(heights)
x = lambda i: i - (n - 1) / 2  # x position of slot i
bottoms = [pie.point(x(i), -3, hidden=True) for i in range(n)]
tops = [pie.point(x(i), h - 3, hidden=True) for i, h in enumerate(heights)]
bars = [pie.line(b, t, stroke=gray) for b, t in zip(bottoms, tops)]
tick = pie.scalar(0, out='tick')  # not drawn; animating it is a half-second pause

# bars[order[i]] is the bar in slot i.
order = list(range(n))
for end in range(n - 1, 0, -1):
    for i in range(end):
        left, right = order[i], order[i + 1]
        pie.set_stroke([bars[left], bars[right]], amber)
        if heights[left] > heights[right]:
            # The left bar moves right by 1 and the right bar left by 1.
            pie.translate_point_by([bottoms[left], tops[left], bottoms[right], tops[right]], [1, 1, -1, -1], 0, animate=True)
            order[i], order[i + 1] = right, left
        else:
            pie.translate_scalar_by(tick, 1, animate=True)
        pie.set_stroke([bars[left], bars[right]], gray)
    pie.set_stroke(bars[order[end]], teal)
pie.set_stroke(bars[order[0]], teal)

Amber bars are being compared. A teal bar is in its final place.