Building A Canvas Slideshow with React Konva

by

Recently, I was tasked with building an application that allowed users to interact with product configurations on an HTML canvas. When using the app, users would be able to: 

  • Drag and drop different products on the canvas
  • Move and reorder products
  • Easily change between the main product images using navigation buttons or by swiping left and right. 

After searching extensively for a code example that could provide a framework for the canvas, I came up with zero results. This meant, of course, that I would need to build the functionality from scratch. It felt like a daunting task. 

However, when I broke down the requirements, I realized it wasn’t that difficult to conceptualize. In fact, the basic parameters for the canvas requirements could be divided into four steps: 

  1. Build the basic HTML canvas structure
  2. Place the images on the canvas offset from one another
  3. Add the ability to swipe left or right between images
  4. Add the ability to use navigation buttons to move between images

Step 1: Building the Basic HMTL Canvas Structure

As this was a React project, I used React Konva for the HTML canvas and all application functionality. React Konva is an HTML5 Canvas JavaScript framework for building desktop and mobile applications. Using React Konva provided declarative and reactive bindings to the Konva framework. 

Scaffolding the Canvas

I used Create React App to make a quick example project. Then I added dependencies for React Konva.

I created draggable elements (in this example, stars) for the canvas by updating the App.tsx file with the code below: 

<iframe src="https://codesandbox.io/embed/1-scaffold-canvas-ul6xnt?fontsize=14&hidenavigation=1&theme=dark"
     style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
     title="1-scaffold-canvas"
     allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
     sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
   ></iframe>

You can see what the stars look like on the canvas here.  

The code for these draggable elements could then be used to make the product images draggable on the final HTML canvas. 

Step 2: Placing the Images on the Canvas

The next step was adding the images that would be rendered in the slideshow. This could be accomplished with the following steps: 

  1. Add the images to the public directory at the root of the project directory. 
  2. Add the constants file. This file includes both the slide images and the image dimensions. 
  3. Add an image component that handles rendering the image files on the canvas. When we added the image component, we also had to add the package `use-image` per the React Konva instructions

The existing App.tsx code was then replaced with the following: 

<iframe src="https://codesandbox.io/embed/2a-add-images-oqij4o?fontsize=14&hidenavigation=1&theme=dark"
     style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
     title="2a-add-images"
     allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
     sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
   ></iframe>

As you can see here, three draggable images were rendered on the canvas. 

Step 3: Adding The Ability to Swipe Between Images

The draggable images were now rendered side-by-side on the canvas, but they still needed a lot more work to function as expected. In addition to being able to swipe between images, I needed to:

  • Prevent users from swiping left when they were at the beginning of the images
  • Prevent users from swiping right when they were at the end of the images
  • Ensure that when the user stopped swiping with two images on the screen, the program automatically centered on one image

To achieve these goals, I tapped into the canvas API using a few event props with callbacks for the grouped images and followed these steps:  

  1. Add `onDragMove` to prevent both vertical scrolling and scrolling past the edges of the canvas. This ensured that users could only scroll horizontally between the canvas images. 
  2. Add `onDragEnd` to automatically snap the active slide back into the center of the user’s canvas when the scrolling was stopped. This prevented the user from getting stuck with two partial images on their screen. 
  3. Add a few things to help ensure that the slide state and positions were set up properly. These included a place to reference the active slide (activeSlideId), a handler that sets the active slide (handleSetActiveSlideId), and a function that retrieves the slide properties for each slide (getSlideProperties).

The code was updated as follows: 

<iframe src="https://codesandbox.io/embed/2b-add-some-control-to-images-czmmz6?fontsize=14&hidenavigation=1&theme=dark"
     style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
     title="2b-add-some-control-to-images"
     allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
     sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
   ></iframe>

The HTML canvas now had three images that could easily be swiped left and right, as seen here

Step 4: Adding the Ability to Use Navigation Buttons to Move Between Images 

Though swiping was a useful feature, the client also requested that navigation controls be added to the user interface (UI). Since I had already captured the active slide index, I just needed to add a few things to capture the index change and animate the images when a new index was selected. I achieved this with the following steps: 

  1. Add a reference for the group of slides using `useRef` and add the reference to the group element that wraps the image slides (slideGroupRef).
  2. Add a function that sets the current slide when a navigation button is selected (handleChangeSlide)
  3. Add `useEffect` to ensure that the selected image remained centered in the canvas when the screen was resized. 
  4. Add some basic styles to update the navigation appearance. 

The updated code for the navigation buttons looked like this: 

<iframe src="https://codesandbox.io/embed/3-navigation-controls-76c615?fontsize=14&hidenavigation=1&theme=dark"
     style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
     title="3-navigation-controls"
     allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
     sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
   ></iframe>

Once the navigation bar was complete, I had an example product that contained all of the elements that the client requested. You can see the finished product here.

I was then able to take the elements of this example and turn it into the client’s HTML canvas. Because we designed the canvas ourselves, we were able to customize it to our client’s needs so that they had a product we knew they would love. 

You can learn more about Grio’s other projects by checking out Our Work

Leave a Reply

Your email address will not be published. Required fields are marked