60

I need to rotate an image with javascript in 90-degree intervals. I have tried a few libraries like jQuery rotate and Raphaël, but they have the same problem - The image is rotated around its center. I have a bunch of content on all sides of the image, and if the image isn't perfectly square, parts of it will end up on top of that content. I want the image to stay inside its parent div, which has max-with and max-height set.

Using jQuery rotate like this (http://jsfiddle.net/s6zSn/1073/):

var angle = 0;
$('#button').on('click', function() {
    angle += 90;
    $("#image").rotate(angle);
});

Results in this:

How jQuery rotate works

And this is the result i would like instead:

How I would like it to work

Anyone have an idea on how to accomplish this?

Piyin
  • 1,823
  • 1
  • 16
  • 23
TheQ
  • 6,858
  • 4
  • 35
  • 55

9 Answers9

71

You use a combination of CSS's transform (with vendor prefixes as necessary) and transform-origin, like this: (also on jsFiddle)

var angle = 0,
  img = document.getElementById('container');
document.getElementById('button').onclick = function() {
  angle = (angle + 90) % 360;
  img.className = "rotate" + angle;
}
#container {
  width: 820px;
  height: 100px;
  overflow: hidden;
}
#container.rotate90,
#container.rotate270 {
  width: 100px;
  height: 820px
}
#image {
  transform-origin: top left;
  /* IE 10+, Firefox, etc. */
  -webkit-transform-origin: top left;
  /* Chrome */
  -ms-transform-origin: top left;
  /* IE 9 */
}
#container.rotate90 #image {
  transform: rotate(90deg) translateY(-100%);
  -webkit-transform: rotate(90deg) translateY(-100%);
  -ms-transform: rotate(90deg) translateY(-100%);
}
#container.rotate180 #image {
  transform: rotate(180deg) translate(-100%, -100%);
  -webkit-transform: rotate(180deg) translate(-100%, -100%);
  -ms-transform: rotate(180deg) translateX(-100%, -100%);
}
#container.rotate270 #image {
  transform: rotate(270deg) translateX(-100%);
  -webkit-transform: rotate(270deg) translateX(-100%);
  -ms-transform: rotate(270deg) translateX(-100%);
}
<button id="button">Click me!</button>
<div id="container">
  <img src="https://i.stack.imgur.com/zbLrE.png" id="image" />
</div>
Jeromy French
  • 11,812
  • 19
  • 76
  • 129
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 2
    Add `filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);` for IE8 and IE7 support. `rotation=1` for 90 deg, `2` for 180 deg, `3` for 270 deg. – mqchen May 28 '13 at 14:29
  • 1
    Note that you should really apply this to the image container, if you want the border to work right. – Niet the Dark Absol May 28 '13 at 14:29
  • 2
    Nopes ! this transform brings OP to the same problem. The transform is applied but not in the way OP wants – Om Shankar May 28 '13 at 14:34
  • @OmShankar I think it still gives OP enough to go on. – Blazemonger May 28 '13 at 14:35
  • 2
    This is almost working, however take a look that this: http://jsfiddle.net/bhN6e/. I would like the text below the image to stay below the image, even after rotation. As it is right now, the image ends up on top of the text. – TheQ May 28 '13 at 14:37
  • So [something like this](http://jsfiddle.net/bhN6e/1/)? I have added a container around the image, applied the class to the container, adjusted some CSS... Basically, the important thing is to switch the container's width and height around when rotating by 90 or 270. – Niet the Dark Absol May 28 '13 at 14:40
  • @Blazemonger, Look at the **images** in the question asked. OP already has shown in the question that he/she is able to achieve that rotation **already** – Om Shankar May 28 '13 at 14:42
  • @Kolink: That looks very promising, need to AFK a bit now, but i'll try and implement it on my site tomorrow. Thanks! – TheQ May 28 '13 at 14:43
  • **This** is how you answer a question. Nice one. – T.J. Crowder Feb 27 '16 at 13:19
10
var angle = 0;
$('#button').on('click', function() {
    angle += 90;
    $('#image').css('transform','rotate(' + angle + 'deg)');
});

Try this code.

Harsha Venkataramu
  • 2,887
  • 1
  • 34
  • 58
10

No need for jQuery and lot's of CSS anymore (Note that some browsers need extra CSS)

Kind of what @Abinthaha posted, but pure JS, without the need of jQuery.

let rotateAngle = 90;

function rotate(image) {
  image.setAttribute("style", "transform: rotate(" + rotateAngle + "deg)");
  rotateAngle = rotateAngle + 90;
}
#rotater {
  transition: all 0.3s ease;
  border: 0.0625em solid black;
  border-radius: 3.75em;
}
<img id="rotater" onclick="rotate(this)" src="https://upload.wikimedia.org/wikipedia/en/e/e0/Iron_Man_bleeding_edge.jpg"/>
Anuga
  • 2,619
  • 1
  • 18
  • 27
  • The original accepted answer still works better for my use case, since I need text to flow properly below the image, and adapt to the size of the image. http://jsfiddle.net/soqkrbut/ is an updated version of the original answer, that works exactly as I want. Using this code does not work, see http://jsfiddle.net/uzhoy6pm/ – TheQ Aug 22 '18 at 12:13
  • 1
    Thanks for this; hate when jquery gets forced into a question I otherwise have. – Wyatt Ward Apr 02 '20 at 15:41
  • 1
    I know it should be avoided but +1 for the Iron Man image. – smoore4 Sep 04 '20 at 15:44
  • I was ahead of my time (50+ hours in the game now :) – Anuga Sep 07 '20 at 00:41
