I had a problem where I am position a popup <div> in the center of the window using:
var popup = $("#popup"), popupWidth = popup.css("width").replace("px",""), popupHeight = popup.css("height").replace("px","");
var xPosition = ($(window).width() - popupWidth) / 2;
var yPosition = (($(window).height() - popupHeight) / 2) + $(window).scrollTop();
if (yPosition <= 0){
yPosition = '0';
} else if(yPosition <= $(window).scrollTop()){
yPosition = $(window).scrollTop();
} else {
yPosition = yPosition - 68; //minus top shaddow height
}
if (xPosition >= $('body').offset().left) {
xPosition = xPosition;
} else {
xPosition = '0';
}
$(popup).css({
'top': yPosition + 'px',
'left': xPosition + 'px',
'display' : 'block',
'height' : 'auto'
}).addClass("popup-open");
The problem I had was that on first load the height of the popup was being returned as 0 because it is hidden until after the position above has been worked out. To resolve this I set a default height via CSS and then once the popup has been displayed I overwrite this to auto.
The problem now is that if the popup has been closed and re-opened the height is auto. Is there a way to find the CSS height:value in the stylesheet not the inline height:auto
Updated Code
Following Nicola answer here is the fixed code:
var popup = $("#popup"), popupWidth = popup.css("width").replace("px",""), popupHeight = popup.css("height").replace("px","");
// Save/Get original height
if(popupHeight == "auto"){
popupHeight = popup.data('origHeight');
} else {
popup.data('origHeight', popupHeight);
}
var xPosition = ($(window).width() - popupWidth) / 2;
var yPosition = (($(window).height() - popupHeight) / 2) + $(window).scrollTop();
Why don't you save the original values in a variable?
var popup = $("#popup"), popupWidth = popup.css("width").replace("px",""), popupHeight = popup.css("height").replace("px","");
var originalHeight = popupHeight;
var originalWidth = popupWidth;
When you reopen the pop up you use the original values instead of the actual values
Or you could use use data() to store it and retrieve it
$('#popup').data('origHeight', popupHeight);
//the use $('#popup').data('origHeight') to retrieve it
Related
Lets say we have a long scrollable page, and a separate side block, which is shorter than page, but longer than screen height.
I'm trying to make the sidebar always inside the screen by one of it's ends.
When scrolling down, sidebar scrolled until fixes with it's bottom to the bottom of the screen:
Then if you scroll upwards, it will scroll until fixed with top:
So sidebar will never leave the screen.
It is simmilar to bootstrap affix, but with scroll ability.
Seems to be a common feature, saw few sites with this behavior, suprised I couldn't find ready implementation.
I just can't make it right, always find new bugs in unusual situations.
Maybe there is ready solution in some library?
Today I realised I don't need "fixed" positon and can update offset on each scroll.
Here is my code if anyone will search for the same question.
html:
<div id="screen">
<div id="page">
</div>
<div id="sidebar">
</div>
</div>
js:
var margin = 0;
var sidebarIsFixed = false;
var lastScroll = 0;
var topOffset = 0;
var sidebar = document.getElementById('sidebar');
var screen = document.getElementById('screen');
var yPos = undefined;
function OnBodyScroll() {
if (yPos == undefined) {
yPos = 0;
var parent = sidebar.offsetParent;
while (parent && parent != screen) {
yPos += parent.offsetTop;
parent = parent.offsetParent;
}
margin = sidebar.offsetTop;
topOffset = margin;
}
var windowHeight = screen.clientHeight;
var barHeight = sidebar.clientHeight;
var scroll = screen.scrollTop;
if (scroll >= lastScroll) {
if (scroll + windowHeight > yPos + topOffset + barHeight + margin) {
topOffset = scroll -yPos + windowHeight - barHeight - margin;
sidebar.style.marginTop = topOffset + "px";
}
} else {
if (scroll < yPos + topOffset - margin) {
topOffset = scroll - yPos + margin;
if (topOffset < margin) {
topOffset = margin;
}
sidebar.style.marginTop = topOffset + "px";
}
}
lastScroll = scroll;
}
screen.onscroll = OnBodyScroll;
OnBodyScroll();
http://jsfiddle.net/ilyad/da543f40/3/
chrome.browserAction.onClicked.addListener(function (tab) {
var currentWidth = 0;
var currentHeight = 0;
chrome.windows.getCurrent(function(w) {
// You can modify some width/height here
alert(w.top);
currentWidth = w.left / 2;
currentHeight = w.top / 2;
});
var w = 440;
var h = 220;
var left = (screen.width / 2) - (w / 2) - currentWidth;
var top = (screen.height / 2) - (h / 2) - currentHeight;
chrome.windows.create({
'type': 'popup',
'width': w,
'height': h,
'left': left,
'top': top}, function (window) {
chrome.tabs.executeScript(newWindow.tabs[0].id, {
code: 'document.write("hello world");'
});
});
});
The window shows up in the middle but when the current window is resized to a smaller view, the window shows up at where the center of the screen would be not at the center of current window.
When I remove the /2 from currentHeight or currentWidth, the window shows, but it's at the wrong location (too far off to one side).
You're misusing the asynchronous API.
See this answer for a general description of the problem.
In your case, it should sufficient to move the logic into your first callback:
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.windows.getCurrent(function(win) {
var currentWidth = 0;
var currentHeight = 0;
var width = 440;
var height = 220;
// You can modify some width/height here
alert(win.top);
currentWidth = win.left / 2;
currentHeight = win.top / 2;
var left = (screen.width / 2) - (width / 2) - currentWidth;
var top = (screen.height / 2) - (height / 2) - currentHeight;
chrome.windows.create(
{
'type': 'popup',
'width': width,
'height': height,
'left': left,
'top': top
}, function (window) {
chrome.tabs.executeScript(window.tabs[0].id, {
code: 'document.write("hello world");'
});
}
);
});
// Here, currentWidth/currentHeight is not assigned yet
});
I made a carousel using 2 divs named "left" and "right" putting mousemove events on them. I wanted to make it go up and down as well so I created a "top" and "bottom" and noticed that I couldn't make them combine to go the way the cursor goes.
I thus thought of targeting a specific area in the container (i.e top half of my container div) instead of creating divs inside triggering a specific direction, this way (I think) I can trigger all these event altogether. However after now hours of research I couldn't find a way to do so.
How should I proceed ? here is the code : http://jsfiddle.net/pool4/vL5g3/3/
var x=0,
y=0,
rateX=0,
rateY=0,
maxspeed=10;
var backdrop = $('.backdrop');
$('.directionx', backdrop).mousemove(function(e){
var $this = $(this);
var left = $this.is('.left');
var right = $this.is('.right');
if (left){
var w = $this.width();
rateX = (w - e.pageX - $this.offset().left + 1)/w;
}
else if (right){
var w = $this.width();
rateX = -(e.pageX - $this.offset().left + 1)/w;
}
});
$('.directiony', backdrop).mousemove(function(e){
var $this = $(this);
var top = $this.is('.top');
var bottom = $this.is('.bottom');
if (top){
var h = $this.height();
rateY = (h - e.pageY - $this.offset().top + 1)/h;
}
else if (bottom) {
var h = $this.height();
rateY = -(e.pageY - $this.offset().top + 1)/h;
}
});
backdrop.hover(
function(){
var scroller = setInterval( moveBackdrop, 30 );
$(this).data('scroller', scroller);
},
function(){
var scroller = $(this).data('scroller');
clearInterval( scroller );
}
);
function moveBackdrop(){
x += maxspeed * rateX;
y += maxspeed * rateY;
var newpos = x+'px '+y+'px';
backdrop.css('background-position',newpos);
}
Your problem is that the divs that control movement up and down are placed over the ones that control left and right, so the latter do not receive the mousemove event ever. Mouse events do not propagate through layers, even if they're transparent. I changed your code and CSS, so each div is in one of the corners. To make things easier, I've used data-* attributes so the direction controlled by each div is set in a declarative way, without the need to change the code. You'll see that the code is much simpler (and it could be simplified even more).
By the way, you could achieve this witout extra divs, just controlling where the cursor is (to the top, right, left or bottom of the center of the div).
backdrop.on('mousemove', '.dir', function(e){
var $this = $(this);
var direction = $(e.target).attr('data-direction');
var left = direction.indexOf('left') > - 1;
var right = direction.indexOf('right') > - 1;
var top = direction.indexOf('up') > - 1;
var bottom = direction.indexOf('down') > - 1;
if (left){
var w = $this.width();
rateX = (w - e.pageX - $this.offset().left + 1)/w;
}
else if (right){
var w = $this.width();
rateX = -(e.pageX - $this.offset().left + 1)/w;
}
if (top){
var h = $this.height();
rateY = (h - e.pageY - $this.offset().top + 1)/h;
}
else if (bottom) {
var h = $this.height();
rateY = -(e.pageY - $this.offset().top + 1)/h;
}
});
I've updated your fiddle.
EDIT In this new fiddle I do it without extra divs:
var w = backdrop.width() / 2;
var h = backdrop.height() / 2;
var center = {
x: backdrop.offset().left + backdrop.width() / 2,
y: backdrop.offset().top + backdrop.height() / 2
};
backdrop.on('mousemove', function(e){
var offsetX = e.pageX - center.x;
var offsetY = e.pageY - center.y;
rateX = -offsetX / w;
rateY = -offsetY / h;
});
backdrop.hover(
function(){
var scroller = $(this).data('scroller');
if (!scroller) {
scroller = setInterval( moveBackdrop, 30 );
$(this).data('scroller', scroller);
}
},
function(){
var scroller = $(this).data('scroller');
if (scroller) {
clearInterval( scroller );
$(this).data('scroller', null);
}
}
);
As you see, the mousmove handler is considerably simpler.
To avoid issue of children losing event could use just the one.
First HTML from 4 child divs to just one
<div class="backdrop">
<div class="direction"></div>
</div>
<div id="pos"></div>
Next Inside the mousemove find your relative position
//Get Relative Position
var relX = e.pageX - $this.offset().left;
var relY = e.pageY - $this.offset().top;
Get Relative Position as a percentage of width and put 50% of it in negative for direction
var w = $this.width();
rateX = ((relX / w) - 0.5) * -1;
var h = $this.height();
rateY = ((relY / h) - 0.5) * -1;
Fiddle
As you can see the image below, there is "A", "B", "C", "D" and "E" on the website, and the user may only can see the A, B, and a little parts of D in their browser. They need to require to scroll down the browser or some users may have a bigger screen, or a longer window on their browser that allow they can even see the element C.
Ok, my question is, is this possible to let me know what the user seeing on their browser using javascript? In this element, is "A", "B" and "D".
Using the following, you can get the browser's viewport size.
window.innerHeight;
window.innerWidth;
Refer to: http://www.javascripter.net/faq/browserw.htm
If you want to detect how far they have scrolled down the page, you can use
window.scrollX; // Horizontal scrolling
window.scrollY; // Vertical scrolling
Also, I have found a window object - window.screen. On my system it has the following data:
window.screen.availHeight = 994;
window.screen.availLeft = 0;
window.screen.availTop = 0;
window.screen.availWidth = 1280;
window.screen.colorDepth = 32;
window.screen.height = 1280;
window.screen.pixelDepth = 32;
window.screen.width = 1280;
Try it :) http://jsfiddle.net/Aj2fU/5/
$('input').click(function(){
// check for visible divs with class 'check'
$('.check').each(function(){
var pos = $(this).offset(),
wX = $(window).scrollLeft(), wY = $(window).scrollTop(),
wH = $(window).height(), wW = $(window).width(),
oH = $(this).outerHeight(), oW = $(this).outerWidth();
// check the edges
// left, top and right, bottom are in the viewport
if (pos.left >= wX && pos.top >= wY &&
oW + pos.left <= wX + wW && oH + pos.top <= wY + wH )
alert('Div #' + $(this).attr('id') + ' is fully visible');
else // partially visible
if (((pos.left <= wX && pos.left + oW > wX) ||
(pos.left >= wX && pos.left <= wX + wW)) &&
((pos.top <= wY && pos.top + oH > wY) ||
(pos.top >= wY && pos.top <= wY + wH)))
alert('Div #' + $(this).attr('id') + ' is partially visible');
else // not visible
alert('Div #' + $(this).attr('id') + ' is not visible');
});
});
Updated to work with very wide divs. Basically it checks whether the left, top and right, bottom edges of the divs are both in the visible part of the screen, partially or outside of the viewport.
Basically, you'd first have to measure the viewport dimentions, by using the window object, then you'd need to loop through each of the elements that you want to check, and calculate wether they fit.
See this jsfiddle for an example.
Here's the code (for posterity's sake):
HTML:
<div id="info">
<p class="wxh"></p>
<p class="txl"></p>
<p class="report"></p>
</div>
<h1>A big list!</h1>
<ul></ul>
CSS:
#info{
position: fixed;
right: 0px;
text-align: center;
background: white;
border: 2px solid black;
padding: 10px;
}
JS:
$(function(){
$(window).bind('scroll.measure resize.measure',function(){
// Gather together the window width, height, and scroll position.
var winWidth = $(window).width(),
winHeight = $(window).height(),
winLeft = $(window).scrollLeft(),
winTop = $(window).scrollTop(),
winBottom = winTop + winHeight,
winRight = winLeft + winWidth,
inView = [];
// Loop over each of the elements you want to check
$('.inview').each(function(){
// Get the elements position and dimentions.
var pos = $(this).position(),
width = $(this).outerWidth(),
height = $(this).outerHeight();
// Set bottom and right dimentions.
pos.bottom = pos.top + height;
pos.right = pos.left + width;
// Check whether this element is partially within
// the window's visible area.
if((
pos.left >= winLeft &&
pos.top >= winTop &&
pos.right <= winRight &&
pos.bottom <= winBottom
) || (
pos.left >= winLeft && pos.top >= winTop &&
pos.left <= winRight && pos.top <= winBottom
) || (
pos.right <= winRight && pos.bottom <= winBottom &&
pos.right >= winLeft && pos.bottom >= winTop
)){
// Change this to push the actual element if you need it.
inView.push( $(this).text() );
}
});
// For the purposes of this example, we only need the
// first and last element, but in your application you may need all.
var first = inView.shift(),
last = inView.pop();
// Show the details in the info box.
$('#info .wxh').text( winWidth+' x '+winHeight );
$('#info .txl').text( winTop+' x '+winLeft );
$('#info .report').text( 'Showing from '+first+' to '+last );
});
// The rest is just setup stuff, to make the area scrollable.
for( var i=0; i<100; i++ ){
$('ul').append('<li class="inview">List item '+i+'</li>');
}
$(window).trigger('resize.measure');
})
You can get window's visible area by,
var pwidth = $(window).width();
var pheight = $(window).height();
Then get document scroll,
$(document).scroll(function(e) {
var top = $(this).scrollTop();
$("h1").html("total visible area is from:"+ top +" to "+ (pheight + top) +"px");
});
Full example is here : http://jsfiddle.net/parag1111/kSaNp/
I am having a Tooltip (larger image view) that is being positioned via e.pageX e.pageY and i am trying to make sure it is not hidden below the current scrolled view port.
I have seen many sites have this
my code is something like this but i am missing something.
var positionImg = function(e) {
var viewportWidth = $(window).width();
var viewportHeight = window.innerHeight ? window.innerHeight : $(window).height();
var mouseAtY = e.pageY;
var mouseAtX = e.pageX;
var maxBottomVPos = viewportHeight-"i dont know";
var maxTopVPos = 30;
if (mouseAtY >= maxBottomVPos)
{
tPosX = mouseAtX+ 10;
tPosY = mouseAtY -520;
}
else if (mouseAtY <= maxTopVPos)
{
tPosX = mouseAtX;
tPosY = mouseAtY +40;
}
else
{
tPosX = mouseAtX;
tPosY = mouseAtY +20;
}
$zoomContainer.css({top: tPosY, left: tPosX});
};
var maxBottomVPos = viewportHeight-"i dont know";
You probably don't want to go any lower than the height of the element that you are positioning. So use the height of zoomContainer to figure out how much higher it needs to go. This way, the whole thing can be included. Of course, you'll have to consider that the user might shrink the screen too small to fit the container.
To get the scroll offset use scrollTop. With this you will have both the size of the viewport and how far down the viewport is.
I found the answer:
Quite simple:
var positionImg = function(e) {
cntnrH = $zoomContainer.height() + 230;
calHight = e.pageY - $(window).scrollTop() + cntnrH;
docH = $(window).height()
var mouseAtY = e.pageY;
var mouseAtX = e.pageX;
if (calHight >= docH)
{
tPosX = mouseAtX + 5;
tPosY = mouseAtY - cntnrH;
}
else if (calHight <= calHight){
tPosX = mouseAtX;
tPosY = mouseAtY + 15;
}
else
{
tPosX = mouseAtX;
tPosY = mouseAtY +20;
}
$zoomContainer.css({top: tPosY, left: tPosX});
};
doIt = $("img.hovelble");
doIt.hover(showZoomImg, hideZoomImg).mousemove(positionImg);
});