javascript global variable good practice - javascript

I have a few variables pertaining to the height of elements an want to update them using $(window).on('resize'[...]), as well as calculate them when first loading the page so naturally I would rather make a function for doing that, instead of repeating the code.
Is it bad practice to make these variables global so that I can update them with a function, or is there any other way to do this?
var hSum = 0
for (var i = 0; i < content.length; i++) {
var contentH = $(content[i]).height()
hSum += contentH
}
var windowHeight = $(window).height(),
footerHeight = footer.height(),
heightDocument = windowHeight + hSum + footer.height() - 20;
This is the entirety of the script
function scrollFooter(scrollY, footerHeight) {
if (scrollY >= footerHeight) {
$('footer').css({
'bottom': '0px'
});
} else {
$('footer').css({
'bottom': '-' + footerHeight + 'px'
});
}
}
$(document).ready(function() {
var content = $('.content'),
header = $('header'),
footer = $('footer'),
headerContainer = header.find('.container'),
headerBackground = header.find('.background'),
nav = $('.navbar')
var hSum = 0
for (var i = 0; i < content.length; i++) {
var contentH = $(content[i]).height()
hSum += contentH
}
var windowHeight = $(window).height(),
footerHeight = footer.height(),
documentHeight = windowHeight + hSum + footer.height() - 20;
$('#scroll-animate, #scroll-animate-main').css({
'height': documentHeight + 'px'
})
$('header').css({
'height': windowHeight + 'px'
})
$('.wrapper-parallax').css({
'margin-top': windowHeight + 'px'
})
scrollFooter(window.scrollY, footerHeight);
setTimeout(function fadeHeaderIn() {
headerContainer.css('opacity', '1')
headerBackground.css('transform', 'scale(1.25, 1.25)')
}, 300)
$(window).on('scroll', function() {
scroll = window.scrollY
$('#scroll-animate-main').css({
'top': '-' + scroll + 'px'
});
scrollFooter(scroll, footerHeight);
nav.toggleClass('hidden', scroll < windowHeight)
})
nav.on("mouseenter", function() {
nav.removeClass('minimized')
})
nav.on("mouseleave", function() {
nav.addClass('minimized')
})
$('.navbutton').on('click', function(event) {
if ($(this).attr('href') == "#contact")
$('html, body').stop().animate({ scrollTop: documentHeight }, 300, 'swing')
else $('html, body').stop().animate({ scrollTop: $($(this).attr('href')).offset().top }, 300, 'swing')
event.preventDefault()
})
})

The best thing to do is to create a class to handle all the element functions.
for example, let's assume that you have a div or a canvas that you want to check for it's size.
function divHandler(divID){
this.div = document.getElementById(divID);
//Add all global variables here
this.boundingRect = this.div.getBoundingClientRect()
}
//After that access the variables by other functions
divHandler.prototype.displayData = function(){
console.log(this.boundingRect);
}
const d = new divHandler('someDiv');
d.displayData();
#someDiv{
min-width: 100px;
min-height: 100px;
border: 1px solid black;
}
<div id="someDiv">
</div>
Now you have a class that controls all divs by id and you can use it again and again for all other divs in the code.
Update 1:
You can also add an event listener like this
function divHandler(divID){
this.div = document.getElementById(divID);
//Add all global variables here
this.boundingRect = this.div.getBoundingClientRect()
}
divHandler.prototype.listen = function (event, cb, ...args){
this.div.addEventListener(event,cb.bind(this, ...args));
}
const d = new divHandler('someDiv');
d.listen('click', function(e){
console.log(e.type);
this.div.style.backgroundColor = "blue"
});
#someDiv{
min-width: 100px;
min-height: 100px;
border: 1px solid black;
}
<div id="someDiv"></div>

Related

how to run javascript when screen size over certain width size?

