-1

I am trying to display a gallery with multiple images, and i would like that each image would have a button to rotate each image.

So, following the idea of the answer of this question, I created below code:

const Root = document.documentElement,
  gRoot = getComputedStyle(Root)

var RotateDeg = parseInt(gRoot.getPropertyValue('--turn'))

function rotate90() {
  RotateDeg = (RotateDeg + 90) % 360
  Root.style.setProperty('--turn', RotateDeg + "deg")
}
img {
  width: auto;
  height: auto;
  image-rendering: pixelated;
}

:root {
  --turn: 0deg;
}

#theImage {
  -webkit-transform: rotate( var(--turn));
  -moz-transform: rotate( var(--turn));
  -ms-transform: rotate( var(--turn));
  -o-transform: rotate( var(--turn));
  transform: rotate( var(--turn));
}
<div class="card shadow-sm">
  <img id="theImage" alt="text of my image 1" class="img-thumbnail card-img-top" property="contentUrl" src="myimage1.png" /><br/>
  <div class="btn-group">
    <button type="button" class="btn btn-sm btn-outline-secondary" onclick="rotate90()">Rotar</button>
  </div>
</div>
</div>
<div class="card shadow-sm">
  <img id="theImage" alt="text of my image 2" class="img-thumbnail card-img-top" property="contentUrl" src="myimage2.png" /><br/>
  <div class="btn-group">
    <button type="button" class="btn btn-sm btn-outline-secondary" onclick="rotate90()">Rotar</button>
  </div>
</div>
</div>

So, it works partialy, the main problem I have is that when i click one button, it not only rotates its image but ALL images. I think the main reason is because it is using the same ID. The problem i have is that it is a gallery with thousand of images and i wouldn't like to create an ID for each image.

Is there any solution i could use here to rotate just 1 image without creating thousand of IDs?

Thank you!

ThS
  • 4,597
  • 2
  • 15
  • 27
Kaxsp
  • 59
  • 5

1 Answers1

1

The word image, found in the answer, refers to an image that is part of the gallery of images that have the rotation effect.

The word button refers to the button that triggers the rotation effect on an image.


Let me start by showcasing the main issue here that led to all the images being rotated regardless of the button that was clicked.

  • Your rotate90() function adds increment the --turn custom property (also called CSS variable) by 90deg each time a button is clicked
  • The --turn variable is declared under the :root element which means that it is inherited by all elements on the page, including the images.
  • when the rotate90() function is executed the --turn is incremented and its value is also updated on all the images which leads to all the images rotate regardless of the button that was clicked.

With that being explained, a quick fix could be as follows:

The solution that am going to describe is NOT the only possible way to achieve your goal, there are many ways to do so but it all depends on the case.

  1. In the CSS part, move the --turn declaration to the img selector so that each image on the page will have its own copy of that variable.
  2. Give each image an ID (the IDs must be unique).
  3. Tell each button which image to rotate when clicked, i.e connect each button to its image. We may do that by using Data Attributes by adding, for example, data-rotate to each button where that data attribute contains the ID of the image that the button should rotate.
  4. In the JS part, apply click listeners to those buttons and change the rotation of the corresponding image.

Here's a live demo that demonstrates the above solution:

/** loop through the buttons */
document.querySelectorAll('.rotation-trigger').forEach(btn => {
  /** 
   * select and cache the related image (for better performance)  
   * as each button has a "data-rotate" that is the ID of the respective button 
   * we use the value in "data-rotate" to select the respective image by calling "document.getElementById" and passing the ID which found in the "data-rotate" (btn.dataset.rotate)
   */
  const imgToRotate = document.getElementById(btn.dataset.rotate);
  /** listen for click event on each button */
  btn.addEventListener('click', e => {
    e.preventDefault();
    /** update the "--turn" custom attribute, this will affect only the related image and NOT all the images */
    imgToRotate.style.setProperty('--turn', (+imgToRotate.style.getPropertyValue('--turn').replace('deg', '') + 90 % 360) + 'deg');
  });
});
/** each image will have its own copy of "--turn" variable that can be updated without affecting the other buttons */

img {
  --turn: 0deg;
  width: auto;
  height: auto;
  image-rendering: pixelated;
  transform: rotate(var(--turn));
  transition: all .4s 0s ease;
  /** not required, this adds an appealing transition when --turn is updated */
}
<!-- each image has a unique ID -->
<!-- each button has a data-rotate that points to the respective image ID -->
<!-- removed click listener from the HTML, check the JS part -->
<!-- I have also gave "rotation-trigger" class to the buttons to easily select them in the JS part -->
<div class="card shadow-sm">
  <img id="img-1" alt="text of my image 1" class="img-thumbnail card-img-top" property="contentUrl" src="//via.placeholder.com/150?text=Image+%231" /><br/>
  <div class="btn-group">
    <button type="button" class="btn btn-sm btn-outline-secondary rotation-trigger" data-rotate="img-1">Rotar</button>
  </div>
</div>
<div class="card shadow-sm">
  <img id="img-2" alt="text of my image 2" class="img-thumbnail card-img-top" property="contentUrl" src="//via.placeholder.com/150?text=Image+%232" /><br/>
  <div class="btn-group">
    <button type="button" class="btn btn-sm btn-outline-secondary rotation-trigger" data-rotate="img-2">Rotar</button>
  </div>
</div>
</div>

As I mentioned above, the solution found in the answer is not the only possible solution, matter of fact, I tried to keep the above solution as simple as possible so that it can be understood quite easily.

ThS
  • 4,597
  • 2
  • 15
  • 27
  • Thank you for the answer, I see it works perfectly in the snippet, but somehow when i just write it on my html encapsulating the script and style it does not work. Any idea? Thanks anyway. – Kaxsp Sep 26 '22 at 19:58