4

I created an image view component with buttons to rotate, zoom in and zoom out. When you click a button it adds CSS transform to the image.

For some reason, when I zoom the image, I can't scroll it to the very top or left corner. I tried to add transform-origin: top left; to the image, and it fixes zoom, however, it breaks rotation. How can I solve this issue?

You can see my code here https://codesandbox.io/s/delicate-star-eitj3s?file=/src/app/app.component.ts

EDIT: transform-origin: top left; makes the image stick to the top left corner, but I need to keep the image in the center. Is it possible to fix the scroll and keep the origin for the image transformations in the center?

rel1x
  • 2,351
  • 4
  • 34
  • 62
  • 1
    All solutions I found seem to depend on `transform-origin`. For some reason the parent element doesn't recognize top and left overflows. – Moaaz Bhnas Feb 24 '22 at 08:16
  • I you set `transform-origin` to `bottom right` and try to zoom in, the scroll bar won't even appear. Weird behavior. – Moaaz Bhnas Feb 24 '22 at 08:17
  • 2
    Browsers do not take top and left overflows into consideration for scrollbars. This problem is usually solved with translating the element. [Here's a good explanation](https://stackoverflow.com/a/21305283/6113902). Alternatively (though less ideal), you can apply scaling via `width` and `height`, and get away with using `transform` and `transform-origin` for rotation. – bariscc Mar 02 '22 at 00:49

3 Answers3

2

We can use height and width for zoom, and transform for rotation. With display:flex image can be kept at center. Demo

.image-viewer {
  display: flex;
  overflow: auto;
  width: 100%;
  height: 100%;
  border: 1px solid black;
}

.image-viewer img {
  margin:auto;
  width: 70%;
  height: 70%;
  transition: 0.3s;
}

.image-controls {
  width: 100%;
  text-align: center;
}

.image-controls button {
  transition: opacity 0.2s;
  opacity: 0.8;

  &:hover {
    opacity: 1;
  }
}

 private transformImage(): void {
    this.renderer.setStyle(
      this.image.nativeElement,
      "transform", `rotate(${this.angle}deg)`
    );
    this.renderer.setStyle(
      this.image.nativeElement,
      "width", `${100 * this.scale}%`
    );

    this.renderer.setStyle(
      this.image.nativeElement,
      "height", `${100 * this.scale}%`
    );
    /*this.image.nativeElement.scrollIntoView({
      behavior: "smooth",
      inline: "center",
      block: "start"
    });*/
  }
the Hutt
  • 16,980
  • 2
  • 14
  • 44
  • 1
    You can have the transition for zoom **and** rotate by applying multiple transition properties to `.image-viewer img` like this: `transition: transform 0.3s, height 0.3s;`. See [fork](https://codesandbox.io/s/cold-http-o0khxy?file=/src/app/app.component.scss) – bariscc Mar 06 '22 at 21:01
  • 1
    Thanks! forgot to update it. As values are same we can simply use `transition: .3s` – the Hutt Mar 06 '22 at 21:08
0

you are right.transform-origin: top left; is the solution. Put condition in your transformImage method like below and pass true/false

private transformImage(zoom): void {
this.renderer.setStyle(
  this.image.nativeElement,
  "transform",
  `rotate(${this.angle}deg) scale(${this.scale})`
);
if (zoom) {
  this.renderer.setStyle(
    this.image.nativeElement,
    "transform-origin",
    `top left`
  );
}

}

https://codesandbox.io/s/practical-night-n71z3q?from-embed

  • Hi! I don't think your suggested solution works. Try to click on zoom and the rotate, or first rotate, then zoom – rel1x Feb 24 '22 at 07:59
0
  rotate(): void {
    this.angle = this.angle + 90;
    this.transformImage("rotate");
  }

  private transformImage(transformType?: string): void {
    switch (transformType) {
      case "rotate":
        this.renderer.setStyle(
          this.image.nativeElement,
          "tranform-origin",
          "center center"
        );
        break;
      default:
        this.renderer.setStyle(
          this.image.nativeElement,
          "tranform-origin",
          "top left"
        );
        break;
    }

    this.renderer.setStyle(
      this.image.nativeElement,
      "transform",
      `rotate(${this.angle}deg) scale(${this.scale})`
    );
  }

codesandbox

Ali Demirci
  • 5,302
  • 7
  • 39
  • 66