0

I'm working on an image gallery, when the user clicks on a photo in the gallery the photo will do a 3D animation to the center of the screen, something like this:

const style = this.state.expanded ? {
            transform: 'translate3d(' + this.state.xOffset + 'px, ' + this.state.yOffset + 'px, 10em) scale(2)',
            transition: theme.transitions.create('transform')
        } : {
                transform: 'translate3d(0px, 0px, 0px)',
                transition: theme.transitions.create('transform')
            }

That style is applied to every image in the gallery, something like:

//react-virtualized grid of: <div ref={this.divElement} style={style as any}> {...etc}</div>

This works fine except 'zIndex' is not respected when transform is applied. I've tried setting a z offset to the translate3D to no avail.

All I really want is for the expanded image to render last and on top of all the other cards.

Here's the root react virtualized component:

class MasonryComponent extends React.Component<IMasonryProps, IMasonryState>
{
    state = {
        columns: 3
    }
    _cellPositioner: Positioner | undefined = undefined

    // Default sizes help Masonry decide how many images to batch-measure
    cache = new CellMeasurerCache({
        defaultHeight,
        defaultWidth,
        fixedWidth: true
    });

    columnWidth = () => {
        const { columnWidth, width } = this.props;

        // const newW = width > columnWidth ? columnWidth : width;

        return width > columnWidth ? columnWidth : width;
    }

    _initCellPositioner = () => {
        const columnWidth = this.columnWidth()
        if (typeof this._cellPositioner === 'undefined') {
            this._cellPositioner = createMasonryCellPositioner({
                cellMeasurerCache: this.cache,
                columnCount: this.state.columns,
                columnWidth,
                spacer: gutter,
            });
        }
    }

    componentWillReceiveProps(nextProps: IMasonryProps) {
        if (JSON.stringify(nextProps.items) !== JSON.stringify(this.props.items)) {
            this._masonry.current!.clearCellPositions();

            this.cache.clearAll();
            this.cellPositioner(this.props.width);
            this._masonry.current!.clearCellPositions();
        }
    }

    cellPositioner = (width: number): Positioner => {
        const columnWidth = this.columnWidth()
        const columns = Math.floor(width / columnWidth);
        if (this.state.columns != columns)
            this.setState({ columns: columns });

        this._cellPositioner!.reset({
            columnCount: columns,
            columnWidth: columnWidth,
            spacer: gutter
        })

        if (this._masonry.current)
            this._masonry.current.recomputeCellPositions();


        return this._cellPositioner!
    }
    _masonry = React.createRef<Masonry>()

    cellRenderer = ({ index, key, parent, style }: any) => {
        const props = this.props;
        if (!props.items[index])
            return <div>404</div>

        const item = props.items[index];
        let customRender = props.customRender;

        const size = this.props.imageSizeResolve(item);
        const columnWidth = this.columnWidth()
        return (
            <CellMeasurer cache={this.cache} index={index} key={key} parent={parent}>
                {customRender ? customRender(item, style, columnWidth) :
                    <div style={style}>
                        <img
                            src={item.url}
                            style={{
                                width: columnWidth,
                                height: columnWidth / size.width * size.height
                            }}
                        />
                    </div>}
            </CellMeasurer>
        );
    }
    public render() {
        const props = this.props;

        this._initCellPositioner();

        const columnWidth = this.columnWidth()
        let paddingLeft = props.width < columnWidth ? 0 : (props.width - (columnWidth + gutter) * this.state.columns) / 2
        if (paddingLeft < 0) {
            paddingLeft = 0;
        }
        return (
            <Masonry
                style={{
                    paddingLeft
                }}
                overscanByPixels={1080}
                ref={this._masonry}
                autoHeight={false}
                cellCount={props.items ? props.items.length : 0}
                cellMeasurerCache={this.cache}
                cellPositioner={this.cellPositioner(props.width)}
                cellRenderer={this.cellRenderer}
                height={props.height}
                width={props.width}
            />
        );
    }
};

Anyway to accomplish this?

meds
  • 21,699
  • 37
  • 163
  • 314
  • can you attach rendered DOM part that holds it? –  Dec 29 '18 at 09:00
  • @mkbctrl since I'm using react-virtualized the rendering isn't done directly by me, I've attached the virtualized component, cellRenderer is where it's ultimately rendered from... – meds Dec 29 '18 at 09:02
  • 1
    oh, pitty. Usually when I have simillar problem with `z-index`, taking a look at the DOM helps me figure it out. Still, I will try to help, maybe smth will stand out. –  Dec 29 '18 at 09:17
  • take a look here, maybe that one will aid: https://stackoverflow.com/questions/20851452/z-index-is-canceled-by-setting-transformrotate –  Dec 29 '18 at 09:20
  • Did you try to set `zIndex` with the new transform? Just thinking out loud, but if you read this part of attached response: `Note that after removing .test's -webkit-transform rule you can, once again, give it its own stacking context by setting a new z-index rule (any value) on .test (again, because it is positioned)! ` it actually start to make sense –  Dec 29 '18 at 09:25
  • unfortunately that's only solving the issue when there's items inside the div element being transformed, in my case the div item being transformed is independent of the other divs I want it to be in front of – meds Dec 29 '18 at 09:32
  • can you link me a screnshot? –  Dec 29 '18 at 09:44

0 Answers0