Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS rotate element while staying inside container

If you take a a look at: http://jsfiddle.net/KA4dz/

In this demo, you can clearly see the inner element reaching outside of the outer element due to its rotation. The request is to scale down the inner element (while maintaining aspect ratio's and center positioning) just so it fits within its container.

The use-case is that the user can manually rotate such an inner element while ensuring that it stays within the outer element. (so simply scaling down until it fits for the eyes is not a solution).

This is a scenario where my math skills are clearly lacking. Posting what I've tried wont do much good at this stage. Can someone point me in the right direction?

Thanks!

One additional requirement is that the inner element only scales down whenever its required but never scales down when its not required (where required means leaving the boundaries of the outer element)

To save a click:

.outer{
    border: 1px solid black;
    width: 100px;
    height: 50px;
    margin: 100px;
}

.inner{
    background: blue;
    width: 100px;
    height: 50px;

    transform: rotate(-40deg);
    -webkit-transform: rotate(-40deg);
}

<div class="outer">
    <div class="inner">
    </div>
</div>        
like image 535
Polity Avatar asked Nov 05 '13 16:11

Polity


2 Answers

This was interesting. Here's my solution: http://jsfiddle.net/fletiv/jrHTe/

And javascript looks like this:

(function () {

var setRotator = (function () {

    var setRotation,
        setScale,
        offsetAngle,
        originalHeight,
        originalFactor;

    setRotation = function (degrees, scale, element) {
        element.style.webkitTransform = 'rotate(' + degrees + 'deg) scale(' + scale + ')';
        element.style.transform = 'rotate(' + degrees + 'deg) scale(' + scale + ')';
    };

    getScale = function (degrees) {

        var radians = degrees * Math.PI / 180,
            sum;

        if (degrees < 90) {
            sum = radians - offsetAngle;
        } else if (degrees < 180) {
            sum = radians + offsetAngle;
        } else if (degrees < 270) {
            sum = radians - offsetAngle;
        } else {
            sum = radians + offsetAngle;
        }

        return (originalHeight / Math.cos(sum)) / originalFactor;
    };

    return function (inner) {

        offsetAngle = Math.atan(inner.offsetWidth / inner.offsetHeight);
        originalHeight = inner.offsetHeight;
        originalFactor = Math.sqrt(Math.pow(inner.offsetHeight, 2) + Math.pow(inner.offsetWidth, 2));

        return {

            rotate: function (degrees) {
                setRotation (degrees, getScale(degrees), inner);
            }
        }
    };

}());

var outer = document.getElementById('outer'),
    inner = document.getElementById('inner'),
    rotator = setRotator(inner),
    degrees = 0;

window.setInterval(function () {
    degrees += 1;

    if (degrees >= 360) {
        degrees = 0;
    }

    rotator.rotate(degrees);
}, 50);

}());

Edit: Here's an image which tries to explain the logic of my code. :)

enter image description here

like image 190
Matti Mehtonen Avatar answered Nov 19 '22 20:11

Matti Mehtonen


A simplified version of Matti's answer

var scaler = function (id, degrees) {
        var inner = document.getElementById(id);
        offsetAngle = Math.atan(inner.offsetWidth / inner.offsetHeight);
        originalHeight = inner.offsetHeight;
        originalFactor = Math.sqrt(Math.pow(inner.offsetHeight, 2) + Math.pow(inner.offsetWidth, 2));
        var radians = degrees * Math.PI / 180,
            sum, result;
        if (degrees < 90) {
            sum = radians - offsetAngle;
        } else if (degrees < 180) {
            sum = radians + offsetAngle;
        } else if (degrees < 270) {
            sum = radians - offsetAngle;
        } else {
            sum = radians + offsetAngle;
        }
        var result = (originalHeight / Math.cos(sum)) / originalFactor;
        inner.style.webkitTransform = 'scale(' + result+ ')';
        inner.style.transform = 'scale(' + result+ ')';
}
like image 1
XIMRX Avatar answered Nov 19 '22 20:11

XIMRX