I have a problem with a JavaScript I'm developing for my website. I have images which opens on hovering over them.
First my script calculates if the image should be displayed on the right or on the left of my window:
$("html,body").live("mousemove", function (e) {
//console.log("mousemove: "+e.pageX)
var width_window = $(window).width();
var center = width_window / 2;
if (e.pageX < center) {
side = 'left';
} else {
side = 'right';
}
});
Then, once we know on which side of the window the image will be displayed, I have another script to resize the image, depending of the height & width of my window, including the margins:
this.resizeImg = function (img, offset) {
var d = new Date();
//console.log(d, side);
var window_height = $(window).height();
var img_height = $(img).height();
var img_top = $(img).offset().top;
var window_width = $(window).width();
var img_width = $(img).width();
var img_left;
side == 'left' ? img_left = offset.left : img_left = window_width - offset.left;
console.log(window_width, img_left)
var image_resize_height = window_height - img_top - 20;
var image_resize_width = window_width - img_left - 20;
if (img_height + img_top > window_height && img_width + img_left > window_width) {
console.log("h w")
if (image_resize_width > image_resize_height) {
$(img).css('height', image_resize_height + 'px').css("width", "auto");
} else {
$(img).css('width', image_resize_width + 'px').css("height", "auto");
}
} else if (img_height + img_top > window_height) {
//console.log("h")
$(img).css('height', image_resize_height + 'px').css("width", "auto");
} else if (img_width + img_left > window_width) {
//console.log("w")
$(img).css('width', image_resize_width + 'px').css("height", "auto");
} else {
//console.log("non")
}
};
It almost works, but sometimes my images exceed the window width or height. I can't find the solution...
Here is my CSS:
.vignette {
max-height: 800px;
max-width : 800px;
z-index : 2;
top : 25px;
}
.info{
position : relative;
}
.info img {
position : absolute;
display : none;
cursor : pointer;
}
My full script in jsFiddle: http://jsfiddle.net/CrnNZ/
Here is the link to my website : http://olivierlellouche.com/
Thanks a lot for your help !
Are you taking care of the fact that you are moving the image down 25px in:
.vignette {
top : 25px;
}
The only height adjustment I see is 20px:
var image_resize_height = window_height - img_top - 20;
You may just need to subtract few more pixels to your calculations?
Or better yet:
var img_top = $(img).offset().top;
May be top of the offset area and not the raw top of the image. In which case, you still need to subtract 25px for that.
(From your website) The other thing that may be useful is to always enable, or always disable the vertical scroll-bar on the right. Or re-size the text area to be smaller than the available area when their isn't a scroll-bar. (Unfortunately, I could not get your jsfiddle to work at all and the only error from their I could view was vertical calculation errors. I could not see any horizontal errors.)
Does the problem continue if you subtract a few more pixels off the height?
I can't tell from your code but, does it place the image then re-size it? It may be better idea to calculate the size available before trying to place the image, that way it never changes sizes once it is placed.
EDIT:
After looking at your webpage with much smaller sized window I thought of something else. $(window).height() is not the same as $(document).height(). See: $(window).height() vs $(document).height You may need to calculate the remaining page differently if they are not the same.
Related
I would like to add left margin and right margin to the body to hide the width change when I hide the vertical scrollbar.
I have this code that finds the width of the vertical scrollbar:
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
var scrollbarwidth = 100 - widthWithScroll;
It gives the value "17" (in pixels) for IE11, Chrome 45, and Firefox 39 (desktop).
When I hide the vertical scrollbar, all elements, such as images, jump exactly 17 pixels to the right, which I want to hide.
I have tried:
document.body.style.marginRight = scrollbarwidth + "px";
$('body').css('margin-right', scrollbarwidth);
$(body).css("marginRight", scrollbarwidth + "px");
The last one might be faulty in some way, since other parts of the function stops working when it's enabled. The two others don't seem to work either, as I don't see any margin changes.
EDIT 1: For easier understanding of how I am going to use it, I wanted to mention that it's supposed to trigger on a on scroll function, like this:
var check1 = false;
$(document).bind('scroll', function() {
if(check1 === false && $(window).scrollTop() >= $('#divscrolltester').offset().top + $('#divscrolltester').outerHeight() - window.innerHeight) {
check1 = true;
unloadScrollBars();
disableScroll();
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
var scrollbarwidth = 100 - widthWithScroll;
//document.body.style.paddingRight = scrollbarwidth + "px"; Temporary disabled.
//$('body').css('padding-right', scrollbarwidth); Temporary disabled.
//$(body).css("marginRight", scrollbarwidth + "px"); Temporary disabled.
setTimeout(function() {
enableScroll();
reloadScrollBars();
//document.body.style.paddingLeft = scrollbarwidth + "px"; Temporary disabled.
//$('body').css('padding-left', scrollbarwidth); Temporary disabled.
//$(body).css("marginLeft", scrollbarwidth + "px"); Temporary disabled.
}, 500);
}
});
EDIT 2:
Here is a Fiddle to show most of the js, html and css: https://jsfiddle.net/tfnwj7dj/10/.
I haven't added the change of css through code yet, as I'm still trying to solve the issue. Also, the scrolling and scrollbar are supposed to be re-enabled in a second, but there seems to be an error in there somewhere, sorry.
EDIT 3:
For your information at this moment, these lines work:
document.body.style.paddingLeft = (scrollbarwidth) + "px";
$('body').css('padding-left', scrollbarwidth);
document.body.style.paddingRight = (scrollbarwidth) + "px";
$('body').css('padding-right', scrollbarwidth);
document.body.style.marginLeft = (scrollbarwidth) + "px";
$('body').css('margin-left', scrollbarwidth);
document.body.style.marginRight = (scrollbarwidth) + "px";
$('body').css('margin-right', scrollbarwidth);
Maybe you have enough information to solve it, if you have the same issue, but unfortunately, this wasn't enough for me. It might be important info to know that I have my content centered with a width / max-width of just 500px, and that I don't actually have a body class. Maybe on designs with width="100%", or elements with absolute positioning, the lines might be enough.
Both javascript and jquery solutions are welcomed.
EDIT 4:
I finally solved it for my own circumstances - feel free to read the answer below. It works for preventing elements to jump when hiding the vertical scrollbar, and with some tinkering, it could probably do for a body class, or other situations.
Is your scrollbarwidth integer? Try this
var scrollbarwidth = 100;
$('body').css('margin-right', scrollbarwidth);
Maybe you have wrong value at scrollbarwidth ? In my ff this code works.
I managed to solve it - I'd like to clarify that my css actually don't contain a body class, and that I just centered all elements with a width / max-width of 500px and margin-left/right auto.
For my and other, similar cases, here is the answer:
/* First 5 lines for finding the scrollbar width. */
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
var scrollbarwidth = 100 - widthWithScroll;
var scrollbarwidthadjustment = scrollbarwidth / 2; /* For centered elements, divide the scrollbar width by 2. */
var element = document.getElementById('element');
element.style.right = (scrollbarwidthadjustment) + "px";
And when you re-enable the vertical scrollbar, simply add:
element.style.right = "0px";
Also, the element must have a css position stated, otherwise it won't trigger. Here is an example of a css style that works:
.examplestyle {
color: white;
position: relative;
margin-left: auto;
margin-right: auto;
max-width: 100%;
display: block;
}
EDIT 1:
To prevent some unsightly css errors on mobile devices, add these lines:
/* ... */
var scrollbarwidthadjustment = scrollbarwidth / 2;
var windowWidth = $(window).width(); /* Get current window width on click/scroll etc. */
var window1 = windowWidth + scrollbarwidth; /* Window width + scrollbar width. */
var element = document.getElementById('element');
if(window1 >= widthofelement) {element.style.right = (scrollbarwidthadjustment) + "px";}
else {}
EDIT 2:
Fix for image resized smaller than its original size:
var offsetwidth = element.offsetWidth;
var widthadjustment = offsetwidth - scrollbarwidth; /* Get full width of image when scrollbar hidden, and then remove the scrollbar width. */
if(window1 < widthofelement && scrollbarwidth > 0) {
element.style.width = widthadjustment + "px";
element.style.right = (scrollbarwidthadjustment) + "px";
}
And then this code when showing the Y-scrollbar again:
if(window1 < widthofelement && scrollbarwidth > 0) {
element.style.width = "OriginalSizepx";
element.style.right = "0px";
}
If you want to use every edit that I have added, here is the full code:
/* First 5 lines for finding the scrollbar width. */
var $outer = $('<div>').css({visibility: 'hidden', width: 100, overflow: 'scroll'}).appendTo('body'),
widthWithScroll = $('<div>').css({width: '100%'}).appendTo($outer).outerWidth();
$outer.remove();
var scrollbarwidth = 100 - widthWithScroll;
var scrollbarwidthadjustment = scrollbarwidth / 2; /* For centered elements, divide the scrollbar width by 2. */
var element = document.getElementById('element'); /* Put element ID into a variable for easier use, and consecutive uses without re-identifying it. */
var window1 = windowWidth + scrollbarwidth; /* Window width + scrollbar width. */
var offsetwidth = element.offsetWidth; /* Get exact element size in current window. Shows shown dimensions when the window is resized. */
var widthadjustment = offsetwidth - scrollbarwidth; /* Get full width of image when scrollbar hidden, and then remove the scrollbar width. */
if(window1 >= widthofelement) {element.style.right = (scrollbarwidthadjustment) + "px";} /* If current window is equal to or greater than element width... */
if(window1 < widthofelement && scrollbarwidth > 0) { /* If current windows is smaller than the element width, and the window has a scrollbar greater than 0 pixels in width. */
element.style.width = widthadjustment + "px";
element.style.right = (scrollbarwidthadjustment) + "px";
}
/* When re-enabling the Y-scrollbar again; */
if(window1 >= widthofelement) {element.style.right = "0px";}
if(window1 < widthofelement && scrollbarwidth > 0) {
element.style.width = "OriginalSizepx";
element.style.right = "0px";
}
For further clarification, this code will prevent elements from jumping to the right when you hide the vertical scrollbar.
padding is your answer, as Shikkediel said. Just change margin to that and it'll work.
The items move because you change the default margin body has, so the whole body moves to the left (in case we are modifying margin-right).
If you remove the scroll bar, the default margin will go right behind it, and then you need to "buffer" the rest, left of the margin, and that's what padding does.
I really enjoy working with the Inspecting tool Chrome supplies (Ctrl + Shift + I) and then in the Styles tab on the right scorll down until you see the measurements. It really helps understand the CSS box model.
Did you add 'px' here..
$('body').css('margin-right', scrollbarwidth+'px')??
Just nowI tried in w3schools. If you add 'px' to above syntax, it is working for me.
Got a strange issue, my tag has a greater width than my monitor, which it shouldn't. I have some JavaScript which gets the scroll offset and adjusts my background, to give it a parallax effect, but as you can see, once the background gets given an 100% width, it snaps and stretches out. You can see this by zooming out of the page, the background is larger.
Here is the website
Any idea what is going wrong with it? Here is my JavaScript, and view the CSS by inspecting the element. It has also gone a bit slow as well to be honest, was working nice and smooth.
var ismobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
if (!ismobile){
window.onresize = function(event) {
//Detect window size and make new padding
if (window.innerWidth > 835) {
var newPadding = parseInt(window.innerHeight)/2.8;
newPadding = newPadding.toFixed(0);
var limitPadding = 221;
//Apply new padding value to header
if (newPadding > limitPadding) {
doc("header").style.padding = newPadding + "px 0px";
}
}
}
window.onscroll = function() {
var speed = 0.7;
var newPos = "100% " + (window.pageYOffset * speed) + "px";
document.body.style.backgroundPosition = newPos;
}
}
Add the overflow property to your body tag...
body {overflow-X: hidden;}
I'm currently working on this script for "tooltips" on a website. I'm finding that the code I currently have will get the image height for my first tooltip image on the page ('pop1') but it ignores the rest (they come out as null).
What's the most effective way to get all the tooltip image heights, and use them every time the user scrolls over the tooltip image?
Another issue, if anyone is able to figure this one out - is that on my FULL webpage (many more divs, rows, columns, etc.) the script begins to break because clientX and clientY are being affected by the various divs and page elements.
I'd like to be able to set clientX and clientY to the exact (x, y) coordinates that the user's mouse is at, relative to the entire webpage, not relative to the page's child elements.
Thanks
Here's my JSFiddle: http://jsfiddle.net/tgs7px4f/18/
JS Code:
$('a.popper').hover(function (e) {
var target = '#' + ($(this).attr('data-popbox'));
$(target).show();
}, function () {
var target = '#' + ($(this).attr('data-popbox'));
if (!($("a.popper").hasClass("show"))) {
$(target).hide();
}
});
$('a.popper').mousemove(function (e) {
var target = '#' + ($(this).attr('data-popbox'));
// images vary in height!
// images are all 366px wide.
var imageWidth = 366;
var imageHeight = $(".popimg").height();
//alert('Image Height: ' + imageHeight);
//Offset tooltip:
//10px to the right of cursor
var imageX = e.clientX + 20;
//imageHeight up from cursor
var imageY = e.clientY - imageHeight - 20;
// Find bounds of current window, and if...
// Tooltip goes off right side:
if ((imageX + imageWidth) > $(window).width()) {
//Move tooltip left so it meets edge:
imageX = $(window).width() - imageWidth;
}
// Tooltip goes off top
if (imageY < 0) {
//Move tooltip down so it meets top:
imageY = 0;
}
$(target).css('top', imageY).css('left', imageX);
});
What's the most effective way to get all the tooltip image heights, and use them every time the user scrolls over the tooltip image?
First of all, I suppose you mean whenever a user does a mouseover on one of the elements? However, this seems to work and it cashes the height of the image directly on the element and uses it the next time a mouseover occurs:
$('a.popper').mousemove(function (e) {
var target = '#' + ($(this).attr('data-popbox'));
// images vary in height!
// images are all 366px wide.
var imageWidth = 366;
$target = $(target);
if (!$target.attr("height")) {
var img = $target.closest(".popbox").children("img");
var imageHeight = img.height();
$target.attr("height", imageHeight);
console.log("height attribute set");
} else {
var imageHeight = +($target.attr("height")) + 0;
console.log("cached height used");
}
console.log('Image Height: ', imageHeight);
//Offset tooltip:
//10px to the right of cursor
var imageX = e.clientX + 20;
//imageHeight up from cursor
var imageY = e.clientY - imageHeight - 20;
// Find bounds of current window, and if...
// Tooltip goes off right side:
if ((imageX + imageWidth) > $(window).width()) {
//Move tooltip left so it meets edge:
imageX = $(window).width() - imageWidth;
}
// Tooltip goes off top
if (imageY < 0) {
//Move tooltip down so it meets top:
imageY = 0;
}
$(target).css('top', imageY).css('left', imageX);
});
Obviously, you should remove all the console.log statements which are for testing purposes only.
jsFiddle
Regarding your second question, it's hard to say anything concrete without another jsFiddle or additional code.
Imagine I have the below element appended to the document :
<html>
<head>
<style>
#resizable {
position: absolute;
top: 30px;
left: 30px;
background: url(http://www.some243x350image.jpg) no-repeat;
height: 243px;
width: 350px;
background-size: contain;
}
</style>
</head>
<body>
<div id="resizable"></div>
</body>
</html>
I'd like to be able to resize the above div proportionally, without any max/min height/width limits.
Below is the code I've written (Working Example : http://jsfiddle.net/7wYAh/) but it has two main bugs :
1. The div's height and width do not change proportionally all the time (even though the image obviously does, given that I'm using background-size: contain;.
2. There are sudden increases/decreases in the height/width of the element the moment the element is "grabbed".
I'm not using an aspect ratio variable. What I'm doing is that I choose randomly whether to resize based on height or width every time. So if the height changes then I'll resize the width based on the height increase. And vice versa. Isn't that proportional as well? Meaning that if the height increases by 2px, I'll increase the width by 2px as well and vice versa.
Looking for an answer to my problem I found this post but I don't want to use width/height limits and I don't understand the use of the ratio.
So can you spot anything wrong with this code (assume that the elementCanBeResized is set to true whenever the mouse grabs the bottom right corner of the div) :
Working Example : http://jsfiddle.net/7wYAh/
var $element = $('#resizable');
var previousResizeX, previousResizeY, resizeDistanceX, resizeDistanceY;
$(window).mousemove(function (mouseCoordinates)
{
if (!elementCanBeResized)
{
return;
}
if (typeof previousResizeX === 'undefined')
{
previousResizeX = mouseCoordinates.pageX;
previousResizeX = mouseCoordinates.pageY;
}
else
{
var newResizeX = mouseCoordinates.pageX;
var newResizeY = mouseCoordinates.pageY;
// resizing proportionally based on width change
if (newResizeX !== previousResizeX)
{
resizeDistanceX = newResizeX - previousResizeX;
previousResizeX = newResizeX;
previousResizeY += resizeDistanceX;
newWidth = $element.width() + resizeDistanceX;
newHeight = $element.height() + resizeDistanceX;
}
// resizing proportionally based on height change
else if (newResizeY !== previousResizeY)
{
resizeDistanceY = newResizeY - previousResizeY;
previousResizeY = newResizeY;
previousResizeX += resizeDistanceY;
newHeight = $element.height() + resizeDistanceY;
newWidth = $element.width() + resizeDistanceY;
}
$element.css({
height: newHeight,
width: newWidth
});
}
});
I assume that you want to resize by clicking at some point and then 'dragging' de mouse. Okay.
To question 2: You are storing the point where you click in previousResizeX. But I don't see you cleaning its value after the release of the button. If you don't set previousResizeX to 'undefined' again, next time you click there will be a 'sudden change' of width/height because newResizeX will be the distance between the place where you pressed the mouse the first time and its current position.
To question 1: You are increasing the width/height the same number of pixels every time, that's why your div doesn't resize proportionally. I explain: if you start with a div that's 200 x 100, its width is the double of the height. When you duplicate its width, to be proportional you have to duplicate the height. But if you drag your mouse 100px, you'll end with a (200+100) x (100 + 100) div, which is 300 x 200. The image's width is no longer the double of its height. You need to calculate the ratio between width and height at the beginning:
var ratio = $element.height() / $element.width();
...
resizeDistanceX = newResizeX - previousResizeX;
resizeDistanceY = resizeDistanceX * ratio;
previousResizeX = newResizeX;
previousResizeY += resizeDistanceY;
newWidth = $element.width() + resizeDistanceX;
newHeight = $element.height() + resizeDistanceY;
...
//For Y
resizeDistanceY = newResizeY - previousResizeY;
resizeDistanceX = resizeDistanceY / ratio;
previousResizeY = newResizeY;
previousResizeX += resizeDistanceX;
newHeight = $element.height() + resizeDistanceY;
newWidth = $element.width() + resizeDistanceX;
And remember to set resizeDistanceX and resizeDistanceY once the mouse is released.
Hope this helps you.
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.