From 6e7cc62c14e06eca6e5f3a576ad5d3e72fcdd6b8 Mon Sep 17 00:00:00 2001 From: Robert Long Date: Fri, 13 Aug 2021 12:27:00 -0700 Subject: [PATCH] Naive tile position animations --- src/GridDemo.jsx | 317 +++++++++++++++++++++++++++------------- src/GridDemo.module.css | 2 +- 2 files changed, 214 insertions(+), 105 deletions(-) diff --git a/src/GridDemo.jsx b/src/GridDemo.jsx index 40b23304..8690b315 100644 --- a/src/GridDemo.jsx +++ b/src/GridDemo.jsx @@ -9,14 +9,8 @@ export function GridDemo() { const tileKey = useRef(0); const [stream, setStream] = useState(); const [tiles, setTiles] = useState([]); - const [tileStyles, setTileStyles] = useState({}); - - const [springs, api] = useSprings(tiles.length, (index) => ({ - from: { x: 0, y: 0, zIndex: 0, shadow: 1, scale: 1 }, - config: { - tension: 250, - }, - })); + const tilePositionsRef = useRef([]); + const draggingTileRef = useRef(null); const startWebcam = useCallback(async () => { const stream = await navigator.mediaDevices.getUserMedia({ video: true }); @@ -42,113 +36,234 @@ export function GridDemo() { const [gridRef, gridBounds] = useMeasure(); - useEffect(() => { - const newTileStyles = {}; - const tileCount = tiles.length; - const { width: gridWidth, height: gridHeight } = gridBounds; - const gap = 8; + // useEffect(() => { + // const newTilePositions = []; + // const tileCount = tiles.length; + // const { width: gridWidth, height: gridHeight } = gridBounds; + // const gap = 8; - if (tileCount > 0) { - const aspectRatio = gridWidth / gridHeight; + // if (tileCount > 0) { + // const aspectRatio = gridWidth / gridHeight; - let columnCount, rowCount; + // let columnCount, rowCount; - if (aspectRatio < 1) { - if (tileCount <= 4) { - columnCount = 1; - rowCount = tileCount; - } else if (tileCount <= 12) { - columnCount = 2; - rowCount = Math.ceil(tileCount / 2); - } - } else { - if (tileCount === 1) { - columnCount = 1; - rowCount = 1; - } else if (tileCount === 2) { - columnCount = 2; - rowCount = 1; - } else if (tileCount <= 4) { - columnCount = 2; - rowCount = 2; - } else if (tileCount <= 6) { - columnCount = 3; - rowCount = 2; - } else if (tileCount <= 8) { - columnCount = 4; - rowCount = 2; - } else if (tileCount <= 10) { - columnCount = 5; - rowCount = 2; - } else if (tileCount <= 12) { - columnCount = 4; - rowCount = 3; - } - } + // if (aspectRatio < 1) { + // if (tileCount <= 4) { + // columnCount = 1; + // rowCount = tileCount; + // } else if (tileCount <= 12) { + // columnCount = 2; + // rowCount = Math.ceil(tileCount / 2); + // } + // } else { + // if (tileCount === 1) { + // columnCount = 1; + // rowCount = 1; + // } else if (tileCount === 2) { + // columnCount = 2; + // rowCount = 1; + // } else if (tileCount <= 4) { + // columnCount = 2; + // rowCount = 2; + // } else if (tileCount <= 6) { + // columnCount = 3; + // rowCount = 2; + // } else if (tileCount <= 8) { + // columnCount = 4; + // rowCount = 2; + // } else if (tileCount <= 10) { + // columnCount = 5; + // rowCount = 2; + // } else if (tileCount <= 12) { + // columnCount = 4; + // rowCount = 3; + // } + // } - let tileHeight = Math.round( - (gridHeight - gap * (rowCount + 1)) / rowCount - ); - let tileWidth = Math.round( - (gridWidth - gap * (columnCount + 1)) / columnCount - ); + // let tileHeight = Math.round( + // (gridHeight - gap * (rowCount + 1)) / rowCount + // ); + // let tileWidth = Math.round( + // (gridWidth - gap * (columnCount + 1)) / columnCount + // ); - const tileAspectRatio = tileWidth / tileHeight; + // const tileAspectRatio = tileWidth / tileHeight; - if (tileAspectRatio > 16 / 9) { - tileWidth = (16 * tileHeight) / 9; - } + // if (tileAspectRatio > 16 / 9) { + // tileWidth = (16 * tileHeight) / 9; + // } - for (let i = 0; i < tiles.length; i++) { - const tile = tiles[i]; + // for (let i = 0; i < tiles.length; i++) { + // const verticalIndex = Math.floor(i / columnCount); + // const top = verticalIndex * tileHeight + (verticalIndex + 1) * gap; - const verticalIndex = Math.floor(i / columnCount); - const top = verticalIndex * tileHeight + (verticalIndex + 1) * gap; + // let rowItemCount; - let rowItemCount; + // if (verticalIndex + 1 === rowCount && tileCount % rowCount !== 0) { + // rowItemCount = Math.floor(tileCount / rowCount); + // } else { + // rowItemCount = Math.ceil(tileCount / rowCount); + // } - if (verticalIndex + 1 === rowCount && tileCount % rowCount !== 0) { - rowItemCount = Math.floor(tileCount / rowCount); + // const horizontalIndex = i % columnCount; + // const totalRowGapWidth = (rowItemCount + 1) * gap; + // const totalRowTileWidth = rowItemCount * tileWidth; + // const rowLeftMargin = Math.round( + // (gridWidth - (totalRowTileWidth + totalRowGapWidth)) / 2 + // ); + // const left = + // tileWidth * horizontalIndex + + // rowLeftMargin + + // (horizontalIndex + 1) * gap; + + // newTilePositions.push({ + // width: tileWidth, + // height: tileHeight, + // x: left, + // y: top, + // }); + // } + // } + + // tilePositionsRef.current = newTilePositions; + + // console.log("update tile positions", newTilePositions); + // }, [gridBounds, tiles]); + + const animate = useCallback( + (index) => { + const newTilePositions = []; + const tileCount = tiles.length; + const { width: gridWidth, height: gridHeight } = gridBounds; + const gap = 8; + + if (tileCount > 0) { + const aspectRatio = gridWidth / gridHeight; + + let columnCount, rowCount; + + if (aspectRatio < 1) { + if (tileCount <= 4) { + columnCount = 1; + rowCount = tileCount; + } else if (tileCount <= 12) { + columnCount = 2; + rowCount = Math.ceil(tileCount / 2); + } } else { - rowItemCount = Math.ceil(tileCount / rowCount); + if (tileCount === 1) { + columnCount = 1; + rowCount = 1; + } else if (tileCount === 2) { + columnCount = 2; + rowCount = 1; + } else if (tileCount <= 4) { + columnCount = 2; + rowCount = 2; + } else if (tileCount <= 6) { + columnCount = 3; + rowCount = 2; + } else if (tileCount <= 8) { + columnCount = 4; + rowCount = 2; + } else if (tileCount <= 10) { + columnCount = 5; + rowCount = 2; + } else if (tileCount <= 12) { + columnCount = 4; + rowCount = 3; + } } - const horizontalIndex = i % columnCount; - const totalRowGapWidth = (rowItemCount + 1) * gap; - const totalRowTileWidth = rowItemCount * tileWidth; - const rowLeftMargin = Math.round( - (gridWidth - (totalRowTileWidth + totalRowGapWidth)) / 2 + let tileHeight = Math.round( + (gridHeight - gap * (rowCount + 1)) / rowCount + ); + let tileWidth = Math.round( + (gridWidth - gap * (columnCount + 1)) / columnCount ); - const left = - tileWidth * horizontalIndex + - rowLeftMargin + - (horizontalIndex + 1) * gap; - newTileStyles[tile.key] = { - width: tileWidth, - height: tileHeight, - transform: `translate(${left}px, ${top}px)`, + const tileAspectRatio = tileWidth / tileHeight; + + if (tileAspectRatio > 16 / 9) { + tileWidth = (16 * tileHeight) / 9; + } + + for (let i = 0; i < tiles.length; i++) { + const verticalIndex = Math.floor(i / columnCount); + const top = verticalIndex * tileHeight + (verticalIndex + 1) * gap; + + let rowItemCount; + + if (verticalIndex + 1 === rowCount && tileCount % rowCount !== 0) { + rowItemCount = Math.floor(tileCount / rowCount); + } else { + rowItemCount = Math.ceil(tileCount / rowCount); + } + + const horizontalIndex = i % columnCount; + const totalRowGapWidth = (rowItemCount + 1) * gap; + const totalRowTileWidth = rowItemCount * tileWidth; + const rowLeftMargin = Math.round( + (gridWidth - (totalRowTileWidth + totalRowGapWidth)) / 2 + ); + const left = + tileWidth * horizontalIndex + + rowLeftMargin + + (horizontalIndex + 1) * gap; + + newTilePositions.push({ + width: tileWidth, + height: tileHeight, + x: left, + y: top, + }); + } + } + + tilePositionsRef.current = newTilePositions; + const tilePosition = tilePositionsRef.current[index]; + const draggingTile = draggingTileRef.current; + const dragging = + draggingTileRef.current && index === draggingTileRef.current.index; + + if (dragging) { + return { + width: tilePosition.width, + height: tilePosition.height, + x: tilePosition.x + draggingTile.x, + y: tilePosition.y + draggingTile.y, + scale: 1.1, + zIndex: 1, + shadow: 15, + immediate: (key) => key === "zIndex" || key === "x" || key === "y", + }; + } else { + return { + ...tilePosition, + scale: 1, + zIndex: 0, + shadow: 1, + immediate: false, }; } + }, + [tiles, gridBounds] + ); + + const [springs, api] = useSprings(tiles.length, animate, [tiles, gridBounds]); + + const bind = useDrag(({ args: [index], active, movement: [x, y] }) => { + if (active) { + draggingTileRef.current = { + index, + x, + y, + }; + } else { + draggingTileRef.current = null; } - setTileStyles(newTileStyles); - }, [gridBounds, tiles]); - - const bind = useDrag(({ args: [index], down, movement: [x, y] }) => { - api.start((springIndex) => { - const dragging = springIndex === index && down; - return { - x: dragging ? x : 0, - y: dragging ? y : 0, - scale: dragging ? 1.1 : 1, - zIndex: dragging ? 1 : 0, - shadow: dragging ? 15 : 1, - immediate: dragging - ? (key) => key === "zIndex" || key === "x" || key === "y" - : false, - }; - }); + api.start(animate); }); return ( @@ -159,20 +274,14 @@ export function GridDemo() { {stream && }
- {springs.map(({ shadow, ...springStyles }, i) => { + {springs.map((style, i) => { const tile = tiles[i]; return ( `rgba(0, 0, 0, 0.5) 0px ${s}px ${2 * s}px 0px` - ), - }} + style={style} {...tile} /> ); diff --git a/src/GridDemo.module.css b/src/GridDemo.module.css index 72d23cd5..7e71c6ea 100644 --- a/src/GridDemo.module.css +++ b/src/GridDemo.module.css @@ -17,7 +17,7 @@ .participantTile { position: absolute; - will-change: transform, width, height, opacity; + will-change: transform, width, height, opacity, box-shadow; border-radius: 24px; overflow: hidden; }