All files / src/projection/geometry delta-apply.ts

42.86% Statements 24/56
11.76% Branches 4/34
50% Functions 4/8
50% Lines 24/48

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 16140x     40x           40x 20x 20x 20x           40x             12x 4x     12x           40x   4x 4x       4x               4x                       40x                     40x                                                                                       40x 146x 146x               40x                                             40x 40x         40x        
import { mix } from "popmotion"
import { ResolvedValues } from "../../render/types"
import { IProjectionNode } from "../node/types"
import { hasTransform } from "../utils/has-transform"
import { Axis, Box, Delta, Point } from "./types"
 
/**
 * Scales a point based on a factor and an originPoint
 */
export function scalePoint(point: number, scale: number, originPoint: number) {
    const distanceFromOrigin = point - originPoint
    const scaled = scale * distanceFromOrigin
    return originPoint + scaled
}
 
/**
 * Applies a translate/scale delta to a point
 */
export function applyPointDelta(
    point: number,
    translate: number,
    scale: number,
    originPoint: number,
    boxScale?: number
): number {
    if (boxScale !== undefined) {
        point = scalePoint(point, boxScale, originPoint)
    }
 
    return scalePoint(point, scale, originPoint) + translate
}
 
/**
 * Applies a translate/scale delta to an axis
 */
export function applyAxisDelta(
    axis: Axis,
    Itranslate: number = 0,
    Iscale: number = 1,
    originPoint: number,
    boxScale?: number
): void {
    axis.min = applyPointDelta(
        axis.min,
        translate,
        scale,
        originPoint,
        boxScale
    )
 
    axis.max = applyPointDelta(
        axis.max,
        translate,
        scale,
        originPoint,
        boxScale
    )
}
 
/**
 * Applies a translate/scale delta to a box
 */
export function applyBoxDelta(box: Box, { x, y }: Delta): void {
    applyAxisDelta(box.x, x.translate, x.scale, x.originPoint)
    applyAxisDelta(box.y, y.translate, y.scale, y.originPoint)
}
 
/**
 * Apply a tree of deltas to a box. We do this to calculate the effect of all the transforms
 * in a tree upon our box before then calculating how to project it into our desired viewport-relative box
 *
 * This is the final nested loop within updateLayoutDelta for future refactoring
 */
export function applyTreeDeltas(
    box: Box,
    treeScale: Point,
    treePath: IProjectionNode[],
    isSharedTransition: boolean = false
) {
    const treeLength = treePath.length
    if (!treeLength) return
 
    // Reset the treeScale
    treeScale.x = treeScale.y = 1
 
    let node: IProjectionNode
    let delta: Delta | undefined
 
    for (let i = 0; i < treeLength; i++) {
        node = treePath[i]
        delta = node.projectionDelta
        if ((node.instance as any)?.style?.display === "contents") continue
 
        if (
            isSharedTransition &&
            node.options.layoutScroll &&
            node.scroll &&
            node !== node.root
        ) {
            transformBox(box, { x: -node.scroll.x, y: -node.scroll.y })
        }
 
        if (delta) {
            // Incoporate each ancestor's scale into a culmulative treeScale for this component
            treeScale.x *= delta.x.scale
            treeScale.y *= delta.y.scale
 
            // Apply each ancestor's calculated delta into this component's recorded layout box
            applyBoxDelta(box, delta)
        }
 
        if (isSharedTransition && hasTransform(node.latestValues)) {
            transformBox(box, node.latestValues)
        }
    }
}
 
export function translateAxis(axis: Axis, distance: number) {
    axis.min = axis.min + distance
    axis.max = axis.max + distance
}
 
/**
 * Apply a transform to an axis from the latest resolved motion values.
 * This function basically acts as a bridge between a flat motion value map
 * and applyAxisDelta
 */
export function transformAxis(
    axis: Axis,
    transforms: ResolvedValues,
    [key, scaleKey, originKey]: string[]
): void {
    const axisOrigin =
        transforms[originKey] !== undefined ? transforms[originKey] : 0.5
 
    const originPoint = mix(axis.min, axis.max, axisOrigin as number)
 
    // Apply the axis delta to the final axis
    applyAxisDelta(
        axis,
        transforms[key] as number,
        transforms[scaleKey] as number,
        originPoint,
        transforms.scale as number
    )
}
 
/**
 * The names of the motion values we want to apply as translation, scale and origin.
 */
const xKeys = ["x", "scaleX", "originX"]
const yKeys = ["y", "scaleY", "originY"]
 
/**
 * Apply a transform to a box from the latest resolved motion values.
 */
export function transformBox(box: Box, transform: ResolvedValues) {
    transformAxis(box.x, transform, xKeys)
    transformAxis(box.y, transform, yKeys)
}