Zoom and Rotate Image in ReactJS

Banner for a MediaJam post

Christian Nwamba

Zooming means enlarging an image so that the details in the image become more visible and apparent. Zooming a picture has many wide applications ranging from zooming through a camera lens to zooming on a photo on the internet, e.t.c.

On the other hand, Rotate is an image processing feature that allows us to turn an image in a clockwise or counterclockwise direction.

In this post, we'll learn how to zoom and rotate the image with React-image-zoom package, Cloudinary, and React.js.

React-image-zooom is an npm package that will allow users to zoom in on images. This component has minimal styling footprint. In addition, we can pass in custom class names and id props that'll enable us to customise the package to fit our design needs.

Cloudinary is a platform on which we can upload, store, manage, transform, and deliver images and videos for web and mobile applications.

Sandbox

The complete project is on CodeSandbox. Fork and run it to quickly get started.

https://codesandbox.io/embed/focused-pare-kx8jdl?fontsize=14&hidenavigation=1&theme=dark

Prerequisites

This post requires the following:

  • Experience with JavaScript and react.js
  • Installation of Node.js
  • A Cloudinary account. Signup is free!

Setups and Installations

We will run the following command in the terminal to create a new React.js application:

1npx create-react-app zoom-rotate-app

The above command bootstraps a react application in ****the zoom-rotate folder.

Next, we'll navigate into the project directory and install some dependencies:

1cd zoom-rotate # to navigate into the project directory

Navigate to the src directory and delete all the files except App.js and index.js

Next, we'll install the following npm packages:

1npm install react-image-zooom @cloudinary/url-gen react-icons

or

1yarn add react-image-zooom @cloudinary/url-gen react-icons

Next, we'll install the bootstrap library with the following command to handle our styles.

1npm install react-bootstrap bootstrap

Next, we'll log in to cloudinary, navigate to the samples folder and navigate to people and tag a few images.

Create a tag name and click on the Update button.

Next, we'll provide our details in this URL format and query it to get our cloudinary tagged assets:

1https://res.cloudinary.com/<cloud-name>/<type>/list/<tag-name>.json

Next, we’ll remove restrictions on Image list in cloudinary. Navigate to settings (the gear icon), click on the Security tab and uncheck Resource List under Restricted media types.

Scroll down to save settings.

Next, import the following line of code inside the pages/index.js file:

1import "bootstrap/dist/css/bootstrap.min.css";

Your index.js should look like this:

1//index.js
2import React from 'react';
3import ReactDOM from 'react-dom/client';
4import App from './App';
5import "bootstrap/dist/css/bootstrap.min.css";
6
7const root = ReactDOM.createRoot(document.getElementById('root'));
8 root.render(
9 <React.StrictMode>
10 <App />
11 </React.StrictMode>
12 );

Building the Zoom Effect

Now, clean up the App.js file and update it with the following lines of code :

1import "./App.css";
2import ImageZoom from "react-image-zooom";
3import { useState, useEffect } from "react";
4
5const App = () => {
6 const [imageData, setImageData] = useState(null);
7
8 const baseURL = "https://res.cloudinary.com/<cloud-name>/image";
9
10 const getImages = async () => {
11 const res = await fetch(
12 "https://res.cloudinary.com/<cloud-name>/image/list/<tag-name>.json"
13 );
14 const data = await res.json();
15 setImageData(data);
16 };
17
18
19return (
20 <div className="App">
21 <h1>ZOOM and Roatate Images in React.js</h1>
22 <div className="gallery">
23 {imageData &&
24 imageData.resources.map((item) => {
25 const { format, public_id, version, type } = item;
26 return (
27 <div key={version} className="gallery-img">
28 <ImageZoom
29 src={`${baseURL}/${type}/v${version}/${public_id}.${format}`}
30 alt="Zoom-images"
31 zoom="300"
32 />
33 </div>
34 );
35 })}
36 </div>
37 </div>
38);
39};
40export default App;

In the snippets above, we:

  • Imported ImageZoom from "react-image-zooom" and useState and useEffect from “react”.
  • Created imageData state constant with useState hook and created a baseURL constant.
  • Created the getImages() function to fetch the tagged assets from Cloudinary and update the imageData state.
  • Looped through the imageData, generated a URL for the images, and used the ImageZoom component and display them.

We would see our images rendered with zoom-in and zoom-out functionalities in the browser.

Building the Rotate Effect

First, let's head to Cloudinary media library, and double click on any image asset and copy the image directory.

Next, update the App.js with the following snippets:

