So, I'm coding up a site that has certain events triggering as you scroll down the page. I want the events to be triggered when the relevant element hits a point just around a quarter of the way down the viewport.
However, this trigger point is obviously different for different sized viewports. I've worked out how to get this trigger point calculated, but I haven't found a way to get the position of a div relative to the top of the viewport/page.
I am trying to use .offset(), which I could combine with getPageScroll() to find the right point, but I can't figure out what on earth to do with the array that it returns. I've also tried popping it in a variable and using that with the syntax I have below (as used on the jquery.com documentation), but it's patently wrong, and returned Undefined in the console.
I am pretty new to both Javascript and jQuery, and to any actual programming in general, so please excuse any stupidity. If I'm doing this all backwards, that's totally a valid answer too! Please just point me in the correct direction if that's the case.
I've coded it up like this so far. The actual effects are only placeholders for now - I'm just trying to get the basic framework working:
// getPageScroll() by quirksmode.com - adapted to only return yScroll
function getPageScroll() {
var yScroll;
if (self.pageYOffset) {
yScroll = self.pageYOffset;
} else if (document.documentElement && document.documentElement.scrollTop) {
yScroll = document.documentElement.scrollTop;
} else if (document.body) {// all other Explorers
yScroll = document.body.scrollTop;
}
return yScroll
}
// Adapted from getPageSize() by quirksmode.com
function getPageHeight() {
var windowHeight
if (self.innerHeight) { // all except Explorer
windowHeight = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight) {
windowHeight = document.documentElement.clientHeight;
} else if (document.body) { // other Explorers
windowHeight = document.body.clientHeight;
}
return windowHeight
}
var containers = $('div.container');
var element_1 = $('#part_one');
var element_2 = $('#part_two_1');
var element_3 = $('#part_two_2');
var element_4 = $('#part_two_3');
var element_5 = $('#part_two_4');
var element_6 = $('#part_three');
var element_7 = $('#part_four');
var element_8 = $('#part_five');
var docHeight = $(document).height();
$(window).scroll(function() {
var offset = offset();
var docHeight = $(document).height();
var pageBottom = getPageScroll() + getPageHeight();
var quarterPoint = getPageScroll()+((pageBottom-getPageScroll())/4)
var halfwayPoint = getPageScroll()+((pageBottom-getPageScroll())/2)
var threeQuarterPoint = pageBottom-((pageBottom-getPageScroll())/4)
var triggerPoint = quarterPoint-(getPageHeight/10)
if (triggerPoint < element_1.offset.top){
containers.stop().animate({backgroundColor: "white", color: "#aaa"}, 50);
element_1.stop().animate({backgroundColor: "#ffa531", color: "white"}, 300, function(){
$(this).children().stop().animate({opacity: "1"}, 300);
});
};
if (triggerPoint > element_2.offset.top){
containers.stop().animate({backgroundColor: "white", color: "#aaa"}, 50);
element_2.stop().animate({backgroundColor: "#d900ca", color: "white"}, 300, function(){
$(this).children('img').stop().animate({opacity: "1"}, 300);
});
};
if (triggerPoint > element_3.offset(top)){
containers.stop().animate({backgroundColor: "white", color: "#aaa"}, 50);
element_3.stop().animate({backgroundColor: "#d900ca", color: "white"}, 300);
};
and so on and so forth, for somewhere between 8 and 12 trigger points.
Any help would be greatly appreciated!
Couple things i see here:
var offset = offset(); // i don't believe this is a global function.
if (triggerPoint < element_1.offset.top) { // offset needs to be offset(), its a function not a property
Related
I'm using this script which I purchased from some website in German, so I can't understand the instructions. Basically, I want to make it so this is only triggered on screens above 768 pixels. I've tried a few different things and can't seem to get it to work. I'm not very well versed in Javascript. If someone could show me how to do this, I would be very grateful.
$(document).ready(function() {
//Build Bubble Machines with the Bubble Engine ------------------------
var SoapBubbleMachineNumber1 = $('fn').BubbleEngine({
particleSizeMin: 0,
particleSizeMax: 60,
particleSourceX: 0,
particleSourceY: 500,
particleAnimationDuration: 5000,
particleDirection: 'right',
particleAnimationDuration: 6000,
particleAnimationVariance: 2000,
particleScatteringX: 500,
particleScatteringY: 300,
gravity: -100
});
//Start Bubble Machine 1 ---------------------------------------------
SoapBubbleMachineNumber1.addBubbles(50);
});
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth;
if(x > 768){
//your code here.
}
The first part is a pretty robust function to find the window width.
What you would then do is wrap your code shown in a function and call the function within the //your code here part
first google translator is your friend ;) If nothing works ask a german like me ;)
Anyhow :
function executeme(minWidth,minHeight){
var width = window.innerWidth|| document.documentElement.clientWidth||
Document.body.clientWidth;
var height = window.innerHeight || document.documentElement.clientHeight ||
document.body.clientHeight;
if (width < minWidth){return false;}
if (height < minHeight){return false;}
return true;
}
this will work on the browser window
If you want to know how much space is left in a div for example
function getGeometry(id){
try{
var element=document.getElementById()
} catch (ex){
return false;
}
var rect = element.getBoundingClientRect();
// uncomment to see the whole show :)
// console.log(rect);
return rect;
}
function runOnElementGeometry(id,minWidth,minHeight){
try{
var element=document.getElementById()
} catch (ex){
return false;
}
var rect = element.getBoundingClientRect();
if (rect.width < minWidth){return false;}
if (rect.height < minHeight){return false;}
return true;
}
if you need also the position of the element on the page you need to add the scroll positions (not needed for the width and height)
var x = window.scrollX
var y = window.scrollY
Now you can check whats going on and either start your bubbeles or even not :)
I'm still very new to javascript and I'm learning as I build. This may be a simple fix but how would I disable a function on my parallax images ( or disable a specific js function in general ) on a smaller width?
Here's what I have so far that doesn't quite work but shows "undefined". I've been searching for a solution for a couple of days now with no luck. Any help would be appreciated.
var paraLlaxS = document.querySelector("#firstImgc2");
var paraLlaxS = document.querySelector("#secondImgc2");
var paraLlaxS = document.querySelector("#backbox1");
function setTranslate(xPos, yPos, el) {
el.style.transform = "translate3d(" + xPos + ", " + yPos + "px, 0)";
}
window.addEventListener("DOMContentLoaded", scrollLoop, false);
var xScrollPosition;
var yScrollPosition;
function scrollLoop() {
xScrollPosition = window.scrollX;
yScrollPosition = window.scrollY;
setTranslate(0, yScrollPosition * -0.2, firstImgc2);
setTranslate(0, yScrollPosition * 0.15, secondImgc2);
setTranslate(0, yScrollPosition * -0.6, backbox1);
requestAnimationFrame(scrollLoop);
if(window.innerWidth < 900) {
document.querySelector('#firstImgc2').innerHTML = window.removeEventListener("DOMContentLoaded", scrollLoop, false);
return;
} else {
}
}
You could add a conditional return at the beginning of you function. But if the width increases again you would need to listen for that to start the loop again.
function scrollLoop() {
if(window.innerWidth < 900)return;
...
I borrowed a solution from another post.
Listen for browser width for responsive web design?
This code is compatible with a wider variety of browsers as getting the screen size can vary depending on the browser.
var width = 0;
function getWindowSize() {
if (document.body && document.body.offsetWidth) {
width = document.body.offsetWidth;
}
if (document.compatMode=='CSS1Compat' &&
document.documentElement &&
document.documentElement.offsetWidth ) {
width = document.documentElement.offsetWidth;
}
if (window.innerWidth) {
width = window.innerWidth;
}
return(width);
}
I am using this code: EXAMPLE
Depending on if "image-ul" is fully above the bottom edge of the browser window or not, will make divs scroll at different speeds, as it should. But the problem that I am having is that the scrolling is not smooth when the slow scrolling divs get somewhere close to the top of the page. They seem to stall for a moment, and even scroll in the opposite direction sometimes.
//
// default speed ist the lowest valid scroll speed.
//
var default_speed = 1;
//
// speed increments defines the increase/decrease of the acceleration
// between current scroll speed and data-scroll-speed
//
var speed_increment = 0.01;
//
// maximum scroll speed of the elements
//
var data_scroll_speed_a = 3; // #sloganenglish
var data_scroll_speed_b = 5; // #image-ul
//
//
//
var increase_speed, decrease_speed, target_speed, current_speed, speed_increments;
$(document).ready(function() {
$(window).on('load resize scroll', function() {
var WindowScrollTop = $(this).scrollTop(),
Div_one_top = $('#image-ul').offset().top,
Div_one_height = $('#image-ul').outerHeight(true),
Window_height = $(this).outerHeight(true);
if (WindowScrollTop + Window_height >= (Div_one_top + Div_one_height)) {
$('#sloganenglish').attr('data-scroll-speed', data_scroll_speed_a).attr('data-current-scroll-speed', default_speed).attr('data-speed-increments', data_scroll_speed_a * speed_increment);
$('#image-ul').attr('data-scroll-speed', data_scroll_speed_b).attr('data-current-scroll-speed', default_speed).attr('data-speed-increments', data_scroll_speed_b * speed_increment);
$('.slogan-a-line').css('color', 'yellow');
increase_speed = true;
decrease_speed = false;
} else {
$('#sloganenglish').attr('data-scroll-speed', '1').attr('data-current-scroll-speed', default_speed);
$('#image-ul').attr('data-scroll-speed', '1').attr('data-current-scroll-speed', default_speed);
$('.slogan-a-line').css('color', 'red');
decrease_speed = true;
increase_speed = false;
}
}).scroll();
});
// data-scroll-speed script
$.fn.moveIt = function() {
var $window = $(window);
var instances = [];
$(this).each(function() {
instances.push(new moveItItem($(this)));
});
window.onscroll = function() {
var scrollTop = $window.scrollTop();
instances.forEach(function(inst) {
inst.update(scrollTop);
});
}
}
var moveItItem = function(el) {
this.el = $(el);
this.speed = parseInt(this.el.attr('data-scroll-speed'));
this.current_speed = 1.0;
};
moveItItem.prototype.update = function(scrollTop) {
target_speed = parseInt(this.el.attr('data-scroll-speed'));
current_speed = this.current_speed;
speed_increments = parseFloat(this.el.attr('data-speed-increments'));
if (increase_speed) {
if (current_speed < target_speed) {
current_speed += speed_increments;
} else {
current_speed = target_speed;
}
} else if (decrease_speed) {
if (current_speed > default_speed) {
current_speed -= speed_increments;
}
if ($(window).scrollTop() === 0) {
current_speed = default_speed;
}
}
this.current_speed = current_speed;
var pos = scrollTop / this.current_speed;
this.el.css('transform', 'translateY(' + -pos + 'px)');
};
// Initialization
$(function() {
$('[data-scroll-speed]').moveIt();
});
The sample code wasn't slow for me, so it may be specific to your machine or browser.
However, there are a few things you can do:
Don't use jQuery where you don't need it. jQuery is significantly slower than using native JS functions (e.g. document.getElementById).
Don't repeatedly use jQuery selectors. Every time you use a jQuery selector, you suffer a performance hit. So for example, instead of this:
function(){
var Div_one_top = $('#image-ul').offset().top,
Div_one_height = $('#image-ul').outerHeight(true);
}
Do this:
var imageUl = $('#image-ul');
function(){
imageUl.offset().top,
imageUl.outerHeight(true);
}
This example should increase performance quite a bit. You're doing multiple jQuery selectors every time the page scrolls for no reason.
The best choice for something performance intensive is to cut out jQuery completely and do it by hand.
I have a page with many divs that are laid out in a grid. Each div has text in it. I want the text to be just big enough to fill the div. I do this by increasing the text size until I detect that the div has scrolled, and then go back, as per this answer:
Auto-size dynamic text to fill div
This works really well on most browsers, including mobile ones, but on IE10 it is very slow. You can actually watch it making the text smaller. I am guessing that it is doing some kind of window-wide layout operation each time the font size changes.
Any idea how to suspend the redraw until all of the divs are done or otherwise improve performance?
Here is a simple fiddle showing the technique. Just imagine this with about 50 divs on the page. Instant in Chrome, takes several seconds in IE10:
(function($) {
$.fn.textfill = function(options) {
var fontSize = options.maxFontPixels;
var ourText = $('span:visible:first', this);
var maxHeight = $(this).height();
var maxWidth = $(this).width();
var textHeight;
var textWidth;
do {
ourText.css('font-size', fontSize);
textHeight = ourText.height();
textWidth = ourText.width();
fontSize = fontSize - 1;
} while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
return this;
}
})(jQuery);
$(document).ready(function() {
$('.jtextfill').textfill({ maxFontPixels: 200 });
});
jsfiddle: http://jsfiddle.net/pRJdY/
well the jsFiddle fails cause there was a bug in the version of jQuery jsFiddle is referencing, http://bugs.jquery.com/ticket/13980.
So I created a local version of the sample. I think I see what you are talking about, but not totally sure. I see it go from the normal small text to much larger, but it happens real fast. I see the same behavior in Chrome. So my guess is till I have thousands of elements on the page I may not be able to recreate your issue.
I did optimize your JavaScript a little so I hope that helps you out a little:
(function ($) {
$.fn.textfill = function (options) {
var $this = $(this),
fontSize = options.maxFontPixels,
ourText = $('span:visible:first', this),
maxHeight = $this.height(),
maxWidth = $this.width(),
textHeight,
textWidth;
do {
ourText.css('font-size', fontSize);
textHeight = ourText.height();
textWidth = ourText.width();
fontSize = fontSize - 1;
} while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
return this;
}
})(jQuery);
The problem is the huge number of DOM accesses. Fortunately, your algorithm can be greatly optimized.
Starting at 200px fontsize and going down, when you're going to end up around 10-30px is very slow. Better to go up, and better to do a binary search for the correct size.
Starting at the minimum size and going up is 5x faster, in this case, at least: http://jsfiddle.net/pRJdY/2/
Binary search cuts the time required in half, again: http://jsfiddle.net/pRJdY/4/
(function($) {
$.fn.textfill = function(options) {
var start = (new Date).getTime(),
node = $(this),
max = options.maxFontPixels,
min = 3,
span = $('span:visible:first', this),
maxHeight = node.height(),
maxWidth = node.width(),
size,
isTooBig,
finalSize = null;
do {
console.log(size);
size = Math.round((min + max) / 2);
span.css('font-size', size);
isTooBig = (span.height() > maxHeight || span.width() > maxWidth);
if (isTooBig) {
max = size - 1;
} else {
min = size;
}
if (min === max) {
finalSize = max;
}
} while (finalSize === null);
span.css('font-size', finalSize);
console.log('elements:', node.size(), 'elapsed time:', (new Date).getTime() - start);
return this;
}
})(jQuery);
I posted a question previously that got off topic, I'm reposting with better code that I have VERIFIED is compatible with iPhone (it works with mine anyway!)
I just want to apply background-position coordinates to the body element and call the script conditionally for iPhone, iPod, & iPad. Here's my conditional call for those devices:
var deviceAgent = navigator.userAgent.toLowerCase();
var agentID = deviceAgent.match(/(iphone|ipod|ipad)/);
if (agentID) {
// do something
} else {
//do this
}
Now, I've found this excellent script that sets the "top: x" dynamically on the basis of scroll position. Everyone has told me (and ALL of the tutorials and Google search results as well) that it's impossible to set scroll position dynamically for iPhone because of the viewport issue. HOWEVER, they are wrong because if you scroll to the bottom of the page and view this javascript demo on iPhone, you can scroll and the
<div style="background-position: fixed; top: x (variable)"></div>
div DOES stay centered on iPhone. I really hope this question helps alot of people, I thought it was impossible, but it's NOT... I just need help stitching it together!
The original code (you can test it on iPhone yourself) is here:
http://stevenbenner.com/2010/04/calculate-page-size-and-view-port-position-in-javascript/
**EDIT: For reference, here is the div that DOES absolute position itself by dynamically applying the "top: x" element as (even on iPhone):
http://stevenbenner.com/2010/04/calculate-page-size-and-view-port-position-in-javascript/**
So I just need help getting the following code to apply the dynamic "background-position: 0 x" to the BODY tag where x is centered and relative to the viewport position. Also, needs to be nested inside the above code that is conditional for iPhone and similar devices.
// Page Size and View Port Dimension Tools
// http://stevenbenner.com/2010/04/calculate-page-size-and-view-port-position-in-javascript/
if (!sb_windowTools) { var sb_windowTools = new Object(); };
sb_windowTools = {
scrollBarPadding: 17, // padding to assume for scroll bars
// EXAMPLE METHODS
// center an element in the viewport
centerElementOnScreen: function(element) {
var pageDimensions = this.updateDimensions();
element.style.top = ((this.pageDimensions.verticalOffset() + this.pageDimensions.windowHeight() / 2) - (this.scrollBarPadding + element.offsetHeight / 2)) + 'px';
element.style.left = ((this.pageDimensions.windowWidth() / 2) - (this.scrollBarPadding + element.offsetWidth / 2)) + 'px';
element.style.position = 'absolute';
},
// INFORMATION GETTERS
// load the page size, view port position and vertical scroll offset
updateDimensions: function() {
this.updatePageSize();
this.updateWindowSize();
this.updateScrollOffset();
},
// load page size information
updatePageSize: function() {
// document dimensions
var viewportWidth, viewportHeight;
if (window.innerHeight && window.scrollMaxY) {
viewportWidth = document.body.scrollWidth;
viewportHeight = window.innerHeight + window.scrollMaxY;
} else if (document.body.scrollHeight > document.body.offsetHeight) {
// all but explorer mac
viewportWidth = document.body.scrollWidth;
viewportHeight = document.body.scrollHeight;
} else {
// explorer mac...would also work in explorer 6 strict, mozilla and safari
viewportWidth = document.body.offsetWidth;
viewportHeight = document.body.offsetHeight;
};
this.pageSize = {
viewportWidth: viewportWidth,
viewportHeight: viewportHeight
};
},
// load window size information
updateWindowSize: function() {
// view port dimensions
var windowWidth, windowHeight;
if (self.innerHeight) {
// all except explorer
windowWidth = self.innerWidth;
windowHeight = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight) {
// explorer 6 strict mode
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
} else if (document.body) {
// other explorers
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
};
this.windowSize = {
windowWidth: windowWidth,
windowHeight: windowHeight
};
},
// load scroll offset information
updateScrollOffset: function() {
// viewport vertical scroll offset
var horizontalOffset, verticalOffset;
if (self.pageYOffset) {
horizontalOffset = self.pageXOffset;
verticalOffset = self.pageYOffset;
} else if (document.documentElement && document.documentElement.scrollTop) {
// Explorer 6 Strict
horizontalOffset = document.documentElement.scrollLeft;
verticalOffset = document.documentElement.scrollTop;
} else if (document.body) {
// all other Explorers
horizontalOffset = document.body.scrollLeft;
verticalOffset = document.body.scrollTop;
};
this.scrollOffset = {
horizontalOffset: horizontalOffset,
verticalOffset: verticalOffset
};
},
// INFORMATION CONTAINERS
// raw data containers
pageSize: {},
windowSize: {},
scrollOffset: {},
// combined dimensions object with bounding logic
pageDimensions: {
pageWidth: function() {
return sb_windowTools.pageSize.viewportWidth > sb_windowTools.windowSize.windowWidth ?
sb_windowTools.pageSize.viewportWidth :
sb_windowTools.windowSize.windowWidth;
},
pageHeight: function() {
return sb_windowTools.pageSize.viewportHeight > sb_windowTools.windowSize.windowHeight ?
sb_windowTools.pageSize.viewportHeight :
sb_windowTools.windowSize.windowHeight;
},
windowWidth: function() {
return sb_windowTools.windowSize.windowWidth;
},
windowHeight: function() {
return sb_windowTools.windowSize.windowHeight;
},
horizontalOffset: function() {
return sb_windowTools.scrollOffset.horizontalOffset;
},
verticalOffset: function() {
return sb_windowTools.scrollOffset.verticalOffset;
}
}
};
<?php
/* detect Mobile Safari */
$browserAsString = $_SERVER['HTTP_USER_AGENT'];
if (strstr($browserAsString, " AppleWebKit/") && strstr($browserAsString, " Mobile/"))
{
$browserIsMobileSafari = true;
echo
"
<script>
$(document).ready(function() {
$(window).scroll(function() {
windowPosition = $(this).scrollTop();
$('body').stop().animate({'backgroundPositionY' : windowPosition+'px'}, 500);
});
});
</script>
"
;} ?>