I'm scaling a div in order to be visible without scrolling. So I have:
var sliderOffset = $('.field-slideshow-wrapper').offset().top,
windowHeight = $(window).height(),
sliderAllowed = (windowHeight - sliderOffset),
sliderImage = $('.field-slideshow-slide img').height(),
sliderOriginal = (sliderImage + 150),
scale = (sliderAllowed / sliderOriginal);
$('.field-slideshow-wrapper').css({ transform: 'scale(' + scale + ')'});
Now that div is not on the same position from top as before and I need to determine new offset from top, after css({ transform: 'scale(' + scale + ')' is applied, so I can calculate some margin to move this div at the top.
How to determine new offset().top of the element?
There are two ways you could do this and the choice is yours. The transform: scale() shrinks the element toward its center, so the top of the element moves down. The scaled element will still return the non-scaled element's offset().top, so that won't work.
One option is to just make sure the newly scaled element will stick to the top of the old element's space. Just do this:
$('.field-slideshow-wrapper').css({
transform: 'scale(' + scale + ') translateY(-50%)'
});
This makes the element move up by 50% of its new height, thus sticking it to the top of its old dimensions.
The other option is to do some simple calculation. Get the old element's height, then get the number of pixels the scale() method has moved it "down". You can find the number by some calculations (see below), and that's the number you can add to the old offset().top to get the new one:
var sliderOffset = $('.field-slideshow-wrapper').offset().top,
windowHeight = $(window).height(),
elHeight = $('.field-slideshow-wrapper').innerHeight(),
sliderAllowed = (windowHeight - sliderOffset),
sliderImage = $('.field-slideshow-slide img').height(),
sliderOriginal = (sliderImage + 150),
scale = (sliderAllowed / sliderOriginal);
var addProportion = 1-scale / 2;
var newOffset = sliderOffset + (addProportion * elHeight);
Whether you should use innerHeight() or outerHeight() depends on your layout.
well just get the new offset after you've applied the scaling
...
$('.field-slideshow-wrapper').css({ transform: 'scale(' + scale + ')'});
var newOffset = $('.field-slideshow-wrapper').offset().top;
Related
I'm trying to use transform to scale an image to fullsize.
This is how I try to calculate the top and position, it almost works, but the translation is based on the images original size, not the scaled size. Could I solve this by applying different css somehow or do I have to figure out another translation value?
transformCarousel () {
if (this.state.zoom) {
const heightBefore = this.state.carousel.height
const heightAfter = window.innerHeight * 0.792
const scale = heightAfter / heightBefore
const posBefore = this.state.carousel.top
const posAfter = window.pageYOffset
const translate = posAfter - posBefore
return {
zIndex: 1070,
transform: 'scale(' + scale + ') translateY(' + translate + 'px)'
}
}
}
I am just guessing what it's your problem.
It seems that the px value of the translation should be in the final scale and not the beginning scale.
This code would do it:
transform: 'translateY(' + translate + 'px) scale(' + scale + ')'
The order in the transforms is right to left, so the scale will be applied and after this the translate will be
I am working on a project where I am using CSS transform to scale up the whole body of a page. After scaling up a bit, content from corners start becoming un-viewable because they are outside visible ranges. Is there a way for the content to still be viewable by scrolling vertically or horizontally using transform scaling?
I am currently using Javascript to scale up the body like so
document.body.style.transform = 'scale(1.5)';
However, this cuts off some content from pages. I need it to work as I continue scaling up from 1.0.
Try adjusting the transform-origin:
document.body.style.transformOrigin = 'top left';
document.body.style.transform = 'scale(' + scaleFactor + ')';
You may also need to adjust the width and height of the body to match the scaling.
var scaleFactor = 1.5;
document.body.style.transformOrigin = 'top left';
document.body.style.transform = 'scale(' + scaleFactor + ')';
document.body.style.width = 100 * scaleFactor + "%";
document.body.style.height = 100 * scaleFactor + "%";
A note concerning transforms. Transforms are imaginary and don't alter physical dimensions including x, y, width and height. So you'll have to manage these physical dimensions manually to match your "transform'd" dimensions in order to keep the scroll bars happy.
I have a div whose initial width and height are set by the user. When a user zooms in the browser(ctrl+ or ctrl-) the initial width and height of that div changes, say a user zooms in 175%, the aspect ratio of that div stays the same because the width and height is adjusted. Is there a way to replicate this by dynamically setting transform: scale(x,y). I have tried several thing but can't seem to find a solid solution.
Solution seems pretty straight-forward. Store scale somewhere, then increase/decrease it on button's click:
(function () {
function zoom(element, scale) {
element.style.webkitTransform =
element.style.transform = 'scale(' + scale + ')';
return scale;
}
var zoomable = document.querySelector('.zoomable');
var scale = 1;
document.querySelector('#zoomin')
.addEventListener('click', function () {
scale = zoom(zoomable, scale * 2);
});
document.querySelector('#zoomout')
.addEventListener('click', function () {
scale = zoom(zoomable, scale * 0.5);
});
})();
Demo: http://jsbin.com/aJagofU/1/edit?js,output
I have a resizable div which is positioned over a selection of elements which have been set to alsoResize.
Visually, the resizable element is a bounding box for the alsoResize elements.
I want to be able to resize the alsoResize elements in proportion of the resizable div. UI's default behaviour makes each element have a fixed left and top position when resizing:
http://jsfiddle.net/digitaloutback/SrPhA/2/
But I want to adjust the left and top of each AR element to scale with the bounding box as it's resized.
I first thought this wouldn't be too much hassle by altering the alsoResize plugin. This is what I added to the resize: _alsoResize:
// Get the multipliers
var scaleX = self.size.width / os.width;
var scaleY = self.size.height / os.height;
newElW = ( parseInt(el.css('width')) * scaleX );
newElH = ( parseInt(el.css('height')) * scaleY );
newElL = ( parseInt(el.css('left')) * scaleX );
newElT = ( parseInt(el.css('top')) * scaleY );
el.css({ width: newElW, height: newElH, left: newElL, top: newElT });
As you'll see, the boxes lag somewhat:
http://jsfiddle.net/digitaloutback/SrPhA/4/
Something seems to be ballooning the figures and can't quite figure it out, any suggestions appreciated. Possibly discrepancy of decimal places between scripts & browser?
Maybe you need to rethink the structure..
You could insert the .lyr elements inside the .resizer element and position them inside it with percentage positions .. this way they will automatically resize while their container is changing size. (the plugin does not have to handle them)
demo at http://jsfiddle.net/SrPhA/65/
Update after comment
To de-couple the resizer from the alsoResize elements you will need to take a couple of things into consideration for the calculations.
Firstly, you need to use the starting dimensions/positions and not the current of the elements, so use start.width .height etc..
for the positioning you need to translate the element to the origin (in regards to distance from the resizer) scale the left/top and then re-translate back to where they were..
the final calculations become
newElW = start.width * scaleX;
newElH = start.height * scaleY;
newElL = ((start.left - op.left) * scaleX) + op.left;
newElT = ((start.top - op.top ) * scaleY) + op.top ;
It needs some more tinkering to handle the case were you scale the elements by dragging the top or left side of the resizer..
demo at http://jsfiddle.net/gaby/SrPhA/171/
Latest Update
to handle scaling in all directions use these helpers..
utils: {
west: function(start, op, scale, delta) {return ((start.left - op.left) * scale) + op.left + delta.left},
east: function(start, op, scale, delta) {return ((start.left - op.left) * scale) + op.left;},
south: function(start, op, scale, delta){return ((start.top - op.top ) * scale) + op.top; },
north: function(start, op, scale, delta){return ((start.top - op.top ) * scale) + op.top + delta.top; }
}
Working example with all updates at http://jsfiddle.net/gaby/SrPhA/324/
Did you mean to use + instead of *?
newElW = (parseInt(el.css('width')) + scaleX);
newElH = (parseInt(el.css('height')) + scaleY);
newElL = (parseInt(el.css('left')) + scaleX);
newElT = (parseInt(el.css('top')) + scaleY);
I had a little luck by setting the margin-top and margin-left for positioning and leaving the 'top' and 'left' attributes at default for animation.
http://jsfiddle.net/SrPhA/97/
I have written the following script to display a hidden element, then fix it's position to the center of the page.
function popUp(id,type) {
var popUpBox = document.getElementById(id);
popUpBox.style.position = "fixed";
popUpBox.style.display = "block";
popUpBox.style.zIndex = "6";
popUpBox.style.top = "50%";
popUpBox.style.left = "50%";
var height = popUpBox.offsetHeight;
var width = popUpBox.offsetWidth;
var marginTop = (height / 2) * -1;
var marginLeft = (width / 2) * -1;
popUpBox.style.marginTop = marginTop + "px";
popUpBox.style.marginLeft = marginLeft + "px";
}
When this function is called by an onclick event, the offsetHeight and offsetWidth are calculated incorrectly, thus not centering the element correctly. If I click the onclick element a second time, the offsetHeight and offsetWidth calculate correctly.
I have tried changing the order in every way I can imagine, and this is driving me crazy! Any help is very much appreciated!
I am guessing your height and width are not defined on the parent. See this fiddle where it works fine. Boy I'm smart. http://jsfiddle.net/mrtsherman/SdTEf/1/
Old Answer
I think this can be done a lot more simply. You are setting the top and left properties to 50%. This will place the fixed element slight off from the center. I think you are then trying to pull it back into the correct position using negative margins. Instead - just calculate the correct top/left values from the start and don't worry about margin. Here is a jQuery solution, but it can be easily adapted to plain js. I also think your current code won't work if the window has been scrolled at all.
//this code will center the following element on the screen
$('#elementid').click(function() {
$(this).css('position','fixed');
$(this).css('top', (($(window).height() - $(this).outerHeight()) / 2) + $(window).scrollTop() + 'px');
$(this).css('left', (($(window).width() - $(this).outerWidth()) / 2) + $(window).scrollLeft() + 'px');
});