1//App.js
2...
3import { Cloudinary } from "@cloudinary/url-gen";
4import { byAngle } from "@cloudinary/url-gen/actions/rotate";
5import { BsArrowClockwise, BsArrowCounterclockwise } from "react-icons/bs";
6
7const App = () => {
8 ...
9 const [imageURL, setImageURL] = useState();
10 const [rotateValue, setRotateValue] = useState(0);
11
12 const rotateImages = () => {
13 const cld = new Cloudinary({
14 cloud: {
15 cloudName: "cloud-name",
16 },
17 });
18 const rotateImg = cld
19 .image("image directory here")
20 .rotate(byAngle(rotateValue));
21 setImageURL(rotateImg.toURL());
22 };
23
24 ...
25
26useEffect(() => {
27 ...
28 rotateImages();
29});
30
31return (
32 <div className="App">
33 <h1>Zoom and Roatate Images in React.js</h1>
34 <div className="gallery">
35 ...
36 </div>
37
38 <div className="rotate">
39 <img src={imageURL} alt="snow-boy" width={500} height={500} />
40 <div className="controls m-3">
41 <button
42 onClick={() => setRotateValue(rotateValue - 90)}
43 className="m-1 btn-primary"
44 >
45 <BsArrowCounterclockwise />
46 </button>
47 <button
48 onClick={() => setRotateValue(rotateValue + 90)}
49 className="m-1 btn-primary"
50 >
51 <BsArrowClockwise />
52 </button>
53 </div>
54 </div>
55 </div>
56 );
57};
58export default App;

In the snippets above, we:

  • Imported Cloudinary and byAngle rotate actions from "@cloudinary/url-gen."
  • Imported Clockwise and CounterClockwise arrows from react-icons and created imageURL and rotateValue state constants.
  • Created the rotateImages() function and inside it, instantiated a new instance of Cloudinary and passed our cloud name.
  • Created the rotateImg constant, targeted our image asset, called the rotate() and byAngle() functions on it. Then passed the rotateValue state and updated the imageURL state.
  • Rendered the imageURL in an img tag and rendered the Counterclockwise and Clockwise arrows with an onClick() function that will decrease or increase the rotateValue state.

Your App.js should look like this:

1//App.js
2import "./styles.css";
3import ImageZoom from "react-image-zooom";
4import { useState, useEffect } from "react";
5import { Cloudinary } from "@cloudinary/url-gen";
6import { byAngle } from "@cloudinary/url-gen/actions/rotate";
7import { BsArrowClockwise, BsArrowCounterclockwise } from "react-icons/bs";
8
9const App = () => {
10 const [imageData, setImageData] = useState(null);
11 const [imageURL, setImageURL] = useState();
12 const [rotateValue, setRotateValue] = useState(0);
13 const rotateImages = () => {
14 const cld = new Cloudinary({
15 cloud: {
16 cloudName: "cloud-name"
17 }
18 });
19
20 const rotateImg = cld
21 .image("image directory here")
22 .rotate(byAngle(rotateValue));
23 setImageURL(rotateImg.toURL());
24 };
25
26 const baseURL = "https://res.cloudinary.com/<cloud-name>/image";
27 const getImages = async () => {
28 const res = await fetch(
29 "https://res.cloudinary.com/<cloud-name>/image/list/<tag-name>.json"
30 );
31 const data = await res.json();
32 setImageData(data);
33 };
34
35useEffect(() => {
36 getImages();
37 rotateImages();
38});
39
40return (
41 <div className="App">
42 <h1>Zoom and Rotate Images in React.js</h1>
43 <div className="gallery">
44 {imageData &&
45 imageData.resources.map((item) => {
46 const { format, public_id, version, type } = item;
47 return (
48 <div key={version} className="gallery-img">
49 <ImageZoom
50 src={`${baseURL}/${type}/v${version}/${public_id}.${format}`}
51 alt="Zoom-images"
52 zoom="300"
53 />
54 </div>
55 );
56 })}
57 </div>
58 <div className="rotate">
59 <img src={imageURL} alt="snow-boy" width={500} height={500} />
60 <div className="controls m-3">
61 <button
62 onClick={() => setRotateValue(rotateValue - 90)}
63 className="m-1 btn-primary"
64 >
65 <BsArrowCounterclockwise />
66 </button>
67 <button
68 onClick={() => setRotateValue(rotateValue + 90)}
69 className="m-1 btn-primary"
70 >
71 <BsArrowClockwise />
72 </button>
73 </div>
74 </div>
75 </div>
76 );
77};
78export default App;

We will have the zoom and rotate functionalities working on the images in the browser as expected.

Conclusion

In this post, we discussed how to implement zoom and rotating image functionalities using cloudinary, React-image-zooom and React.

Resources

The following resource might be helpful:

Christian Nwamba

Developer Advocate at AWS

A software engineer and developer advocate. I love to research and talk about web technologies and how to delight customers with them.