3

CSS can be applied and you will have to set transform-origin correctly to get the applied transformation in the way you want

See the fiddle:

http://jsfiddle.net/OMS_/gkrsz/

Main code:

/* assuming that the image's height is 70px */

img.rotated {
    transform: rotate(90deg);
    -webkit-transform: rotate(90deg);
    -moz-transform: rotate(90deg);
    -ms-transform: rotate(90deg);

    transform-origin: 35px 35px;
    -webkit-transform-origin: 35px 35px;
    -moz-transform-origin: 35px 35px;
    -ms-transform-origin: 35px 35px;
}

jQuery and JS:

$(img)
    .css('transform-origin-x', imgWidth / 2)
    .css('transform-origin-y', imgHeight / 2);

// By calculating the height and width of the image in the load function

// $(img).css('transform-origin', (imgWidth / 2) + ' ' + (imgHeight / 2) );

Logic:

Divide the image's height by 2. The transform-x and transform-y values should be this value

Link:

transform-origin at CSS | MDN

Om Shankar
  • 7,989
  • 4
  • 34
  • 54
  • What if the image's size changes, or is just not fixed? That'd be a mess. Mind you, this is a mess with 180 and 270 rotations ;) – Niet the Dark Absol May 28 '13 at 14:42
  • @Kolink. Cool. Anyways, you have jQuery and JS on the page. One can calculate and apply this CSS on the fly. I am editing the answer for JS. Thanks for pointing out ! – Om Shankar May 28 '13 at 14:44
  • Seems a bit over-convoluted. I prefer my solution :p It's completely independent of the image's size. – Niet the Dark Absol May 28 '13 at 14:47
  • @Kolink, I am going per the concept as read from Mozilla DN. In your solution (which is good of course), you are doing an additional tranlate. This is cheating :) Also, conceptually, translating is what is achieved by using the `transform-origin` values - only that they translate the origin of the transform, rather than the element itself – Om Shankar May 28 '13 at 14:51
  • The problem is that you can't have a single origin to handle all four positions. This is why I stuck with one origin and adjusted the position to place it correctly. – Niet the Dark Absol May 28 '13 at 19:27
  • FYI: If you want to set your `transform-origin` to the centre of the image just use a value of `50%` - e.g. `transform-origin: 50% 50%;` – Robin Jun 21 '15 at 13:20
3

i have seen your running code .There is one line correction in your code.

Write:

$("#wrapper").rotate(angle); 

instead of:

$("#image").rotate(angle);

and you will get your desired output,hope this is what you want.

thisiskelvin
  • 4,136
  • 1
  • 10
  • 17
3

Hope this can help you!

<input type="button" id="left"  value="left" />
<input type="button" id="right" value="right" />
<img src="https://www.google.com/images/srpr/logo3w.png" id="image">

<script>
 var angle = 0;
    $('#left').on('click', function () {  
        angle -= 90;
        $("#image").rotate(angle);
    });

    $('#right').on('click', function () {  
        angle += 90;
        $("#image").rotate(angle);
    });
</script>

Try it

Man Sun
  • 49
  • 2
3

I think this will work.

    document.getElementById('#image').style.transform = "rotate(90deg)";

Hope this helps. It's work with me.

2

You can always apply CCS class with rotate property - http://css-tricks.com/snippets/css/text-rotation/

To keep rotated image within your div dimensions you need to adjust CSS as well, there is no needs to use JavaScript except of adding class.

Wojciech Bednarski
  • 6,033
  • 9
  • 49
  • 73
0

Based on Anuga answer I have extended it to multiple images.

Keep track of the rotation angle of the image as an attribute of the image.

function rotate(image) {
  let rotateAngle = Number(image.getAttribute("rotangle")) + 90;
  image.setAttribute("style", "transform: rotate(" + rotateAngle + "deg)");
  image.setAttribute("rotangle", "" + rotateAngle);
}
.rotater {
  transition: all 0.3s ease;
  border: 0.0625em solid black;
  border-radius: 3.75em;
}
<img class="rotater" onclick="rotate(this)" src="https://upload.wikimedia.org/wikipedia/en/e/e0/Iron_Man_bleeding_edge.jpg"/>
<img class="rotater" onclick="rotate(this)" src="https://upload.wikimedia.org/wikipedia/en/e/e0/Iron_Man_bleeding_edge.jpg"/>
<img class="rotater" onclick="rotate(this)" src="https://upload.wikimedia.org/wikipedia/en/e/e0/Iron_Man_bleeding_edge.jpg"/>

Edit

Removed the modulo, looks strange.

rioV8
  • 24,506
  • 3
  • 32
  • 49