Skip to content

Commit

Permalink
Refactoring snapshot
Browse files Browse the repository at this point in the history
  • Loading branch information
mattgperry committed Nov 10, 2022
1 parent 039c531 commit 8d53854
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 59 deletions.
6 changes: 3 additions & 3 deletions packages/framer-motion-3d/src/components/use-layout-camera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ export function useLayoutCamera<CameraType>(
const removeAnimationCompleteListener = projection.addEventListener(
"animationComplete",
() => {
const { actual } = projection.layout || {}
const { layoutBox } = projection.layout || {}

if (actual) {
if (layoutBox) {
setTimeout(() => {
const newSize = calcBoxSize(actual)
const newSize = calcBoxSize(layoutBox)
updateCamera(newSize)

dimensions.current = { size: newSize }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export class VisualElementDragControls {
*/
if (percent.test(current)) {
const measuredAxis =
this.visualElement.projection?.layout?.actual[axis]
this.visualElement.projection?.layout?.layoutBox[axis]

if (measuredAxis) {
const length = calcLength(measuredAxis)
Expand Down Expand Up @@ -275,7 +275,7 @@ export class VisualElementDragControls {
} else {
if (dragConstraints && layout) {
this.constraints = calcRelativeConstraints(
layout.actual,
layout.layoutBox,
dragConstraints
)
} else {
Expand All @@ -298,7 +298,7 @@ export class VisualElementDragControls {
eachAxis((axis) => {
if (this.getAxisMotionValue(axis)) {
this.constraints[axis] = rebaseAxisConstraints(
layout.actual[axis],
layout.layoutBox[axis],
this.constraints[axis]
)
}
Expand Down Expand Up @@ -330,7 +330,7 @@ export class VisualElementDragControls {
)

let measuredConstraints = calcViewportConstraints(
projection.layout.actual,
projection.layout.layoutBox,
constraintsBox
)

Expand Down Expand Up @@ -446,7 +446,7 @@ export class VisualElementDragControls {
const axisValue = this.getAxisMotionValue(axis)

if (projection && projection.layout) {
const { min, max } = projection.layout.actual[axis]
const { min, max } = projection.layout.layoutBox[axis]

axisValue.set(point[axis] - mix(min, max, 0.5))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ import { eachAxis } from "../utils/each-axis"
import { has2DTranslate, hasScale, hasTransform } from "../utils/has-transform"
import {
IProjectionNode,
Layout,
LayoutEvents,
LayoutUpdateData,
ProjectionNodeConfig,
ProjectionNodeOptions,
Snapshot,
Measurements,
} from "./types"
import { FlatTree } from "../../render/utils/flat-tree"
import { Transition } from "../../types"
Expand Down Expand Up @@ -116,13 +115,13 @@ export function createProjectionNode<I>({
* hydrated when this node's `willUpdate` method is called and scrubbed at the
* end of the tree's `didUpdate` method.
*/
snapshot: Snapshot | undefined
snapshot: Measurements | undefined

/**
* A box defining the element's layout relative to the page. This will have been
* captured with all parent scrolls and projection transforms unset.
*/
layout: Layout | undefined
layout: Measurements | undefined

/**
* The layout used to calculate the previous layout animation. We use this to compare
Expand Down Expand Up @@ -247,7 +246,7 @@ export function createProjectionNode<I>({
/**
* An object representing the calculated contextual/accumulated/tree scale.
* This will be used to scale calculcated projection transforms, as these are
* calculated in screen-space but need to be scaled for elements to actually
* calculated in screen-space but need to be scaled for elements to layoutly
* make it to their calculated destinations.
*
* TODO: Lazy-init
Expand Down Expand Up @@ -657,8 +656,8 @@ export function createProjectionNode<I>({
roundBox(layout)

this.snapshot = {
measured,
layout,
measuredBox: measured,
layoutBox: layout,
latestValues: {},
}
}
Expand Down Expand Up @@ -696,19 +695,20 @@ export function createProjectionNode<I>({

const prevLayout = this.layout
this.layout = {
measured,
actual: this.removeElementScroll(measured),
measuredBox: measured,
layoutBox: this.removeElementScroll(measured),
latestValues: {},
}

this.layoutCorrected = createBox()
this.isLayoutDirty = false
this.projectionDelta = undefined
this.notifyListeners("measure", this.layout.actual)
this.notifyListeners("measure", this.layout.layoutBox)

this.options.visualElement?.notify(
"LayoutMeasure",
this.layout.actual,
prevLayout?.actual
this.layout.layoutBox,
prevLayout?.layoutBox
)
}

Expand Down Expand Up @@ -848,7 +848,7 @@ export function createProjectionNode<I>({
removeBoxTransforms(
boxWithoutTransform,
node.latestValues,
node.snapshot?.layout,
node.snapshot?.layoutBox,
sourceBox
)
}
Expand Down Expand Up @@ -913,8 +913,8 @@ export function createProjectionNode<I>({
this.relativeTargetOrigin = createBox()
calcRelativePosition(
this.relativeTargetOrigin,
this.layout.actual,
relativeParent.layout.actual
this.layout.layoutBox,
relativeParent.layout.layoutBox
)
copyBoxInto(this.relativeTarget, this.relativeTargetOrigin)
} else {
Expand Down Expand Up @@ -956,17 +956,17 @@ export function createProjectionNode<I>({
} else if (this.targetDelta) {
if (Boolean(this.resumingFrom)) {
// TODO: This is creating a new object every frame
this.target = this.applyTransform(this.layout.actual)
this.target = this.applyTransform(this.layout.layoutBox)
} else {
copyBoxInto(this.target, this.layout.actual)
copyBoxInto(this.target, this.layout.layoutBox)
}

applyBoxDelta(this.target, this.targetDelta)
} else {
/**
* If no target, use own layout as target
*/
copyBoxInto(this.target, this.layout.actual)
copyBoxInto(this.target, this.layout.layoutBox)
}

/**
Expand Down Expand Up @@ -1043,7 +1043,7 @@ export function createProjectionNode<I>({
* Reset the corrected box with the latest values from box, as we're then going
* to perform mutative operations on it.
*/
copyBoxInto(this.layoutCorrected, this.layout.actual)
copyBoxInto(this.layoutCorrected, this.layout.layoutBox)

/**
* Apply all the parent deltas to this box to produce the corrected box. This
Expand Down Expand Up @@ -1167,8 +1167,8 @@ export function createProjectionNode<I>({
) {
calcRelativePosition(
relativeLayout,
this.layout.actual,
this.relativeParent.layout.actual
this.layout.layoutBox,
this.relativeParent.layout.layoutBox
)
mixBox(
this.relativeTarget,
Expand Down Expand Up @@ -1280,17 +1280,17 @@ export function createProjectionNode<I>({
layout &&
shouldAnimatePositionOnly(
this.options.animationType,
this.layout.actual,
layout.actual
this.layout.layoutBox,
layout.layoutBox
)
) {
target = this.target || createBox()

const xLength = calcLength(this.layout!.actual.x)
const xLength = calcLength(this.layout!.layoutBox.x)
target!.x.min = lead.target!.x.min
target!.x.max = target.x.min + xLength

const yLength = calcLength(this.layout!.actual.y)
const yLength = calcLength(this.layout!.layoutBox.y)
target!.y.min = lead.target!.y.min
target!.y.max = target.y.min + yLength
}
Expand All @@ -1307,7 +1307,7 @@ export function createProjectionNode<I>({
/**
* Update the delta between the corrected box and the final target box, after
* user-set transforms are applied to it. This will be used by the renderer to
* create a transform style that will reproject the element from its actual layout
* create a transform style that will reproject the element from its layout layout
* into the desired bounding box.
*/
calcBoxDelta(
Expand Down Expand Up @@ -1515,7 +1515,7 @@ export function createProjectionNode<I>({
: valuesToRender.opacityExit
} else {
/**
* Or we're not animating at all, set the lead component to its actual
* Or we're not animating at all, set the lead component to its layout
* opacity and other components to hidden.
*/
styles.opacity =
Expand Down Expand Up @@ -1590,43 +1590,43 @@ function notifyLayoutUpdate(node: IProjectionNode) {
snapshot &&
node.hasListeners("didUpdate")
) {
const { actual: layout, measured: measuredLayout } = node.layout
const { layoutBox: layout, measuredBox: measuredLayout } = node.layout
const { animationType } = node.options

// TODO Maybe we want to also resize the layout snapshot so we don't trigger
// animations for instance if layout="size" and an element has only changed position
if (animationType === "size") {
eachAxis((axis) => {
const axisSnapshot = snapshot.isShared
? snapshot.measured[axis]
: snapshot.layout[axis]
? snapshot.measuredBox[axis]
: snapshot.layoutBox[axis]
const length = calcLength(axisSnapshot)
axisSnapshot.min = layout[axis].min
axisSnapshot.max = axisSnapshot.min + length
})
} else if (
shouldAnimatePositionOnly(animationType, snapshot.layout, layout)
shouldAnimatePositionOnly(animationType, snapshot.layoutBox, layout)
) {
eachAxis((axis) => {
const axisSnapshot = snapshot.isShared
? snapshot.measured[axis]
: snapshot.layout[axis]
? snapshot.measuredBox[axis]
: snapshot.layoutBox[axis]
const length = calcLength(layout[axis])
axisSnapshot.max = axisSnapshot.min + length
})
}

const layoutDelta = createDelta()
calcBoxDelta(layoutDelta, layout, snapshot.layout)
calcBoxDelta(layoutDelta, layout, snapshot.layoutBox)
const visualDelta = createDelta()
if (snapshot.isShared) {
calcBoxDelta(
visualDelta,
node.applyTransform(measuredLayout, true),
snapshot.measured
snapshot.measuredBox
)
} else {
calcBoxDelta(visualDelta, layout, snapshot.layout)
calcBoxDelta(visualDelta, layout, snapshot.layoutBox)
}

const hasLayoutChanged = !isDeltaZero(layoutDelta)
Expand All @@ -1647,15 +1647,15 @@ function notifyLayoutUpdate(node: IProjectionNode) {
const relativeSnapshot = createBox()
calcRelativePosition(
relativeSnapshot,
snapshot.layout,
parentSnapshot.layout
snapshot.layoutBox,
parentSnapshot.layoutBox
)

const relativeLayout = createBox()
calcRelativePosition(
relativeLayout,
layout,
parentLayout.actual
parentLayout.layoutBox
)

if (!boxEquals(relativeSnapshot, relativeLayout)) {
Expand Down
18 changes: 6 additions & 12 deletions packages/framer-motion/src/projection/node/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,13 @@ import { InitialPromotionConfig } from "../../context/SwitchLayoutGroupContext"
import { MotionStyle } from "../../motion/types"
import type { VisualElement } from "../../render/VisualElement"

// TODO: Find more appropriate names for each snapshot
export interface Snapshot {
measured: Box
layout: Box
export interface Measurements {
measuredBox: Box
layoutBox: Box
latestValues: ResolvedValues
isShared?: boolean
}

export interface Layout {
measured: Box
actual: Box // with scroll removed
}

export type LayoutEvents =
| "willUpdate"
| "didUpdate"
Expand All @@ -44,8 +38,8 @@ export interface IProjectionNode<I = unknown> {
unmount: () => void
options: ProjectionNodeOptions
setOptions(options: ProjectionNodeOptions): void
layout?: Layout
snapshot?: Snapshot
layout?: Measurements
snapshot?: Measurements
target?: Box
relativeTarget?: Box
targetDelta?: Delta
Expand Down Expand Up @@ -128,7 +122,7 @@ export interface IProjectionNode<I = unknown> {

export interface LayoutUpdateData {
layout: Box
snapshot: Snapshot
snapshot: Measurements
delta: Delta
layoutDelta: Delta
hasLayoutChanged: boolean
Expand Down

0 comments on commit 8d53854

Please sign in to comment.