Dynamic Image Collages in React JS

R. Wolf
Philosophie is Thinking
4 min readSep 5, 2017

Background

For one of our current projects here at Philosophie, we ran into an interesting engineering challenge that dealt with building a dynamic image collage from multiple smaller images. We’re working on a chat application for a large fashion retailer, built on Ruby on Rails and React, and part of the core brand experience is a stylist being able to send groups of items to users for their perusal within a chat. We didn’t want the experience just to be a stylist sending over a sequential list of products to a user, but wanted to present them in an engaging, brand-focused way.

Working with the design team, we came up with an experience wherein the stylist would be able to group a series product images together in a single collage and send that to a client. The mockup ended up looking something like this:

Note: this image shows 3 items, but design research showed us that this image collage system needed to be able to handle any number of product images.

This presented some interesting engineering challenges not only on the engineering side, but on the human side as well.

Engineering:

  1. How might we render this? Runtime (client-side) or server-side?
  2. How might we accommodate a variable amount of images?
  3. What would the DSL look like?
  4. How we resize images?

Human:

  1. How might we build a DSL that allows designers to modify this layout?
  2. How might we build this within our tight timeline?
  3. How might we build this within our knowledge constraints?

Attempt Number 1

Our first attempt at solving this was to build the image collages server-side. For image processing we tried out Rmagick, a library of Ruby bindings for the image processing library ImageMagick. We reasoned that we’d be able to build the images server-side and then pass them to the client via an internal API call. This ended up not being feasible for a few reasons:

  1. We didn’t have have enough experience with Rmagick and its API to build out the complexity of this feature.
  2. Somewhat related to point 1, the API documentation for Rmagick is robust and ergo time-consuming to decipher; unfortunately we are on a tight timeline with this project and getting onboarded to understanding Rmagick just wasn’t possible.
  3. Because this would be happening server-side, we’d need to upload the images using a service like S3 and have the client fetch these via the uploaded images’ URLs. We didn’t have the timeline space, nor the resources, to build that out.

This ultimately taught us a lot and helped us better understand the requirements for a solution. Namely:

  1. It had to render at runtime (on the client application).
  2. It had to use an library that we were familiar with.
  3. It couldn’t use file uploads (at least for now).

Attempt Number 2: Electric Boogaloo

This led us to decide on using the HTML5 Canvas API to build this feature out, such that we’d be able to render these dynamic collages off of an abstracted basic DSL at runtime.

Here’s an example of a React component that implements this functionality. The component is passed an array of imageUrls as a prop, and then builds the dynamic image collage in Canvas off of those in conjunction with the logic delineated in the Javascript object imageSizesByItemCount (lines 10–25). This object serves as our simple DSL in which a developer or designer can specify the number of images to be rendered and information about where they are positioned (via x and y offsets) and resizing logic for keeping images proportional.

As an example, if we pass in the following images’ (from Unsplash) locations to this component, we will get:

A couple of notes on this:

  1. The imageSizesByItemCount DSL object should not be operating off of string keys at the object root. This is a spike that we just finished, in the final build imageSizesByItemCount will probably be an array of objects with these objects’ indexes in the array corresponding to the number of images to be rendered (or something along those lines).
  2. Similarly to point #1, in lines 33 & 34 we obviously shouldn’t be indexing in to the imageSizesByItemCount DSL object with a hardcoded root key, but again this is a spike.

I think this was a great way to use a simple code structure to solve a complex engineering problem in an MVP-style way. Engineering isn’t just coding in isolation, it’s balancing problem-solving with timeline, skillsets, feasibility, etc. Challenges like these are good refreshers on how to use simple, creative problem-solving to deliver on challenging engineering work.

--

--