Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamically measured images example #1081

Merged
merged 1 commit into from
May 11, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
103 changes: 103 additions & 0 deletions docs/Masonry.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,106 @@ ReactDOM.render(
document.getElementById('example')
);
```

### Masonry example with dynamically measured images

Items in the list in basic example can only be measured once, which means client has to know all the
sizes upfront before displaying. For cases when server cannot deliver such data we need to
pre-measure images. In order to preserve correct optimized layout images can only be displayed one
by one in the order they appear in the array, not in the order they are loaded.

These specifics were taken into account in a small library
[react-virtualized-image-measurer](https://github.com/kirill-konshin/react-virtualized-image-measurer)
here is an example with dynamically measured images:

```js
import React from "react";
import { render } from "react-dom";
import {
CellMeasurer,
CellMeasurerCache,
createMasonryCellPositioner,
Masonry
} from "react-virtualized";
import ImageMeasurer from "react-virtualized-image-measurer";

// Array of images with captions
//const list = [{image: 'http://...', title: 'Foo'}];

// We need to make sure images are loaded from scratch every time for this demo
const noCacheList = list.map(item => ({
...item,
image: item.image + "?noCache=" + Math.random()
}));

const columnWidth = 200;
const defaultHeight = 250;
const defaultWidth = columnWidth;

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

// Our masonry layout will use 3 columns with a 10px gutter between
const cellPositioner = createMasonryCellPositioner({
cellMeasurerCache: cache,
columnCount: 3,
columnWidth,
spacer: 10
});

const MasonryComponent = ({ itemsWithSizes }) => {

function cellRenderer({ index, key, parent, style }) {
const { item, size } = itemsWithSizes[index];
const height = columnWidth * (size.height / size.width) || defaultHeight;

return (
<CellMeasurer cache={cache} index={index} key={key} parent={parent}>
<div style={style}>
<img
src={item.image}
alt={item.title}
style={{
height: height,
width: columnWidth
}}
/>
<h4>{item.title}</h4>
</div>
</CellMeasurer>
);
}

return (
<Masonry
cellCount={itemsWithSizes.length}
cellMeasurerCache={cache}
cellPositioner={cellPositioner}
cellRenderer={cellRenderer}
height={600}
width={800}
/>
);
};

// Render your grid
render(
<ImageMeasurer
items={noCacheList}
image={item => item.image}
defaultHeight={defaultHeight}
defaultWidth={defaultWidth}
>
{({ itemsWithSizes }) => (
<MasonryComponent itemsWithSizes={itemsWithSizes} />
)}
</ImageMeasurer>,
document.getElementById("root")
);
```

Live demo: https://codesandbox.io/s/7y66p25qv6