I am a little confused on how to keep some variables Ive created uptodate when the window is resized so my scroll function carries on getting the correct values. Basically I have multiple elements that contain a message that gets displayed when the user scrolls the element into 50% height of the viewport height. This works fine but my issue is when I resize I'm not sure how to update my variables boxHeight, elementOffset, verticalMatch which keep control of the values I need to use in my scroll event. I was wondering can someone help explain how I can resolve this?
My code looks like this
var windowHeight = $(window).height(),
headerHeight = $('.header').height();
$('.box').each(function (i,e) {
var el = $(e);
var boxHeight = el.height(),
elementOffset = el.offset().top,
verticalMatch = (windowHeight / 2) + (headerHeight / 2) - (boxHeight / 2);
$(window).on('scroll', function () {
var scrollTop = $(window).scrollTop(),
distance = elementOffset - scrollTop;
if( distance <= verticalMatch ) {
el.addClass('is-active');
}
});
});
$(window).on('resize', function() {
windowHeight = $(window).height()
elementOffset = $('.box').offset().top;
$('.box').each(function (i,e) {
var el = $(e);
//update boxHeight, elementOffset, verticalMatch
verticalMatch = (windowHeight / 2) + (headerHeight / 2) - (boxHeight / 2);
});
});
And heres the JS Fiddle: http://jsfiddle.net/fm4z7/2/
If someone could explain how I do this it would be great!
If all you want to do is update your sizing variables during a resize event, then do just that:
$(window).on('resize', function() {
windowHeight = $(window).height();
elementOffset = $('.box').offset().top;
});
Your variables are global so they can be accessed anywhere.
Related
You can scroll to an element using a url with a hashtag and the elements ID:
window.location.href = "#ID"
This will scrol so that the top of the element is at the top of the browser. How would I scroll to an element so that it's vertically centered?
you can scroll up right after the navigation happens:
addEventListener("hashchange", function(){
setTimeout(function(){
document[
document.documentElement.scrollTop ?
"documentElement":
"body"
].scrollTop-= (innerHeight/2.1);
}, 1);
}, false);
this will cause the focused element to appear half-way up the screen, vertically centered.
the 2.1 causes it to scroll just under half the screen, since there will be some room at the top already. you can adjust the ".1" to match your desired effect (baseline, middle, etc).
obligatory fiddle link: http://jsfiddle.net/ckhafLzq/2/
This is what I have achieved:
function centerScroll(element) {
if (!(element instanceof Element)) {
throw new TypeError("Element expected");
}
var bodyRect = document.body.getBoundingClientRect();
var elementRect = element.getBoundingClientRect();
var left = elementRect.left - bodyRect.left;
var top = elementRect.top - bodyRect.top;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var elementWidth = element.offsetWidth;
var elementHeight = element.offsetHeight;
var x = left - Math.max(0, (windowWidth - elementWidth) / 2);
var y = top - Math.max(0, (windowHeight - elementHeight) / 2);
window.scrollTo(x, y);
return [x, y];
}
No, there's no built-in way, you'd have to write that yourself:
function center_element_vertically(elt) {
var rect = elt.getBoundingClientRect();
window.scrollTo(0, rect.top + window.pageYOffset -
(window.innerHeight - rect.height)/2);
}
Alternatives without writing your own code: you could scroll so that the element was at the bottom by passing false to scrollIntoView, or scroll only if the element is not already visible by calling scrollIntoViewIfNeeded, available only in Chrome AFAIK.
I want to rewrite the following code so that it doesn't get the height of the <body>, but rather the height of the element I put the object in to carry out the function:
var img = document.getElementById("logo");
window.onscroll = function() {
var bodyHeight = parseInt(getComputedStyle(document.body).height, 10);
var scrollLimit = bodyHeight - window.innerHeight;
var scrollTop = document.body.scrollTop;
var scrollPCT = (scrollTop / (scrollLimit / 100)) / 100;
logo.style.top = bodyHeight * scrollPCT - logo.offsetHeight + "px";
};
How can I target, say an ID, instead of document.body? I tried the following but it didn't work at all:
var img = document.getElementById("logo");
window.onscroll = function() {
var body = document.getElementById("container");
var bodyHeight = parseInt(getComputedStyle(document.getElementById("container")).height, 10);
var scrollLimit = bodyHeight - window.innerHeight;
var scrollTop = document.getElementById("container").scrollTop;
var scrollPCT = (scrollTop / (scrollLimit / 100)) / 100;
logo.style.top = bodyHeight * scrollPCT - logo.offsetHeight + "px";
};
The desired effect involves a reverse scroll in which an image will move down as the user scrolls down, instead of up, like it normally does.
I guess the computed height does not work? Use the clientHeight property:
var bodyHeight = document.getElementById("container").clientHeight;
(or one of the other height properties)
I have a little problem with window resizing using jQuery's function .resize(). I would like to know which dimension is getting bigger/smaller - width or height. I need this because if I just put two conditions - if width is for 50px bigger than div and if height is for 50px bigger than div,
// (pseudocode)
if width = div.width + 50px
width = something
if height = div.height + 50px
height = something
then is working on just one condition and I can resize only width or height.
How could I know which dimension is changing in size or if both are?
By saving last window size values in variables.
var h = $(window).height(), w = $(window).width();
$(window).resize(function(){
var nh = $(window).height(), nw = $(window).width();
// compare the corresponding variables.
h = nh; w = nw; // update h and w;
});
Save the previous size and compare with it, everytime the size changes.
For ex:
var prevW = -1, prevH = -1;
$(document).ready(function() {
// ... other stuff you might have inside .ready()
prevW = $(window).width();
prevH = $(window).height();
});
$(window).resize(function() {
var widthChanged = false, heightChanged = false;
if($(window).width() != prevW) {
widthChanged = true;
}
if($(window).height() != prevH) {
heightChanged = true;
}
// your stuff
prevW = $(window).width();
prevH = $(window).height();
});
Demo: http://jsfiddle.net/44aNW/
I'm trying to get an image that is around 1920x1200px to pan around on a 800x600px browser window.
So if my mouse is on the top-left of the browser window the image is alined so it's top-left margins are on the top-left of the browser window. The same goes for the bottum-right.
So if the mouse is in the centre of the screen the image should be centered too.
Im not sure what calculations are needed as my math is a bit rusty.
Currently I'm using a bit of javascript that just moves the image using CSS's top/left properties but without much success as it's just moving the picture around from it's top/left corner.
I'v also set the image's position to absolute in css.
function updateImgPosition( e )
{
var avatar = document.getElementById("avatar");
// Width
var windowWidth = window.innerWidth;
var mouseWidthLocation = e.x;
var percentOfWidth = (100 / windowWidth) * mouseWidthLocation;
// Height
var windowHeight = window.innerHeight;
var mouseHeightLocation = e.y;
var percentOfHeight = (100 / windowHeight) * mouseHeightLocation;
avatar.style.top = percentOfHeight + "%";
avatar.style.left = percentOfWidth + "%";
}
document.onmousemove = updateImgPosition;
This is a demo of what I have: http://jsfiddle.net/uQAmQ/1/
Fiddle: http://jsfiddle.net/uQAmQ/2/
You should not "pan" on an absolutely positioned element, because the window's width and height keep changing according to the image. A smoother solution involves using a background image. See the middle of my answer for the used logic.
Consider this JavaScript (read comments; HTML + CSS at fiddle):
(function(){ //Anonymous function wrapper for private variables
/* Static variables: Get the true width and height of the image*/
var avatar = document.getElementById("avatar");
var avatarWidth = avatar.width;
var avatarHeight = avatar.height;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
/* Logic: Move */
var ratioY = (avatarHeight - windowHeight) / windowHeight;
var ratioX = (avatarWidth - windowWidth) / windowWidth;
function updateImgPosition( e ) {
var mouseY = e.pageX; //e.pageX, NOT e.x
var mouseX = e.pageY;
var imgTop = ratioY*(-mouseY);
var imgLeft = ratioX*(-mouseX);
document.body.style.backgroundPosition = imgLeft + "px " + imgTop + "px";
}
/* Add event to WINDOW, NOT "document"! */
window.onmousemove = updateImgPosition;
})();
The logic behind it:
Relative units cannot be used, because the image size is specified in absolute units.
The offsets should change according to a specific ratio, which is similar to: image size divided by window size.However, this ratio is not complete: The image would disappear at the bottom/left corner of the window. To fix this, substract the window's size from the image's size. The result can be found in the code at variable ratioX and ratioY.
The previous code had to be loaded at the window.onload event, because the image's size was dynamically calculated. For this reason, a HTML element was also included in the body.
The same code can be written much smaller and efficient, by specifying the size of the background in the code. See this improved code. Fiddle: http://jsfiddle.net/uQAmQ/3/
(function(){ //Anonymous function wrapper for private variables
/* Static variables: Get the true width and height of the image*/
var avatarWidth = 1690;
var avatarHeight = 1069;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
/* Logic: Move */
var ratioY = (avatarHeight - windowHeight) / windowHeight;
var ratioX = (avatarWidth - windowWidth) / windowWidth;
function updateImgPosition( e ) {
var mouseX = e.pageX; //e.pageX, NOT e.x
var mouseY = e.pageY;
var imgTop = ratioY*(-mouseY);
var imgLeft = ratioX*(-mouseX);
document.body.style.backgroundPosition = imgLeft + "px " + imgTop + "px";
}
/* Add event to WINDOW, NOT "document"! */
window.onmousemove = updateImgPosition;
})();
If you don't mind a decreased code readability, the following code is the best solution, Fiddle: http://jsfiddle.net/uQAmQ/4/:
(function(){ //Anonymous function wrapper for private variables
/* Static variables: Get the true width and height of the image*/
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var ratioY = (windowHeight - 1069) / windowHeight;
var ratioX = (windowWidth - 1690) / windowWidth;
window.onmousemove = function( e ) {
document.body.style.backgroundPosition = ratioX * e.pageX + "px " + ratioY * e.pageY + "px";
}
})();
I'm trying to work out how to enlarge all elements on a page, but keep the centre of enlargement in the centre of the window.
On this page, once the image reaches the top or the left side of the window the centre of enlargement changes. It also changes when you move the image. (exactly what you would expect)
I'm thinking I'd need to take a completely different approach to achieve what I want. But I'm not sure what that approach is..
Any ideas?
Well, here's my take.
Only thing is that I ditched the containers you were using. Is that cheating? Seems like they were only there to get the image centered. No need.
This works as expected with no side effects.
Here's a working demo you can test:
http://jsfiddle.net/YFPRB/1/
(You need to click on the pane with the baboon first.)
HTML
<body>
<img src="http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png" />
</body>
CSS
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
jQuery
EDIT: Thanks to #stagas for the reminder to clean up redundancies.
var $img = $('img'); // Cache the image. Better for performance.
$img.draggable();
$img.css({left: ($('body').width() / 2) - ($img.width() / 2)})
.css({top: ($('body').height() / 2) - ($img.height() / 2)})
$(document).keydown(function(event) {
if (event.keyCode == 38) {
var adjustment = 1.25;
} else if (event.keyCode == 40) {
var adjustment = 0.8;
} else {
return;
}
var offset = $img.offset();
var width = $img.width();
var height = $img.height();
var newWidth = width * adjustment;
var newHeight = height * adjustment;
var diffWidth = newWidth - width;
var diffHeight = newHeight - height;
var hcenter = $('body').width() / 2;
var vcenter = $('body').height() / 2;
var leftPercent = (hcenter - offset.left) / width;
var topPercent = (vcenter - offset.top) / height;
$img.offset({top: offset.top - (diffHeight * topPercent), left: offset.left - (diffWidth * leftPercent)});
$img.width(newWidth).height(newHeight);
});
This is what I came up, it works as you say except the image will always go to the center after zooming in or out:
$('document').ready(function() {
zoomimg=$('#zoomimg'); // we store this in a variable since we don't need to traverse the DOM every time -- this is faster
var viewportWidth = $(window).width();
var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height(); // this is to work with Opera
zoomimg.css({'position': 'absolute', 'left': (viewportWidth/2)-(zoomimg.width()/2), 'top' : (viewportHeight/2)-(zoomimg.height()/2)}).draggable();
$(document).keydown(function(event) {
event = event || window.event;
var viewportWidth = $(window).width();
var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height(); // this is to work with Opera
if (event.keyCode == 38) {
width = zoomimg.width();
height = zoomimg.height();
zoomimg.width(width*1.2).height(height*1.2);
var viewportWidth = $(window).width();
var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height();
zoomimg.css({'left': (viewportWidth/2)-(zoomimg.width()/2), 'top' : (viewportHeight/2)-(zoomimg.height()/2)});
} else if (event.keyCode == 40) {
width = zoomimg.width();
height = zoomimg.height();
zoomimg.width(width*0.8).height(height*0.8);
var viewportWidth = $(window).width();
var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height();
zoomimg.css({'left': (viewportWidth/2)-(zoomimg.width()/2), 'top' : (viewportHeight/2)-(zoomimg.height()/2)});
} else {
return
}
});
});
You should put an ID 'zoomimg' on the tag for it to work, and overflow:hidden on the #container . Also ditch that display:table and display:table-cell they're useless now that we center with Javascript. Also, pressing the down arrow key will cause the container to scroll down, so you should use other keys, as the arrows are reserved by the browser for scrolling the viewport.