DEV Community

KenjiGoh
KenjiGoh

Posted on

React - Image Editor

React - Image Editor

This post is inspired by this npm library react-image-pan-zoom-rotate

Instead of reading this, you can simply install the library add the following lines of code to the App.js.

import PanViewer from "react-image-pan-zoom-rotate";
<PanViewer image={imageURL} alt="cool" />
Enter fullscreen mode Exit fullscreen mode

Alternatively, let's try creating our own component.

I have rewritten the code using React useState hooks and styled-components, but only with rotate-left and flip horizontal or vertical options.

1. Create the styled-components wrappers

I like to use styled-components as we can pass in props.

import React, { useState } from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";

const ToolBarContainer = styled.div`
  position: absolute;
  right: 20%;
  z-index: 2;
  top: 20px;
  user-select: none;
  border-radius: 2px;
  background: rgb(255, 255, 255);
  box-shadow: rgb(53 67 93 / 32%) 0px 2px 6px;
`;

const ToolBarItem = styled.div`
  text-align: center;
  cursor: pointer;
  height: 40px;
  width: 40px;
  border-bottom: 1px solid rgb(204, 204, 204);
`;

// Main part is here, where we manipulate the image by passing in props to transform it's style
const ImgContainer = styled.img`
  width: 500px;
  transform: scaleY(${(props) => props.flipY}) scaleX(${(props) => props.flipX})
    rotate(${(props) => props.rotation * 90}deg)
`;

// this is not styled-components, just for styling of the fas-icons in the toolbars box
const iconStyle = {
  height: "100%",
  width: "100%",
  padding: 10,
  boxSizing: "border-box",
};

Enter fullscreen mode Exit fullscreen mode

2. Create the React Components

Define useState hooks and create a ImageContainer and ToolbarContainer.

const ImagePortal = (props) => {
  const [flipX, setFlipX] = useState(1);
  const [flipY, setFlipY] = useState(1);
  const [rotation, setRotation] = useState(0);

  const flipImageX = () => {
    if (flipX === 1) {
      setFlipX(-1);
    }
    if (flipX === -1) {
      setFlipX(1);
    }
  };

  const flipImageY = () => {
    if (flipY === 1) {
      setFlipY(-1);
    }
    if (flipY === -1) {
      setFlipY(1);
    }
  };

  const rotateLeft = () => {
    if (rotation === -3) {
      setRotation(0);
    } else {
      setRotation(rotation - 1);
    }
  };

  const resetAll = () => {
    setRotation(0);
    setFlipY(1);
    setFlipX(1);
  };

  return(
    <>
      <ImgContainer
        src={props.image}
        alt="test"
        rotation={rotation}
        flipX={flipX}
        flipY={flipY}
      />

      <ToolBarContainer>
        <ToolBarItem>
          <i
            className="fas fa-rotate-left"
            onClick={rotateLeft}
            style={iconStyle}
          ></i>
        </ToolBarItem>

        <ToolBarItem>
          <i
            className="fa-solid fa-arrows-left-right"
            onClick={flipImageX}
            style={iconStyle}
          ></i>
        </ToolBarItem>

        <ToolBarItem>
          <i
            className="fa-solid fa-arrows-up-down"
            onClick={flipImageY}
            style={iconStyle}
          ></i>
        </ToolBarItem>

        <ToolBarItem>
          <i className="fas fa-repeat" onClick={resetAll} style={iconStyle}></i>
        </ToolBarItem>
      </ToolBarContainer>
    </>
  );
};

export default ImagePortal;
Enter fullscreen mode Exit fullscreen mode

3. Import to App.js

Now we just need to import the ImagePortal component into App.js

import styled from "styled-components";
import ImagePortal from "./components/ImagePortal";

// image url from unsplash
const imageURL =
  "https://images.unsplash.com/photo-1640622300930-6e8daa98536f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1772&q=80";

const Container = styled.div`
  display: flex;
  margin: auto;
  width: 60vmin;
`;

const App = () => {
  return (
    <Container>
      <ImagePortal image={imageURL} />
    </Container>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

End Result

Image description

Top comments (0)