I want to run certain javascript only when the window width is over 1024.
The script is long. I've tried to combine them with
if ($(window).width() >= 1024
but it still not working.
Can someone help me?
This is the script I want to run when the width is over 1024 :
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script>
$(window).load(function() {
$(window).on("scroll resize", function() {
var pos = $('#fixPlace').offset();
$('.post').each(function() {
if (pos.top >= $(this).offset().top && pos.top <= $(this).next().offset().top) {
var newDescr = $(this).find('.feature__description').html();
var oldDescr = $("#fixPlace").html();
$('#fixPlace').html(newDescr);
if (newDescr !== oldDescr) {
$("#fixPlace").css('opacity', 0.4).animate({ 'opacity': '1', }, 200);
return;
}
}
});
});
$(document).ready(function() {
$(window).trigger('scroll');
});
});
let fixPlace = '#fixPlace';
let scrollStart = null;
let scrollEnd = null;
let floatBoxTop = 0.25 * $(window).height();
$(document).ready(function() {
scrollStart = $('#fixPlace').offset().top;
scrollEnd = $('.transition').offset().top - 680;
})
$(window).scroll(scroll)
function scroll() {
let scrollTop = $(document).scrollTop() + floatBoxTop;
scrollTop = Math.min(scrollEnd, Math.max(scrollTop, scrollStart))
if (scrollTop === scrollStart || scrollEnd === scrollTop) {
$(fixPlace).css({
position: 'absolute',
top: scrollTop
});
} else {
$(fixPlace).css({
position: 'fixed',
top: floatBoxTop
});
}
}

Get values from one .each function into a different .each function

I have 4 sub-banners with display: block; width: 100%; that each have a div with text inside. These divs hangs down outside the parent element using transform: translateY(238px).
Each div that holds the text is of varying height so I was trying to write a function to check each text div's height and apply the margin to the bottom of that specific parent element accordingly.
What I got so far is this, but I can't figure out how to get the variable respectiveMargin passed into my second each function so that it matches up with the right parent element. Right now it just applies the same margin on all sub-banners. Thanks for any and all help!
const resize = () => {
if ($(window).width() < 768) {
$('.sub-banner-text-wrapper').each(function () {
var textHeight = $(this).height();
var responiveMargin = (textHeight - 62) + 25;
});
$('.sub-banner').each(function () {
$(this).css("margin-bottom", responiveMargin);
});
}
};
$(window).on('resize', resize);
Seems the main problem is that you're trying to use two .eaches when you only need one:
const resize = () => {
if ($(window).width() < 768) {
$('.sub-banner-text-wrapper').each(function () {
var textHeight = $(this).height();
var responiveMargin = (textHeight - 62) + 25;
$(this).closest('.sub-banner').css("margin-bottom", responiveMargin);
});
}
};
$(window).on('resize', resize);
So reference the index when you loop over the one set.
var banners = $('.sub-banner');
$('.sub-banner-text-wrapper').each(function (ind) {
var textHeight = $(this).height();
var responiveMargin = (textHeight - 62) + 25;
banners.eq(ind).css("margin-bottom", responiveMargin);
});
If it happens to be a child/parent element, than you can just select it.
var banners = $('.sub-banner');
$('.sub-banner-text-wrapper').each(function (ind) {
var textHeight = $(this).height();
var responiveMargin = (textHeight - 62) + 25;
//If a child
$(this).find(".sub-banner").css("margin-bottom", responiveMargin);
//or a parent
$(this).parent().css("margin-bottom", responiveMargin);
});
Maybe Something like this?
if ($(window).width() < 768) {
$('.sub-banner-text-wrapper').each(function () {
var subBanner = $(this).closest('.sub-banner').attr('class');
var textHeight = $(this).height();
var responiveMargin = (textHeight - 62) + 25;
$(subBanner).css("margin-bottom", responiveMargin);
});
}

Moving to sections of a website using jQuery `.scroll()`

I am trying to create a simple effect in jQuery that when the user scrolls down the page, a "pane" is automatically animated into view (so that the user doesn't have to scroll down all of the way themselves).
It's hard to explain, so here is the example: http://jsfiddle.net/naxb22q3/1/
As you can see, when you scroll down past the blue pane a few pixels, the green pane is shown. However, the code that I currently have makes it so that once that green pane is shown, you can no longer scroll up or down. You have to reload the page to get it to work again.
Ideally, the user could scroll up or down and the animations would work.
HTML:
<div class="pane bgBlue"></div>
<div class="pane bgGreen"></div>
<div class="pane bgRed"></div>
CSS:
.pane {
height: 1000px;
width: 100%;
}
.bgBlue {
background-color: blue;
}
.bgGreen {
background-color: green;
}
.bgRed {
background-color: red;
}
JavaScript:
/**
* Lock scroll position for each pane
* as the user scrolls down.
*/
$.fn.scrollView = function () {
return this.each(function () {
$('html, body').animate({
scrollTop: $(this).offset().top
}, 1250);
});
}
// Variables
var windowHeight = $(window).height();
var headerHeight = $('.siteHeader').outerHeight();
var paneHeight = windowHeight - (headerHeight / 2);
// `.scroll()` function
$(window).scroll(function () {
height = $(window).scrollTop();
if (height > 5) {
$('.pane.bgGreen').scrollView();
//$(this).off('scroll');
}
// After we scroll past the green pane,
// the red pane is shown (via the same animation)
if (height > (paneHeight * 2)) {
$('.pane.bgRed').scrollView();
}
});
Rough solution, but a start - http://jsfiddle.net/bkseqsu4/
Javascript:
// Variables
var windowHeight = $(window).height();
var headerHeight = $('.siteHeader').outerHeight();
var paneHeight = windowHeight - (headerHeight / 2);
var scrollLock = 0;
var paneIndex = 0;
var lastScroll = 0;
var panes = ['.pane.bgBlue', '.pane.bgGreen', '.pane.bgRed'];
/**
* Lock scroll position for each pane
* as the user scrolls down.
*/
$.fn.scrollView = function() {
this.each(function() {
$('html, body').animate({
scrollTop: $(this).offset().top
}, 1000, "swing", function() {
setTimeout(function() {
scrollLock = 0;
var currentPosition = $(this).scrollTop();
lastScroll = currentPosition;
}, 100);
});
});
}
// `.scroll()` function
$(window).scroll(function() {
if (scrollLock == 0) {
var currentPosition = $(this).scrollTop();
if (currentPosition > lastScroll) {
paneIndex = paneIndex + 1;
} else {
paneIndex = paneIndex - 1;
}
scrollLock = 1;
$(panes[paneIndex]).scrollView();
}
});

Control page scroll animation with mousewheel

can anybody help me understand how Honda achieved this effect:
http://testdays.hondamoto.ch/
I mean the ease when you scroll.
var $pages = $(".page"),
tot = $pages.length,
c = 0, pagePos = 0, down = 0, listen = true;
$('html, body').on('DOMMouseScroll mousewheel', function(e) {
e.preventDefault();
if(!listen)return;
listen = false;
down = e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0;
c = Math.min(Math.max(0, down ? ++c : --c), tot-1);
pagePos = $pages.eq(c).offset().top;
$(this).stop().animate({scrollTop: pagePos}, 650, function(){
listen = true;
});
});
*{margin:0;}
.page{min-height:100vh;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="page" style="background:#0bf">PAGE 1</div>
<div class="page" style="background:#fb0">PAGE 2</div>
<div class="page" style="background:#0fb">PAGE 3</div>
<div class="page" style="background:#b0f">PAGE 4</div>
P.S:
Use .position().top; if your .pages are inside a scrollable DIV like $("#pagesParent") (instead of $('html, body'))
Notice:
for mobile you might want to adjust the value accounting for the browser's tabs bar height (or best, prevent that behaviour at all). You got the idea
Open up their JS file : http://testdays.hondamoto.ch/js/script_2.js
and search for Utils - Navigation
/***********************************************************************************************/
/************************************ Utils - Navigation *************************************/
/***********************************************************************************************/
/**
* navigation
*/
function navigation(target){
//--Init Quiz
if(!quizRdy){
hideQuiz();
}
//Add class to body
var pageName = target.substr(1).split('-');
$('body').removeClass(lastPage);
$('body').addClass(pageName[0]);
lastPage = pageName[0];
if(resizeBg)retractBg();
resizeBg = false;
busy = true;
$('body').addClass('loading');
//Change Nav Color
$('#nav-wrapper ul.nav li a').each(function(){
$(this).removeClass('selected');
});
var currentNavNumber = currentNav +1;
$('#main_nav_'+currentNavNumber).addClass('selected')
var wHeight = $(window).height();
if(wHeight<1080){
var newMargin = 180 - ( (wHeight - 720)/2 ) ;
if(newMargin<0) newMargin=180;
}else{
var newMargin =0 - (wHeight - 1080)/2;
}
var navTop = $(target).offset().top + newMargin;
navTop += 'px';
trace('navTop : '+navTop);
//$('#nav-wrapper').css('top',navTop);
$('html,body').stop().animate({
scrollTop: $(target).offset().top + newMargin
}, 1000,'easeInOutExpo',function(){
trace('annime done - wHeight : '+wHeight+' target top : '+$(target).offset().top);
if(currentNav==2 && !quizRdy && !quizForm){
showQuiz();
}
if(currentNav==4){
//update social datas
$.getJSON('inc/socials.php', function(data) {
$('#count-fans').empty().append(data['fans-count']);
$('#count-followers').empty().append(data['followers-count']);
});
}
/*
if(currentNav==2){
$('#quiz-nav').livequery(function(){
$(this).show();
});
}else{
$('#quiz-nav').livequery(function(){
$(this).hide();
});
}
*/
$('body').removeClass('loading');
if(currentNav!=0 && currentNav!=4){
$('#nav-wrapper').fadeIn(200);
}else{
$('#nav-wrapper').fadeOut(200);
}
if(currentNav==3){
//--Init Google Map
if(!mapReady){
if(dealerReady){
//init map
initialize();
}else{
askMap = true;
}
}
}
if(wHeight>1080){
extendBg();
}
busy = false;
});
}
/**
* navigation next Page
*/
function nextPage(){
if(currentNav<navArray.length-1 && !busy){
currentNav++;
navigation(navArray[currentNav]);
}
}
/**
* navigation previous Page
*/
function prevPage(){
if(currentNav>0 && !busy){
currentNav--;
navigation(navArray[currentNav]);
}
}
/**
* Center content
*/
function centerContent(){
if(!busy){
//--Retract Background if expended for big screen
if(resizeBg)retractBg();
var wHeight = $(window).height();
var wWidth = $(window).width();
var imgHeight = 0;
//--Test image width / Height and fill the screen
if(wWidth / wHeight > ratioImg ){
//trace('case1 - width : ' + wWidth + ' height : '+wHeight);
if(wHeight > 1080 || wWidth > 1900){
var newImgHeight = wWidth * 1080 / 1920;
$(".bg-image").each(function(){
$(this).css({
'height':newImgHeight+'px',
'width':'100%'
});
});
imgHeight = newImgHeight;
}else{
$(".bg-image").each(function(){
$(this).css({
'height':'1080px',
'width':'1900px'
});
});
imgHeight = 1080;
}
}else{
if(wHeight > 1080 || wWidth > 1900){
$(".bg-image").each(function(){
var newImgWidth = wHeight * 1920 / 1080;
$(this).css({
'height':wHeight+'px',
'width':newImgWidth+'px'
});
});
imgHeight = wHeight;
}else{
$(".bg-image").each(function(){
$(this).css({
'height':'1080px',
'width':'1900px'
});
});
imgHeight = 1080;
}
}
//--Fix height if window > img height
if(wHeight>imgHeight){
$(".bg-image").each(function(){
var newImgWidth = wHeight * 1920 / 1080;
$(this).css({
'height':wHeight+'px',
'width':newImgWidth+'px'
});
});
}
//--Center horizontal bkg image
if(wWidth<1900){
$(".bg-image").each(function(){
var marginCenter = (wWidth - 1900) / 2;
marginCenter = marginCenter * -1;
if($(this).width() > (wWidth + marginCenter)){
$(this).css({'margin-left':-marginCenter+'px'});
}
});
}
//--Scroll to the good position
if(wHeight<1080){
var newMargin = 180 - ( (wHeight - 720)/2 ) ;
if(newMargin<0) newMargin=180;
}else{
var newMargin =0 - (wHeight - 1080)/2;
}
var navTop =$(navArray[currentNav]).offset().top + newMargin;
navTop += 'px';
//$('#nav-wrapper').css('top',navTop);
//trace('Scrool to good position, then expend bg : ' + navArray[currentNav] + ' '+ $(navArray[currentNav]).offset().top);
$('html,body').stop().animate({
scrollTop: $(navArray[currentNav]).offset().top + newMargin
}, 1000,'easeInOutExpo',function(){
if(wHeight>1080){
extendBg();
}
});
}
}
/**
* Extend the background image for big screen ( > 1080 px )
*/
function extendBg(){
var hWin = $(window).height();
if(hWin > 1080){
//--Get & save current page Name
lastBg = navArray[currentNav].split('-');
lastBg = lastBg[0].substr(1);
lastheight = $('#bg-'+lastBg).height();
//--Calculate the position from top to set the scroll position
posToTop = (hWin - $('#bg-'+lastBg).height())/2;
posToTop = $('#bg-'+lastBg).offset().top - posToTop;
lastPosToTop = $('#bg-'+lastBg).offset().top;
//trace('posToTop setting : '+posToTop+' page : ' + lastBg);
//--Set boolean resize to true to call the retract BG
resizeBg = true;
$('#bg-'+lastBg).css({'z-index':2});
//--Test if it's first or last
if(currentNav != 0 && currentNav != (navArray.length-1)){
$('#bg-'+lastBg).animate({
height:hWin+'px',
top:posToTop+'px'
},600);
}else{
if(currentNav==0){
posToTop=0;
$('#bg-'+lastBg).animate({
height:hWin+'px',
top:0
},600);
}else{
posToTop=0;
$('#bg-'+lastBg).animate({
height:hWin+'px',
top:4320+'px'
},600);
}
}
//--Scroll to the bottom for credits page
if(currentNav==(navArray.length-1)){
$('html,body').stop().animate({
scrollTop: $(document).height()
}, 1000,'easeInOutExpo');
}
}
}
/**
* Retrac the background to normal
*/
function retractBg(){
var hWin = $(window).height();
if(resizeBg && lastheight>0 && lastBg!=""){
$('#bg-'+lastBg).css({'z-index':0});
//trace('posToTop callback : '+posToTop + ' lastBg : ' + lastBg + ' lastheight : ' +lastheight);
if(posToTop>0){
//trace('reset pos top : ' + posToTop);
$('#bg-'+lastBg).animate({
height:lastheight+'px',
top:lastPosToTop+'px'
},600)
}else{
$('#bg-'+lastBg).animate({
height:lastheight+'px'
},600)
}
}
}

Drag and Drop -JQuery

Im creating myself a drag functions just for my personal use so I can drag elements around. I'm having a problem. At the moment trying to make the drag so one you pick up the element you can drag it but once you drop it, it goes back to the original position. This is not working as you can see here. When I let go of #drag2 or #drag3 then it goes to the position of #drag1.
My Function:
function drag(el) {
var position = $(el).position();
var ptop = position.top;
var pleft = position.left;
var down = false;
$(el).mousedown(function(event) {
down = true;
$(this).css({
cursor: 'crosshair',
});
$(this).mousemove(function(event) {
if (down == true) {
$(this).css({
cursor: 'crosshair',
});
var w = $(this).width();
var h = $(this).height();
var left3 = (w / 2) + 7;
var top3 = (h / 2) + 7;
$(this).css({
cursor: 'crosshair',
left: (event.clientX) + (3 * 3) - left3,
top: (event.clientY) + (3 * 3) - top3
});
}
}).mouseup(function() {
down = false;
$(this).css({
cursor: 'default',
});
$(this).animate({
top: ptop,
left: pleft
}, 300);
});
});
}
I have to get the old position:
var position = $(el).position();
var ptop = position.top;
var pleft = position.left;
So should it not get the position of all of them and bring them self back to where they were? Any help will be appreciated.
EDIT: I DO NOT WANT TO USE ANY PLUGIN OR JQUERY UI, THANKS ANYWAYS
The solution is very simple
See this fiddle: http://jsfiddle.net/BggPn/4/
you define 1 var for left and 1 for top. All 3 the elements use the same variables. If you loop through the elements then you make a new scope where each element has it's own vars.
Working code:
$(document).ready(function() {
drag('#drag, #drag2, #drag3')
});
function drag(el) {
$(el).each(function(){
var position = $(this).position();
var ptop = position.top;
var pleft = position.left;
var down = false;
$(this).mousedown(function(event) {
down = true;
$(this).css({
cursor: 'crosshair',
});
$(this).mousemove(function(event) {
if (down == true) {
$(this).css({
cursor: 'crosshair',
});
var w = $(this).width();
var h = $(this).height();
var left3 = (w / 2) + 7;
var top3 = (h / 2) + 7;
$(this).css({
cursor: 'crosshair',
left: (event.clientX) + (3 * 3) - left3,
top: (event.clientY) + (3 * 3) - top3
});
}
}).mouseup(function() {
down = false;
$(this).css({
cursor: 'default',
});
$(this).animate({
top: ptop,
left: pleft
}, 300);
});
});
});
}
Make it a plugin:
$.fn.drag = function drag(){
return this.each(function(){
var position = $(this).position();
var ptop = position.top;
var pleft = position.left;
var down = false;
$(this).mousedown(function(event) {
down = true;
$(this).css({
cursor: 'crosshair',
});
$(this).mousemove(function(event) {
if (down == true) {
$(this).css({
cursor: 'crosshair',
});
var w = $(this).width();
var h = $(this).height();
var left3 = (w / 2) + 7;
var top3 = (h / 2) + 7;
$(this).css({
cursor: 'crosshair',
left: (event.clientX) + (3 * 3) - left3,
top: (event.clientY) + (3 * 3) - top3
});
}
}).mouseup(function() {
down = false;
$(this).css({
cursor: 'default',
});
$(this).animate({
top: ptop,
left: pleft
}, 300);
});
});
});
}
Now you can call it by:
$("#drag1, #drag2").drag();
2 thoughts:
1.) Why don't you use jQuery UI (draggable)?
2.) The idea of giving a selector in stead of an element is wrong, a selector can lead to multiple elements, and that's the first reason why it's failing. If you start with
function drag(selector) {
$(selector).each(function() {
var el = $(this);
//rest of code
}
}
it would be better. But I think you'll run into a few other problems eventually
The problem is whenever you're sending in the list of selectors '#drag, #drag2. #drag3' and your position variable only cares about the first one (try changing the order and you'll see they snap to the first in the list). If you want to go about it this way then you'll want to perform an each iteration over them to get the right values.
get the current position of div after drag and set via this
.mouseup(function() {
var position = $(this).position();
down = false;
$(this).css({
cursor: 'default',
});
$(this).animate({
top: position.top,
left: position.left
}, 300);
DEMO
why don't you use drag and drop plugin. see this article
http://viralpatel.net/blogs/2009/05/implement-drag-and-drop-example-jquery-javascript-html.html
or this one
http://plugins.jquery.com/project/dragndrop

Categories