Projection

Layout projection's geometry, as Motion's: the Delta that maps one box onto another (calcBoxDelta), a delta applied to a box (applyBoxDelta), a box drawn through its ancestors' deltas (applyTreeDeltas), and a box relative to its parent's (calcRelativeBox, placeRelativeBox). A binding's projection pass composes them each frame, and writes each node's Value under KEY for its Environment's renderer to draw. LayoutMode says which parts of a layout change animate.

import * as Projection from "@wardic/core/Projection"

const delta = Projection.calcBoxDelta(layout, target)
Projection.applyBoxDelta(layout, delta) // `target`

Interfaces

AxisDelta

What maps one axis onto another: half a Delta.

Properties

origin
readonly origin: number;

Where along the source it scales about, from 0 to 1: 0.5, its middle, by default.

originPoint
readonly originPoint: number;

That point, on the source: its min, plus origin of its length.

scale
readonly scale: number;

The target's length over the source's.

translate
readonly translate: number;

The move that puts the origin point where it is on the target.


Delta

What maps one box onto another: an AxisDelta on each axis.

Properties

x
readonly x: AxisDelta;

Across.

y
readonly y: AxisDelta;

Down.


Value

What a projection pass writes under KEY for a node, each frame: its Delta, from its layout box to where it's drawn, and its ancestors' scale, which the renderer takes back out so the node isn't scaled twice.

Properties

blendOpacity?
readonly blendOpacity?: number;

A handover's blended opacity, from 0 to 1: drawn as the element's opacity in place of its own and of any crossfade, from the leaving element's opacity to its own over the handover. Absent otherwise.

delta
readonly delta: Delta;

From the node's layout box to where it's drawn.

opacity?
readonly opacity?: number;

A twin's Crossfade, from 0 to 1: the element's own opacity is multiplied by it. The lead fades in, the followers fade out. Absent for a plain layout node, so its own opacity shows.

passesPointer?
readonly passesPointer?: true;

Set on a follower: pointer input passes through it to what's beneath, so a follower drawn on its lead's box never takes the lead's input, fading out or hidden at rest, as Motion's. How a renderer lets it through is its Environment's. Absent on a lead, so the element's own value shows.

raise?
readonly raise?: number;

A raise above its siblings: while it's set, the renderer draws the node above them, as a dragged Reorder item is while it's off its place. Absent at rest, so the element's own stacking shows.

rotate?
readonly rotate?: number;

A handover's blended rotation, in degrees: drawn in place of the element's own rotate, from its twin's to its own over the handover. A follower is drawn with its lead's. Absent otherwise, so the element's own rotate shows.

treeScale
readonly treeScale: Point;

Its ancestors' scale, multiplied together.

Type Aliases

LayoutMode

type LayoutMode = true | "position" | "size" | "preserve-aspect" | "x" | "y";

Which parts of a layout change a node's layout animation animates, as Motion's: true, its position and size; "position", its position, its size taking the new one at once; "size", its size; "x" or "y", that axis; "preserve-aspect", both while its width-to-height ratio stays within 0.2, else its position.

Variables

AT_REST

const AT_REST: Value;

A node drawn at its own box: no delta, no ancestors' scale. The renderer draws it with the element's own rotation, skew and scale, and leaves its own move out, as it draws a layout node at rest. What a server, which measures nothing, draws a layout node's starting style and mount animation with.


KEY

const KEY: "@projection" = "@projection";

The key a projection pass writes each node's Value under, each frame, for its Environment's renderer to draw as one transform with the element's own rotation and skew. Namespaced, @projection, so it never collides with an animated key.

Functions

animatesPositionOnly()

function animatesPositionOnly(
   mode, 
   from, 
   to
): boolean;

Whether mode animates only the position of a layout change from from to to: "position", or "preserve-aspect" when their width-to-height ratios are more than 0.2 apart, as Motion's.

Parameters

mode

LayoutMode

from

Box

to

Box

Returns

boolean


applyAxisDelta()

function applyAxisDelta(axis, delta): Axis;

An axis projected by an AxisDelta: a fresh axis.

Parameters

axis

Axis

delta

AxisDelta

Returns

