Correct outerWidth with transform: scale - javascript

I have a slideshow where all the elements except from the active one has the transform scale(0.925). I need to get the total width of all my elements and apply this to the parent.
$(slides).each(function() {
console.log($(this).outerWidth());
tot_width += $(this).outerWidth();
});
$('ul').css({width: tot_width});
The tot_width is wrong because of the scaling of the elements. How can I fix this?

Assuming, you are displaying them already, you can use
tot_width += $(this)[0].getBoundingClientRect().width;

You could check if each element is active and then multiply by the scale factor:
$(slides).each(function() {
var width = $(this).outerWidth();
if (!($(this).hasClass('active'))) {
width = width * .925;
}
tot_width += width;
});

Related

Returning offsetWidth of element in percentage or with decimal places to make the width of an overlaying div the same - React / Javascript

Lately I am fiddling a bit in React and I have encountered the following problem, which is not necessarily React related but more Javascript / CSS in general related.
I have created a bar which contains a certain amount of cells. These cells all have the same width and height properties but will adjust its width/height properties to the viewport.
When I click one of these cells a div get's appended to the container of the cells, this div is an overlay with a different color (so you know which cell has been clicked).
The problem is that the bar and it's containing cells have their width attribute set in percentage, this has been done so I can calculate the width needed based on the total cell count when adding more cells to the containing div.
The overlay div however, which is added when a cell is being clicked, has it's width defined in px. This is because the left and top position of the overlay div is being determined with the pageY and pageX coordinates and the height and width of the cell element is being fetched with offsetHeight and offsetWidth.
The result of the above is that the actual width of the cell is a decimal value (it is percentage) but the calculated width is a rounded px value, this results in the following:
The normal Cell width:
The Overlay div width:
as you can see this is a minor difference in width, to show it properly I had to zoom in quite a bit. In the second picture you see that how further in left position the overlay div is being added, the bigger the difference (which is logical).
The code:
This is the normal Cell which is being rendered
_onRenderCell = (item, index) => {
this.myCell = React.createRef();
return (
<div
className="ms-ListGridExample-tile"
data-is-focusable={false}
style={{
width: 100 / this._columnCount + '%',
height: this._rowHeight * 1.5,
float: 'left'
}}
>
... rest of the rendering omitted ...
You can see here that the width is determined based on the column count and returned as a percentage: width: 100 / this._columnCount + '%'
The onMouseDown event to add the overlay div:
_onMouseDown (e){
const containerNode = this.rsvnRef.current;
const cellNode = this.myCell.current;
// Determine current position
let posY = e.pageY - containerNode.getBoundingClientRect().top;
let posX = e.pageX - containerNode.getBoundingClientRect().left;
// Determine width and height of cell
let height = cellNode.offsetHeight;
let width = cellNode.offsetWidth;
// Determine top and left positions
let top = posY - (posY % height);
let left = posX - (posX % width);
var reservationClasses = document.getElementsByClassName('reservation');
var collisions = Array.prototype.filter.call(reservationClasses, function(rsv) {
return rsv.offsetTop == top && rsv.offsetLeft == left;
});
if (collisions.length == 0){
// Creating the overlay div
const newRsvn = document.createElement("div");
newRsvn.className = "reservation reservation-creating";
newRsvn.style.top = top + 'px';
newRsvn.style.left = left + 'px';
newRsvn.style.height = height + 'px';
newRsvn.style.width = width + 'px';
// Apending overlay div to container
containerNode.append(newRsvn);
}
}
My question is (as you probably expected); how can I make the overlaying div have the exact same width as the cell div? Can you return the offsetWidth with decimal places, or can I in some way calculate the offsetWidth in percentage?
After some more research, and thanks to this post: Converting width from percentage to pixels I managed to get it done.
However, I don't know if it is the best / right solution so please do give feedback if you think there is a better way!
I decided to just set the width of the cell in pixels instead of a percentage. The rendering of a cell is being done dynamically anyway (each time the screen size changes) so calculating the right amount of pixels in the cell rendering and rounding that to a whole number works fine since now both the cell and overlaying div are using the same width.
The code:
_onRenderCell = (item, index) => {
this.myCell = React.createRef();
const containerNode = this.rsvnRef.current;
let percents = parseInt(100 / this._columnCount);
let parentWidth = parseInt(containerNode.offsetWidth);
let pixels = parseInt(parentWidth*(percents/100));
return (
<div
className="ms-ListGridExample-tile"
data-is-focusable={false}
style={{
// width: 100 / this._columnCount + '%',
width: pixels + 'px',
height: this._rowHeight * 1.5,
float: 'left'
}}
>
... rest of the rendering omitted ...

New value after applying css() in jQuery

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;

Subtract element width from body width, and add as margin to element

I have an image inside a container. The image should always be at full browser width (100vw). As my layout is responsive, and the container has a fixed width at a certain point (45em), I can't simply use negative margins. So I got an idea, but as a novice I can't seem to achieve it...
This is what I want to do:
Check the body width
Check the container width
Subtract the element width from the body width
Divide this number in two
Add this number as a negative margin to an element
This is what I got so far...
var bodyWidth = $('body').width(); //Check the body width
var elemWidth = $('#content').width(); //Check the container width
var margin = bodyWidth-elemWidth; //Subtract the element width from the body width
I still need to divide the number in two, and add this number as a negative margin to an element.
Help is much appreciated.
You're on the right track.
var bodyWidth = $('body').width(); //Check the body width
var elemWidth = $('#content').width(); //Check the container width
var margin = bodyWidth-elemWidth; //Subtract the element width from the body width
var dividedMargin = margin / 2; // Divide the margin by 2
var negativeMargin = dividedMargin * -1; // set number to negative number
$(element).css("margin", negativeMargin); // replace element by the element name you want to apply this to.
You can also replace margin by margin-left, margin-right,margin-top or margin-bottom.

How to convert css pixels to css3 scale (x,y)

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

offsetHeight and offsetWidth calculating incorrectly on first onclick event, not second

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');
});

Categories