Building a Canvas Slider with React Konva

I was recently tasked with building an application that allows users to interact with product configurations on an HTML canvas. While using the app, users will be able to:

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

After an extensive search for example code that could provide a frame for the canvas, I came up with zero results. This of course meant I had to build the functionality from scratch. I found it to be a difficult task.

However, when I broke down the requirements, I realized it wasn’t that hard to conceptualize. In fact, the main parameters of canvas requirements can be divided into four steps.

  1. Build the basic structure of the HTML canvas
  2. Place the images on the canvas offset from each other
  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

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

Canvas scaffolding

i used Create the React app to make a quick example project. Then I added dependencies Respond to Conva.

I’ve created draggable elements (stars in this example) 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 can then be used to drag the product images onto the final HTML canvas.

Step 2: Placing images on the canvas

The next step was to add the images that will be displayed in the slideshow. This can be done 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 slide images and image dimensions.
  3. Add an image component that handles the rendering of image files on the canvas. When we added the image component, we also had to add the “use-image” package according to Respond to Konva prompts.

Then the existing App.tsx code was 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 herethree retractable images were presented on the canvas.

Step 3: Adding the ability to swipe between images

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

  • Prevent users from swiping left when they are at the beginning of images
  • Prevent users from swiping just when they were at the end of pictures
  • Make sure that when the user stops scrolling through two images on the screen, the app will automatically focus on one image

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

  1. Add “onDragMove” to prevent both vertical scrolling and scrolling over canvas edges. This ensured that users could only scroll horizontally between images on the canvas.
  2. Add “onDragEnd” to automatically bring the active slide back to the center of the user’s canvas when scrolling is stopped. This prevented the user from getting stuck with two partial images on their screen.
  3. Add a few things to help make sure the slide state and positions are created correctly. These included a placeholder 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 has been 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: Added ability to use navigation buttons to move between images

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

  1. Add a reference to the slide group 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 the navigation button is selected (handleChangeSlide)
  3. Add “useEffect” to make sure the selected image stays centered on the canvas when the screen size is resized.
  4. Add some basic styles to update the navigation look.

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>

After the navigation bar was complete, I had a product instance that contained all the elements the customer requested. You can see the finished product here.

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

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

Source link