I'm trying to create snap to top divs that cover the entire page and I have it working, it's just that after they snap to the top they don't unsnap and stay fixed to the top. I'm using the answer given by mu is too short from this previous question scroll then snap to top but I can't get it to unsnap.
Here's a jsbin of the code.
var h = 0;
var notif;
var notif2;
var init;
var docked = false;
function getSize() {
h = window.innerHeight;
notif = document.getElementById("notif");
notif2 = document.getElementById("notif2");
var fl = document.getElementById("floater");
init = notif.scrollTop;
notif.style.top = "" + h + "px";
var h2 = h / 2;
fl.style.marginTop = "" + h2 + "px";
notif.style.height = "" + h + "px";
var twoh = 3 * h2;
notif2.style.top = "" + h + "px";
notif2.style.height = "" + h + "px";
}
window.onscroll = function() {
if (!docked && (notif.offsetTop - document.body.scrollTop < 0)) {
console.log("in loop");
notif.style.top = 0;
notif.style.position = 'fixed';
notif2.style.marginTop = "" + h + "px";
docked = true;
} else if (docked && document.body.scrollTop <= init) {
notif.style.position = 'block';
while (notif.style.top <= h) {
var ab = Math.abs(notif.offsetTop)
var ab2 = Math.abs(document.body.scrollTop);
notif.style.top = init + 'px';
}
if (notif.style.top == h || notif.style.top == h - 1) {
docked = false;
}
}
};
<body onload="getSize()">
<div class="contain">
<div id="floater">
<h1 class="white">Hello, World</h1>
Link 1 Link 2
</div>
</div>
<div class="announcements" id="notif">
Please cover the previous text on the page. If this works i will be really excited.
</div>
<div class="announcements2" id="notif2">
Cover the white page.
</div>
</body>
Save the values used before you set these, and reset them when you "un-dock". Simply setting "docked" to show that you're un-docked is not enough.
This code is an example of how to do that from your staring point.
Here's how I saved it and got something like the behaviour you mention
var h = 0;
var notif;
var notif2;
var init;
var docked = false;
// holding space for reset values
var holdNotifyStyleTop;
var holdNotifyOffsetTop;
var holdNotif2StyleMarginTop;
function getSize() {
h = window.innerHeight;
notif = document.getElementById("notif");
notif2 = document.getElementById("notif2");
var fl = document.getElementById("floater");
init = notif.offsetTop;
notif.style.top = ""+h+"px";
var h2 = h/2;
fl.style.marginTop = ""+h2+"px";
notif.style.height = ""+h+"px";
var twoh = 3*h2;
notif2.style.top=""+h+"px";
notif2.style.height = ""+h+"px";
}
window.onscroll = function () {
if (!docked && (notif.offsetTop - document.body.scrollTop < 0)) {
console.log("--- DOCKING ---");
// save current values
holdNotifyStyleTop = notif.style.top;
holdNotifyOffsetTop = notif.offsetTop;
holdNotif2StyleMarginTop = notif2.style.marginTop;
notif.style.top = 0;
notif.style.position = 'fixed';
notif2.style.marginTop=""+h+"px";
docked = true;
} else if (docked && document.body.scrollTop <= init) {
console.log("--- Un-DOCKING ---");
notif.style.top = holdNotifyStyleTop;
notif.style.position = 'relative';
notif2.style.marginTop=holdNotif2StyleMarginTop;
notif.offsetTop = holdNotifyOffsetTop;
docked = false;
}
};
Related
I'm trying to spawn randomly generated targets on the screen using a function to copy an invisible image of the target to be spawned at a random place within the screen using window object properties.
For this to happen I think the image have to have position set to absolute, but then several images may be spawned in a way that they will overlap, how can I prevent this from happening?
The div element where I copy my first image and also store the other copies.
<div id="targetsDiv">
<img src="target2.png" alt="target_shot" class="target" />
</div>
Inside the script:
var x_pixels = window.innerWidth - 180;
var y_pixels = window.innerHeight - 180;
var x_midScreen = window.innerWidth / 2;
var y_midScreen = window.innerHeight / 2;
var xRandom = Math.floor(Math.random()*x_pixels) +1;
var yRandom = Math.floor(Math.random()*y_pixels) +1;
var targetCollection = document.getElementById("targetsDiv");
var targetCopy = targetCollection.innerHTML
var targetList = document.getElementsByClassName("target");
targetList[0].style.display = "none";
var targetNr = 1;
var numberOfSpawns = 3;
function spawnTargets () {
while (targetNr <= numberOfSpawns) {
if ((xRandom < x_midScreen - 126 || xRandom > x_midScreen + 26) || (yRandom < y_midScreen - 126 || yRandom > y_midScreen + 26)) {
targetCollection.innerHTML += targetCopy;
targetList[targetNr].style.left = xRandom + "px";
targetList[targetNr].style.top = yRandom + "px";
targetNr++;
}
xRandom = Math.floor(Math.random()*x_pixels) +1;
yRandom = Math.floor(Math.random()*y_pixels) +1;
}
}
PS: I appreciate all help, tips and tweaks that you guys provide:) Thanks for helping
The area you want to exclude in the centre of the screen is rather large, and on my little laptop, there isn't even any room to still show the random positioned images.
But anyway, this piece of code should do the job -- I added some infinite loop protection which on my PC was a life-saver:
HTML (added style attribute)
<div id="targetsDiv">
<img src="target2.png" alt="target_shot" class="target"
style="visibility:hidden"/>
</div>
JavaScript:
window.addEventListener('load', function () {
var targetCollection = document.getElementById("targetsDiv");
var template = document.getElementsByClassName("target")[0];
var targetWidth = template.offsetWidth;
var targetHeight = template.offsetHeight;
var x_pixels = window.innerWidth - targetWidth;
var y_pixels = window.innerHeight - targetHeight;
var x_midScreen = window.innerWidth / 2;
var y_midScreen = window.innerHeight / 2;
function spawnTargets (numberOfSpawns) {
var targets = [];
var count = 0; // infinite recursion protection
for (var i = 0; i < numberOfSpawns; i++) {
do {
do {
var x = Math.floor(Math.random()*x_pixels);
var y = Math.floor(Math.random()*y_pixels);
if (count++ > 200) {
console.log('give up');
return;
}
} while ((x >= x_midScreen-450 && x <= x_midScreen+300) && (y >= y_midScreen-350 || y <= y_midScreen+200));
for (var j = 0; j < i; j++) {
if (x >= targets[j].x - targetWidth && x <= targets[j].x + targetWidth &&
y >= targets[j].y - targetHeight && y <= targets[j].y + targetHeight) break; // not ok!
}
} while (j < i);
targets.push({x, y});
img = document.createElement('img');
img.src = template.src;
img.setAttribute('width', targetWidth + 'px');
img.setAttribute('height', targetHeight + 'px');
img.className = template.className;
targetCollection.appendChild(img);
img.style.left = x + "px";
img.style.top = y + "px";
}
}
spawnTargets(3);
});
I have image I am scrolling within a div.
It make sure the image is visible I am using
var isVisible = (
threshold.top >= -39 &&
threshold.bottom <= (window.innerHeight || document.documentElement.clientHeight)
);
What I am trying to do now is make sure that once the element is visible it is able to completely finish scrolling before going out of the view port.
I am thinking I can do this by effecting the speed value based on the the distance of the element from the top on the window. But I am having a very hard time doing this.
I am using .getBoundingClientRect() to get the distance the element is from the top of the viewport:
var threshold = document.getElementById('page-feature').getBoundingClientRect();
var thresholdY = threshold.top;
Below is my code so far:
function scrollImageInViewport() {
var threshold = document.getElementById('page-feature').getBoundingClientRect();
var thresholdY = threshold.top;
var isVisible = (
threshold.top >= -39 &&
threshold.bottom <= (window.innerHeight || document.documentElement.clientHeight)
);
if (isVisible && window.innerWidth > 550) {
scrollDir(thresholdY);
}
}
function scrollUp(thresholdY) {
if (thresholdCounter < maxScrollNegative) {
return;
} else {
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0); -ms-transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0); transform:translate3d(0,' + (--thresholdCounter *speed) + 'px,0);');
}
};
function scrollDown(thresholdY) {
if (thresholdCounter > maxScrollPositive) {
return;
} else {
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0); -ms-transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0); transform:translate3d(0,' + (++thresholdCounter *speed) + 'px,0);');
}
};
function scrollToTop(){
initScroll();
pageScroll.setAttribute('style', 'transform:translate3d(0,0,0);');
thresholdCounter = 0;
};
function scrollDir(thresholdY) {
var scroll = window.scrollY;
if(scroll > position) {
distanceFromTop(thresholdY);
scrollUp(thresholdY);
} else if (scroll < position ){
scrollDown(thresholdY);
}
position = scroll;
};
function distanceFromTop(thresholdY) {
if (thresholdY > 0) {
`enter code here`//set speed as distance from top /px of not shown content
speed = (scrollImageHeight - scrollVisibleHeight) / thresholdY;
}
};
function initScroll(){
position = window.scrollY;
pageScroll = document.getElementById('page-scroll');
scrollImageHeight = pageScroll.offsetHeight; //total height of scroll image
pagePanel = document.getElementById("pagePanel");
pageStyle = window.getComputedStyle(pagePanel,"");
size = pageStyle.getPropertyValue("height");
scrollVisibleHeight = parseInt(size, 10);//visible height of scroll image
scrollImageEnd = scrollImageHeight - scrollVisibleHeight;
maxScrollNegative = -scrollImageEnd / speed;
}
var speed;
var thresholdCounter = 0;
var maxScrollPositive = 0;
var position,
pageScroll,
scrollImageHeight,
pagePanel,
pageStyle,
size,
scrollVisibleHeight,
scrollImageEnd,
maxScrollNegative;
window.addEventListener('resize', scrollToTop);
document.addEventListener('scroll', scrollImageInViewport);
window.addEventListener('load', initScroll);
This is what I ended up with:
var featurePage = document.getElementById('page-feature')
var pageScroll = document.getElementById('page-scroll');
var startP, // where animation needs to begin
endP, // where animation needs to end
diff; // visible element size
function getElementOffset(){ //init
var de = document.documentElement;
var box = featurePage.getBoundingClientRect();
var top = box.top + window.pageYOffset - de.clientTop;
var bottom = box.bottom + window.pageYOffset - de.clientTop;
var winHight = window.innerHeight;
diff = bottom - top;
var elPadding = (winHight - diff);
startP = top - elPadding;
endP = bottom - elPadding;
scrollImage()
}
function scrollImage(){
var scrollImageHeight = pageScroll.offsetHeight;
var scrollPos = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
var s1 = scrollPos - startP;
var realPos = -s1/diff;
var lengthLeft = scrollImageHeight - (diff)
if ( realPos < 0.09 && realPos > -1){
pageScroll.setAttribute('style', '-webkit-transform:translate3d(0,' + (realPos * lengthLeft) + 'px,0); -ms-transform:translate3d(0,' + (realPos *lengthLeft) + 'px,0); transform:translate3d(0,' + (realPos *lengthLeft) + 'px,0);');
}
}
window.addEventListener('resize', getElementOffset);
document.addEventListener('scroll', getElementOffset);
I install Float Left Right Advertising plugin on my site: www.displej.me and I set banners at the side of site. But when you scroll baners are not fixed, they follow page but they are refreshing and blinking. Also, when I'm scrolling down they stay fixed aside and later start to follow the page. Ths is JS code:
function FloatTopDiv()
{
startLX = ((document.body.clientWidth -MainContentW)/2) - (LeftBannerW+LeftAdjust) , startLY = TopAdjust;
startRX = ((document.body.clientWidth -MainContentW)/2) + (MainContentW+RightAdjust) , startRY = TopAdjust;
var d = document;
function ml(id)
{
var el=d.getElementById?d.getElementById(id):d.all?d.all[id]:d.layers[id];
el.sP=function(x,y){this.style.left=x + 'px';this.style.top=y + 'px';};
el.x = startRX;
el.y = startRY;
return el;
}
function m2(id)
{
var e2=d.getElementById?d.getElementById(id):d.all?d.all[id]:d.layers[id];
e2.sP=function(x,y){this.style.left=x + 'px';this.style.top=y + 'px';};
e2.x = startLX;
e2.y = startLY;
return e2;
}
window.stayTopLeft=function()
{
if (document.documentElement && document.documentElement.scrollTop)
var pY = document.documentElement.scrollTop;
else if (document.body)
var pY = document.body.scrollTop;
if (document.body.scrollTop > 200){startLY = 3;startRY = 3;} else {startLY = TopAdjust;startRY = TopAdjust;};
ftlObj.y += (pY+startRY-ftlObj.y)/1;
ftlObj.sP(ftlObj.x, ftlObj.y);
ftlObj2.y += (pY+startLY-ftlObj2.y)/1;
ftlObj2.sP(ftlObj2.x, ftlObj2.y);
setTimeout("stayTopLeft()", 1);
}
ftlObj = ml("divAdRight");
//stayTopLeft();
ftlObj2 = m2("divAdLeft");
stayTopLeft();
}
function ShowAdDiv()
{
var objAdDivRight = document.getElementById("divAdRight");
var objAdDivLeft = document.getElementById("divAdLeft");
objAdDivRight.style.display = "block";
objAdDivLeft.style.display = "block";
FloatTopDiv();
}
What to do? I try to change the numbers in the code but not sucsses.
clear:both
is something I would try to keep the sides free from the centered divs movements.
This is for view zoom image when mouse over on thumbnail. IT'S WORKS !!!
1. Code for html (smarty)
<{html_image onmouseout="view_zoom(this, '');" onmouseover="view_zoom(this, this.src);" file=$img}>
2. Code for js :
function view_zoom(o, i)
{
if(i!=''&&i.indexOf('noimage.jpg') == -1)
{
var s = i.replace('small','big');
var aTag = o;
var leftpos = toppos = 0;
do {aTag = aTag.offsetParent; leftpos += aTag.offsetLeft; toppos += aTag.offsetTop;
} while(aTag.offsetParent != null);
var X = o.offsetLeft + leftpos + 100;
var Y = o.offsetTop + toppos - 20;
document.getElementById('big_zoom').style.left = X + 'px';
document.getElementById('big_zoom').style.top = Y + 'px';
document.getElementById('big_zoom').style.display = 'block';
document.getElementById('big_zoom').innerHTML='<img src="'+s+'" onload="if(this.width<200) {$(\'big_zoom\').style.display = \'none\');}else if(this.width>300){this.width=300;}$(\'big_zoom\').style.width=this.width+\'px\';"/>'
} else {
document.getElementById('big_zoom').style.display = 'none';
}
}
3. code for css :
.big_zoom {width:200px;z-index:1000;position:absolute;padding:5px; background:#FFFFFF;}
.big_zoom img{border:#AACCEE 1px solid;padding:5px;}
don't forget to add this line in html
<div class="big_zoom" id="big_zoom" style="display:none;"></div>
lol !!!
I have an element with animated top margin. I need to detect if it isn't too close from the border, and if it is, scroll parent div to lower position, to prevent animated element from hiding. Here is an example:
http://jsfiddle.net/zYYBR/5/
This green box shouldn't be below the red line after clicking the "down" button.
Do you mean this?
var new_margin;
var step = 75;
var limit = $("#max")[0].offsetTop;
$('#down').click(function() {
var goStep = step;
var elHeight = $("#animated")[0].offsetTop + $("#animated")[0].offsetHeight;
if((elHeight + step) > limit)
{
goStep = limit - elHeight;
}
new_margin = goStep + parseInt($('#animated').css('margin-top'));
$("#animated").animate({marginTop: new_margin}, 1000);
});
http://jsfiddle.net/zYYBR/8/
EDIT: Or maybe something like that (of course you can improve the calculation, because currently it's very buggy with scroll):
var new_margin;
var step = 75;
$('#down').click(function () {
scroll(1000);
});
var scrollTimer = null;
$("#container").bind("scroll", function () {
clearTimeout(scrollTimer);
scrollTimer = setTimeout(function () { scroll(1); }, 10);
});
function scroll(speed) {
var scrollStep, animationStep = step;
var currentBoxBottom = $("#animated")[0].offsetTop + $("#animated")[0].offsetHeight;
var nextCurrentBoxBottom = currentBoxBottom + step;
var limit = $("#max")[0].offsetTop + $("#container")[0].scrollTop;
if (nextCurrentBoxBottom > limit) {
if (limit >= $("#container")[0].scrollTop) {
scrollStep = $("#container")[0].scrollTop + nextCurrentBoxBottom - limit;
}
else {
scrollStep = $("#container")[0].scrollTop - nextCurrentBoxBottom - limit;
animationStep = nextCurrentBoxBottom - limit;
}
$("#container")[0].scrollTop = scrollStep;
}
new_margin = animationStep + parseInt($('#animated').css('margin-top'));
$("#animated").animate({ marginTop: new_margin }, speed);
}
http://jsfiddle.net/zYYBR/13/
Do you mean something like this?
I have the same visual result as Alex Dn did, but I added a little extra direction to what I think you're talking about. If it's what you're looking for I'll make updates:
var new_margin;
var step = 75;
var limit = $("#max")[0].offsetTop;
$('#down2').click(function() {
var anim = $("#animated");
var hrOff = $("#max").offset();
var thOff = anim.offset();
new_margin = Math.min(hrOff.top - thOff.top - anim.height(), 75);
console.log(new_margin, hrOff.top, thOff.top);
var st = 0;
if (new_margin < 75) {
st = 75 - new_margin;
//have container scroll by this much?
}
anim.animate({
marginTop: "+=" + new_margin
}, 1000);
});
http://jsfiddle.net/zYYBR/10/