Skip to content

Commit

Permalink
Merge pull request #64 from saitonakamura/flex-center-anchor
Browse files Browse the repository at this point in the history
Added centerAcnhor prop on Flex, which centers it on position
  • Loading branch information
giulioz authored Sep 1, 2021
2 parents ab622a2 + ab4100b commit aca8e7d
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 4 deletions.
21 changes: 17 additions & 4 deletions src/Flex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
getDepthAxis,
getFlex2DSize,
getOBBSize,
getRootShift,
} from './util'
import { boxContext, flexContext, SharedFlexContext, SharedBoxContext } from './context'
import type { R3FlexProps, FlexYogaDirection, FlexPlane } from './props'
Expand All @@ -26,6 +27,10 @@ export type FlexProps = PropsWithChildren<
scaleFactor?: number
onReflow?: (totalWidth: number, totalHeight: number) => void
disableSizeRecalc?: boolean
/** Centers flex container in position.
*
* !NB center is based on provided flex size, not on the actual content */
centerAnchor?: boolean
}> &
R3FlexProps &
Omit<ReactThreeFiber.Object3DNode<THREE.Group, typeof Group>, 'children'>
Expand All @@ -49,6 +54,7 @@ export function Flex({
scaleFactor = 100,
onReflow,
disableSizeRecalc,
centerAnchor: rootCenterAnchor,

// flex props

Expand Down Expand Up @@ -272,8 +278,8 @@ export function Flex({
[requestReflow, registerBox, unregisterBox, scaleFactor]
)
const sharedBoxContext = useMemo<SharedBoxContext>(
() => ({ node, size: [flexWidth, flexHeight] }),
[node, flexWidth, flexHeight]
() => ({ node, size: [flexWidth, flexHeight], centerAnchor: rootCenterAnchor }),
[node, flexWidth, flexHeight, rootCenterAnchor]
)

// Handles the reflow procedure
Expand Down Expand Up @@ -306,6 +312,9 @@ export function Flex({
// Perform yoga layout calculation
node.calculateLayout(flexWidth * scaleFactor, flexHeight * scaleFactor, yogaDirection_)

const rootWidth = node.getComputedWidth()
const rootHeight = node.getComputedHeight()

let minX = 0
let maxX = 0
let minY = 0
Expand All @@ -314,15 +323,19 @@ export function Flex({
// Reposition after recalculation
boxesRef.current.forEach(({ group, node, centerAnchor }) => {
const { left, top, width, height } = node.getComputedLayout()
const [mainAxisShift, crossAxisShift] = getRootShift(rootCenterAnchor, rootWidth, rootHeight, node)

const position = vectorFromObject({
[mainAxis]: (left + (centerAnchor ? width / 2 : 0)) / scaleFactor,
[crossAxis]: -(top + (centerAnchor ? height / 2 : 0)) / scaleFactor,
[mainAxis]: (mainAxisShift + left + (centerAnchor ? width / 2 : 0)) / scaleFactor,
[crossAxis]: -(crossAxisShift + top + (centerAnchor ? height / 2 : 0)) / scaleFactor,
[depthAxis]: 0,
} as any)

minX = Math.min(minX, left)
minY = Math.min(minY, top)
maxX = Math.max(maxX, left + width)
maxY = Math.max(maxY, top + height)

group.position.copy(position)
})

Expand Down
17 changes: 17 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,3 +155,20 @@ export const getOBBSize = (object: Object3D, root: Object3D, bb: Box3, size: Vec
object.matrixAutoUpdate = oldMatrixAutoUpdate
root.updateMatrixWorld()
}

const getIsTopLevelChild = (node: YogaNode) => !node.getParent()?.getParent()

/** @returns [mainAxisShift, crossAxisShift] */
export const getRootShift = (
rootCenterAnchor: boolean | undefined,
rootWidth: number,
rootHeight: number,
node: YogaNode
) => {
if (!rootCenterAnchor || !getIsTopLevelChild(node)) {
return [0, 0]
}
const mainAxisShift = -rootWidth / 2
const crossAxisShift = -rootHeight / 2
return [mainAxisShift, crossAxisShift] as const
}

0 comments on commit aca8e7d

Please sign in to comment.