Axis


applyBoxDelta()

function applyBoxDelta(box, delta): Box;

A box projected by a Delta: a fresh box. applyBoxDelta(source, calcBoxDelta(source, target)) is target.

Parameters

box

Box

delta

Delta

Returns

Box


applyPointDelta()

function applyPointDelta(
   point, 
   translate, 
   scale, 
   originPoint, 
   boxScale?
): number;

A coordinate projected by a delta, as Motion's applyPointDelta: scaled by boxScale first, when it's given, the ancestors' scale, then by the delta's own scale about originPoint, then moved by translate.

Parameters

point

number

translate

number

scale

number

originPoint

number

boxScale?

number

Returns

number


applyTreeDeltas()

function applyTreeDeltas(layout, ancestorDeltas): object;

Where a node's layout box is drawn, through its ancestors' deltas, and its ancestors' scale, as Motion's applyTreeDeltas. ancestorDeltas are its ancestors' deltas, the outermost first and its parent last: each is applied in turn, and its scale multiplied into treeScale, which snaps to 1 when it's within float noise of it. The caller decides which ancestors' deltas to pass: what Motion also folds in here, a node with no box of its own, a scroll's compensation, a twin's transform, is the caller's.

Parameters

layout

Box

ancestorDeltas

readonly Delta[]

Returns

object

box
readonly box: Box;
treeScale
readonly treeScale: Point;

calcAxisDelta()

function calcAxisDelta(
   source, 
   target, 
   origin?
): AxisDelta;

The AxisDelta that maps source onto target, about origin, from 0 to 1 along it: 0.5, its middle, by default. The scale is the lengths' ratio, 1 for a source of no length; the move puts the origin point where it is on target. Both snap to 1 and 0 within Motion's precisions, so no transform changes by a fraction of a pixel.

Parameters

source

Axis

target

Axis

origin?

number = 0.5

Returns

AxisDelta


calcBoxDelta()

function calcBoxDelta(
   source, 
   target, 
   origin?
): Delta;

The Delta that maps source onto target, about origin, from 0 to 1 on each axis: the middle by default.

Parameters

source

Box

target

Box

origin?

Point = ...

Returns

Delta


calcRelativeAxis()

function calcRelativeAxis(
   child, 
   parent, 
   anchor
): Axis;

child relative to parent, measured from the point anchor, from 0 to 1, along parent: at 0, from its start; at 0.5, from its middle. How a node's box is put in its parent's terms.

Parameters

child

Axis

parent

Axis

anchor

number

Returns

Axis


calcRelativeBox()

function calcRelativeBox(
   child, 
   parent, 
   anchor?
): Box;

child relative to parent on each axis, at anchor: their top-left by default, as Motion's layoutAnchor.

Parameters

child

Box

parent

Box

anchor?

Point = ...

Returns

Box


placeRelativeAxis()

function placeRelativeAxis(
   relative, 
   parent, 
   anchor
): Axis;

calcRelativeAxis undone: a relative axis placed back into parent at anchor. placeRelativeAxis(calcRelativeAxis(c, p, a), p, a) is c.

Parameters

relative

Axis

parent

Axis

anchor

number

Returns

Axis


placeRelativeBox()

function placeRelativeBox(
   relative, 
   parent, 
   anchor?
): Box;

calcRelativeBox undone, on each axis. Placing a child's box relative to its parent into the parent's box as it's animating gives where the child goes, so a child keeps up with its parent whatever their progress.

Parameters

relative

Box

parent

Box

anchor?

Point = ...

Returns

Box


shapeOrigin()

function shapeOrigin(
   mode, 
   origin, 
   target
): Box;

Where a layout animation from origin to target starts under mode, as Motion's: "size" moves origin to target's top-left, so only its size animates; "x" and "y" take the other axis from target; a position-only mode gives origin target's size at its own top-left, so only its position animates; true leaves it as it is. Once, at each layout animation's start.

Parameters

mode

LayoutMode

origin

Box

target

Box

Returns

Box


withSizeOf()

function withSizeOf(box, like): Box;

box with like's size, at its own top-left.

Parameters

box

Box

like

Box

Returns

Box