Arrange images in a responsive, progressive-loading grid managed in JavaScript using CSS transforms.
A re-implementation of @schlosser's pig.js in React.
Instead of hosting images locally I've used Cloudinary - an image hosting provider, which adds the benefit of on-the-fly image resizing. So we don't need to worry about managing/generating multiple versions of an image at different resolutions. Like the original version of Pig.js we still need to provide an array of objects containing metadata about each image. I've created a node script upload.js
to do this for us, see below section on upload.js
.
In addition each image is now clickable and will expand to the center of the screen. It uses React Spring to handle the transition.
Using this file assumes you are using Cloudinary as your image hosting provider. You could take the concepts within it and write it for your own image hosting provider of choice.
Running the file will;
- Loop through a local folder of images and uploads them all to Cloudinary
- Generates metadata for each image, including url, aspectRatio, dominant colour (useful for preload styling), file birthtime (useful for sorting photos by date) and exif data.
- On completion of the upload, it generates a JSON file containing metadata about the collection of images. This JSON file can then be plugged into Pig.
To use upload.js
- Create a Cloudinary account.
- Create a file named
.env
and save it in the same folder asupload.js
. Paste in the following with your Cloudinary credentials filled out;
cloud_name="abc123"
api_key="1234567890"
api_secret="yourapisecret"
- Run the file thusly
node upload --in=./imgs/ --out=./imageData.json --cloudinaryFolder=whatever
--in
- your local folder where your images are at--out
- the output JSON file--cloudinaryFolder
- the folder in Cloudinary (optional)
The Apple Photos app conveniently has a feature where it can export your photos into folders named with location and date. upload.js
will use these folder names to automatically add location
and date
meta data to the images. This is useful for grouping images later. To export your images from Apple Photos;
- Select all images to export
- File -> Export -> Export Photos -> Filename: Use Title & Subfolder Format: Moment Name
- When running upload.js just point it at the generated folder.
This file can be used if you've already uploaded your images to Cloudinary and just want to generate the JSON file for them. Assuming you have a Cloudinary account and have set up your .env file accordingly, you can run this file with;
node generateJSON --cloudinaryFolder=whateverFolderYouWantJsonFor --out=./outputFilename.json
yarn add react-pig
# or
npm i react-pig
import Pig from 'react-pig'
import imageData from './imageData.json' // the file generated by upload.js
class App extends Component {
render() {
return (
<Pig
imageData={imageData} // Array. Required.
groupByDate // Boolean. Optional. Groups images by 'date' value. And uses the first 'location' in the group for the heading text.
gridGap={10} // Integer. Optional. Defaults to 8
expandedSize={1600} // Integer. Optional. Expanded image will be loaded in that size. Defaults to 1000
thumbnailSize={25} // Integer. Optional. Thumbnail image will be loaded in that size. Defaults to 10
sortFunc={(a, b) => a.imageOrder > b.imageOrder} // Function. Optional. Used for sorting images f.ex. if you add custom fields to the json file
bgColor="#fff" // String. Optional. Used for outlines when image is expanded, and for group headings
getUrl={(url, pxHeight) => {
// Pig calls this function every time it needs to fetch an image.
// The url arg will be provided as is from imageData
// Assuming the imageData was generated using upload.js, the url string will contain {{HEIGHT}}
// The purpose of this function is to replace {{HEIGHT}} value with a dynamic value (which is passed in with pxHeight)
// Eg this:
// http://res.cloudinary.com/cloudinaryusername/image/upload/h_{{HEIGHT}}/v12345678/cloudinaryfolder/image.jpg
// Becomes this:
// http://res.cloudinary.com/cloudinaryusername/image/upload/h_800/v12345678/cloudinaryfolder/image.jpg
// This gives you flexibility to define what the url looks like in case you're using something other than Cloudinary.
// getUrl is optional.
// If you omit this prop completely, Pig will do exactly this;
}}
/>
)
}
}
export default App
- Tests
- Clear up readme
- Fix group heading text alignment
- Possibly provide a value to group by?
- Conditional rendering based on users scroll speed
- Dont expand if expanded size is less than container width
- expanded tile outline based on gridgap
- Group by months
- bug: resizing isn't setting width correctly in tile
- Use resize observer instead of scroll/resize listeners
- Convert this package into a module
- Proptype checks
This React library was packaged with https://github.com/transitive-bullshit/create-react-library
MIT © nickmcmillan