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
from
to
Returns
boolean
applyAxisDelta()
function applyAxisDelta(axis, delta): Axis;An axis projected by an AxisDelta: a fresh axis.
Parameters
axis
delta
Returns
applyBoxDelta()
function applyBoxDelta(box, delta): Box;A box projected by a Delta: a fresh box. applyBoxDelta(source, calcBoxDelta(source, target)) is target.
Parameters
box
delta
Returns
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
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
target
origin?
number = 0.5
Returns
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
target
origin?
Point = ...
Returns
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
parent
anchor
number
Returns
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
parent
anchor?
Point = ...
Returns
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
parent
anchor
number
Returns
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
parent
anchor?
Point = ...
Returns
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
origin
target
Returns
withSizeOf()
function withSizeOf(box, like): Box;box with like's size, at its own top-left.