How to disable JavaScript Function when other function is running - javascript

Hi,
I'm learning/practicing to make my custom slider in JS/JQuery, and I've written below code. Its almost running well but little issues. What I'm doing is I'm running it two types,
Auto running after each 5 seconds with autoRun() Function
On every click to slider indicator run to relevant slide with click event.
In below code, I'm facing couple of issues, and will be very thankful to you if you help me.
Issues I'm facing are:
When I click to slider indicator, I want to disable auto Run function for a specific time like 5 second so my slider look more professional.
When it goes to last slide or come back to first slide, console is showing an error below, and it also take double time eg: 10 seconds to go next slide.
"Uncaught TypeError: Cannot read property 'left' of undefined"
$(function () {
var $mainSliderWrap = $('#slider_main_wrapper')
, $sliderMain = $mainSliderWrap.find('.main-slider')
, $sliderchildren = $sliderMain.children('li')
, $sliderIndicator = $mainSliderWrap.find('.slider-main-indicator');
// Slider Setup
window.addEventListener('resize', initMainSlider);
initMainSlider();
// Slider SetUp function
function initMainSlider() {
var wWidth = window.outerWidth
, sliderMainWidth = wWidth * $sliderchildren.length
$sliderMain.css('width', sliderMainWidth + 'px');
$sliderMain.children('li').first().addClass('visible');
$sliderIndicator.children('li').first().addClass('active');
}
// Want to Run Slider on Click event
$sliderIndicator.on('click', 'li', updateMainSlider);
// If Click Event Not happenening then I want to auto run Slider after 5 seconds
autoRun()
function autoRun() {
var mainSliderChildLenght = $sliderchildren.length;
var i = 0;
var next = true;
var dir;
setInterval(function () {
if (mainSliderChildLenght == i || i < 0) {
next = !next;
if (i < 0) {
i = 0;
}
}
if (next) {
dir = 'next';
i++;
}
else {
dir = 'prev';
i--;
if(i < 0) {
return
}
}
updateMainSlider(dir);
$('#result').text(i)
}, 5000);
}
// Here is the function for Updating the Slider
function updateMainSlider(a) {
var visibleSlide = $sliderchildren.filter('.visible')
, actualTranslate = getTranslateValue($sliderMain, 'X');
if (a == 'next' || a == 'prev') { // inside this if is running when function is called from autoRun()
console.log(a)
var newSlide = (a == 'next') ? visibleSlide.next() : visibleSlide.prev()
, newSlideOffsetLeft = newSlide.offset().left
, valueToTranslte = -newSlideOffsetLeft + actualTranslate;
setTranslateValue($sliderMain, 'translateX', valueToTranslte);
visibleSlide.removeClass('visible');
newSlide.addClass('visible');
$sliderIndicator.children('.active').removeClass('active');
$sliderIndicator.find('li').eq(newSlide.index()).addClass('active');
}
else { // inside this if is running when function is called from click event
console.log(a)
var newSlide = $(a.target)
, $newSlideIndicatorIndex = newSlide.index()
, $visibleSlideIndex = visibleSlide.index();
if ($newSlideIndicatorIndex !== $visibleSlideIndex && !$($sliderIndicator).hasClass('disable-click')) {
$($sliderIndicator).addClass('disable-click');
setTimeout(function () {
$($sliderIndicator).removeClass('disable-click');
}, 1000);
var diff = $newSlideIndicatorIndex - $visibleSlideIndex
, valueToTranslte = -(diff * window.outerWidth) + actualTranslate;
setTranslateValue($sliderMain, 'translateX', valueToTranslte);
$($sliderchildren[$visibleSlideIndex]).removeClass('visible');
$($sliderchildren[$newSlideIndicatorIndex]).addClass('visible');
$sliderIndicator.children('.active').removeClass('active');
$sliderIndicator.find('li').eq($newSlideIndicatorIndex).addClass('active');
} // end if
} // end else
} // end function
// SetTranslate Value Fucntion
function setTranslateValue(element, property, value) {
$(element).css({
'transform': property + '(' + value + 'px)'
});
}
// Get Translate Value function
function getTranslateValue(element, axis) {
var trValue = $(element).css('transform');
if (trValue !== 'none') {
trValue = trValue.split(')')[0];
trValue = trValue.split(',');
trValue = (axis == 'X') ? trValue[4] : trValue[5];
}
else {
trValue = 0;
}
return Number(trValue);
}
})
ol {
list-style: none;
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
}
.slider-main-wrapper {
box-shadow: inset 0 0 20px orange;
min-height: 100vh;
}
ol.main-slider {
height: 85vh;
box-shadow: inset 0 0 20px green;
transition: transform 500ms ease;
}
ol.main-slider > li {
float: left;
}
ol.main-slider > li .silder-main-content {
width: 100vw;
height: 85vh;
display: flex;
justify-content: center;
align-items: center;
}
ol.main-slider > li.visible .silder-main-content {
box-shadow: inset 0 0 140px green;
}
ol.slider-main-indicator {
height: 15vh;
display: flex;
}
ol.slider-main-indicator li {
box-shadow: inset 0 0 2px green;
flex: 1;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
ol.slider-main-indicator li.active {
box-shadow: inset 0 0 80px green;
cursor: default;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result" style="font-size: 30px; position: absolute;
top: 0; left: 0"></div>
<div class="slider-main-wrapper" id="slider_main_wrapper">
<ol class="main-slider">
<li>
<div class="silder-main-content">
<h1>First Slide</h1>
</div>
</li>
<li>
<div class="silder-main-content">
<h2>Second Slide</h2>
</div>
</li>
<li>
<div class="silder-main-content">
<h1>Third Slide</h1>
</div>
</li>
<li>
<div class="silder-main-content">
<h1>Fourth Slide</h1>
</div>
</li>
</ol>
<!--end slides-->
<ol class="slider-main-indicator">
<li> <span class="text">First Slide</span> </li>
<li> <span class="text">Second Slide</span> </li>
<li> <span class="text">Third Slide</span> </li>
<li> <span class="text">Fourth Slide</span> </li>
</ol>
<!--end slide indicator-->
</div>

you'll want to clearInterval when you click, the setInterval again once the processing due to the "click" event completes - so, for a start, you'll need to save the returned value of setInterval to use in clearInterval
autoRun in this code returns a function which starts the interval
this is just "part" of your code, not the whole thing - trying to keep it readable regarding the changes I have implemented
$sliderIndicator.on('click', 'li', updateMainSlider);
// save the function returned by autoRun
var go = autoRun();
// start autoRun
go();
// add a variable to store interval identifier
var interval;
function autoRun() {
var mainSliderChildLenght = $sliderchildren.length;
var i = 0;
var next = true;
var dir;
// return a function to begin autoRun for real
return function() {
// save interval identifier
interval = setInterval(function () {
// your code unchanged
}, 5000);
};
}
function updateMainSlider(a) {
var visibleSlide = $sliderchildren.filter('.visible')
, actualTranslate = getTranslateValue($sliderMain, 'X');
if (a == 'next' || a == 'prev') {
// your code - unchanged
} else {
// clear interval
clearInterval(interval);
// your code - unchanged
// now add this to restart the interval
go();
}
}
You may still need to tweak some things, I haven't gone through your code in depth
as requested
$(function () {
var $mainSliderWrap = $('#slider_main_wrapper')
, $sliderMain = $mainSliderWrap.find('.main-slider')
, $sliderchildren = $sliderMain.children('li')
, $sliderIndicator = $mainSliderWrap.find('.slider-main-indicator');
// Slider Setup
window.addEventListener('resize', initMainSlider);
initMainSlider();
// Slider SetUp function
function initMainSlider() {
var wWidth = window.outerWidth
, sliderMainWidth = wWidth * $sliderchildren.length
$sliderMain.css('width', sliderMainWidth + 'px');
$sliderMain.children('li').first().addClass('visible');
$sliderIndicator.children('li').first().addClass('active');
}
// Want to Run Slider on Click event
$sliderIndicator.on('click', 'li', updateMainSlider);
// If Click Event Not happenening then I want to auto run Slider after 5 seconds
var go = autoRun();
// start autoRun
go();
var interval;
function autoRun() {
var mainSliderChildLenght = $sliderchildren.length;
var i = 0;
var next = true;
var dir;
return function() {
setInterval(function () {
if (mainSliderChildLenght == i || i < 0) {
next = !next;
if (i < 0) {
i = 0;
}
}
if (next) {
dir = 'next';
i++;
}
else {
dir = 'prev';
i--;
if(i < 0) {
return
}
}
updateMainSlider(dir);
$('#result').text(i)
}, 5000);
});
}
// Here is the function for Updating the Slider
function updateMainSlider(a) {
var visibleSlide = $sliderchildren.filter('.visible')
, actualTranslate = getTranslateValue($sliderMain, 'X');
if (a == 'next' || a == 'prev') { // inside this if is running when function is called from autoRun()
console.log(a)
var newSlide = (a == 'next') ? visibleSlide.next() : visibleSlide.prev()
, newSlideOffsetLeft = newSlide.offset().left
, valueToTranslte = -newSlideOffsetLeft + actualTranslate;
setTranslateValue($sliderMain, 'translateX', valueToTranslte);
visibleSlide.removeClass('visible');
newSlide.addClass('visible');
$sliderIndicator.children('.active').removeClass('active');
$sliderIndicator.find('li').eq(newSlide.index()).addClass('active');
}
else { // inside this if is running when function is called from click event
clearInterval(interval);
console.log(a)
var newSlide = $(a.target)
, $newSlideIndicatorIndex = newSlide.index()
, $visibleSlideIndex = visibleSlide.index();
if ($newSlideIndicatorIndex !== $visibleSlideIndex && !$($sliderIndicator).hasClass('disable-click')) {
$($sliderIndicator).addClass('disable-click');
setTimeout(function () {
$($sliderIndicator).removeClass('disable-click');
}, 1000);
var diff = $newSlideIndicatorIndex - $visibleSlideIndex
, valueToTranslte = -(diff * window.outerWidth) + actualTranslate;
setTranslateValue($sliderMain, 'translateX', valueToTranslte);
$($sliderchildren[$visibleSlideIndex]).removeClass('visible');
$($sliderchildren[$newSlideIndicatorIndex]).addClass('visible');
$sliderIndicator.children('.active').removeClass('active');
$sliderIndicator.find('li').eq($newSlideIndicatorIndex).addClass('active');
} // end if
go();
} // end else
} // end function
// SetTranslate Value Fucntion
function setTranslateValue(element, property, value) {
$(element).css({
'transform': property + '(' + value + 'px)'
});
}
// Get Translate Value function
function getTranslateValue(element, axis) {
var trValue = $(element).css('transform');
if (trValue !== 'none') {
trValue = trValue.split(')')[0];
trValue = trValue.split(',');
trValue = (axis == 'X') ? trValue[4] : trValue[5];
}
else {
trValue = 0;
}
return Number(trValue);
}
})

Related

JavaScript Boolean is not working and looping goes wrong

The demo created is to illustrate the working of the logic described below -
I have created 4x4 tiles using JavaScript instead of hard coding into html
Code highlight the columns one by one in a infinite loop which is achieved by setInterval(colScan,1000)
When user press the mouse on html body, it changes the column scan --> row scan in the selected column which is also achieved by setInterval(rowScan,1000)
When user clicks again on the html body, it changes the row scan --> col scan
Problem:
No matter what, colScan is always activated which you can see in the console log that the column is always increasing.
When user clicks the second time it doesn't reset to column scan.
part of the code where I think the problem is occurring
createtiles();
var k = 0,
m = 0,
selected_col = "",
mousePressed = false,
col_scan = true,
row_scan = false;
scanSelector();
function scanSelector() {
if (col_scan) {
setInterval(colScan, 1000);
} else if (row_scan) {
setInterval(rowScan, 1000);
}
}
document.body.onmousedown = function() {
mousePressed = true;
}
function colScan() {
if (k > 2) k = 0;
else k++;
console.log("col " + k);
var col = ".j_" + k;
$(".tiles").removeClass('highlighter');
$(col).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = false;
row_scan = true;
selected_col = col;
scanSelector();
}
}
function rowScan() {
if (m > 2) m = 0;
else m++;
console.log("row " + m);
var row = selected_col + (".i_" + m);
$(".tiles").removeClass('highlighter');
$(row).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = true;
row_scan = false;
selected_col = "";
scanSelector();
}
}
function createtiles() {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var divTile = $('<div>', {
class: 'tiles ' + ("j_" + j) + " " + ("i_" + i)
});
divTile.appendTo('.comtile');
}
}
}
DEMO -> https://codepen.io/xblack/pen/BdGzYx
createtiles();
var k = 0,
m = 0,
selected_col = "",
mousePressed = false,
col_scan = true,
row_scan = false;
scanSelector();
function scanSelector() {
if (col_scan) {
setInterval(colScan, 1000);
} else if (row_scan) {
setInterval(rowScan, 1000);
}
}
document.body.onmousedown = function() {
mousePressed = true;
}
function colScan() {
if (k > 2) k = 0;
else k++;
console.log("col " + k);
var col = ".j_" + k;
$(".tiles").removeClass('highlighter');
$(col).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = false;
row_scan = true;
selected_col = col;
scanSelector();
}
}
function rowScan() {
if (m > 2) m = 0;
else m++;
console.log("row " + m);
var row = selected_col + (".i_" + m);
$(".tiles").removeClass('highlighter');
$(row).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = true;
row_scan = false;
selected_col = "";
scanSelector();
}
}
function createtiles() {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var divTile = $('<div>', {
class: 'tiles ' + ("j_" + j) + " " + ("i_" + i)
});
divTile.appendTo('.comtile');
}
}
}
html,
body {
margin: 0px;
padding: 0px;
height: 100%;
min-height: 100%;
overflow: hidden;
font-family: 'Roboto', sans-serif;
background: white;
}
* {
box-sizing: border-box!important;
}
.conatiner {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-template-area: "menu" "comContent";
}
.menu {
grid-area: menu;
height: 5vh;
padding: 2vh;
}
.comtile {
grid-area: comContent;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: auto;
grid-gap: 0.5vh;
height: 95vh;
padding: 2vh;
}
.tiles {
background: #F7F7F7;
border-radius: 0.4vh;
border: 1px solid #EEEBEB;
}
.highlighter {
box-shadow: 0 0 4px rgba(0, 0, 0, 0.15);
transition: box-shadow 0.3s cubic-bezier(0.38, -0.76, 0, 1.69);
border: 1px solid silver;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container">
<div class="menu">MAIN MENU</div>
<div class="comtile"></div>
</div>
You need to make the following changes:
Replace setInterval with setTimeout for reasons stated by #ASDFGerte.
function scanSelector() {
if (col_scan) {
// Replace setInterval with setTimeout
setTimeout(colScan, 1000);
} else i f (row_scan) {
// Replace setInterval with setTimeout
setTimeout(rowScan, 1000);
}
}
Move the scanSelector() lines in rowScan and colScan. The change is the same for both methods, I will only show the change in rowScan.
function rowScan() {
if (m > 2) m = 0;
else m++;
console.log("row " + m);
var row = selected_col + (".i_" + m);
$(".tiles").removeClass('highlighter');
$(row).addClass('highlighter');
if (mousePressed) {
mousePressed = false;
col_scan = true;
row_scan = false;
selected_col = "";
// Remove this line
// scanSelector();
}
// Because you're no longer using setInterval you need to call
// this method after each timeout.
scanSelector();
}
Every time you were calling scanSelector() it would create another interval. The initial interval will highlight the columns, after the first click you have two intervals running side-by-side: the original interval and an interval to highlight rows. After each click you're only adding intervals.
You could store the interval ID, the result of setInterval and clear this interval when you change from column to row highlight and vice versa. The easier solution is moving from setInterval to setTimeout as outlined in the changed I've shown you above.

Mousewheel scroll event fire only once per scroll-session [duplicate]

This question already has an answer here:
jQuery page scroll event logic -- how to throttle
(1 answer)
Closed 6 years ago.
I am trying to mimic the functionality of the following website: www.verbaasd.net. Each scrolling "session" will only trigger one action.
Each time a user scrolls down an action will happen depending on the status of variabel count. I only want this to happen ONCE per scroll. For example if a user has a Macbook with touchpad it will fire multiple times very vast. The count will go from 1 to 4 pretty much instantly. Is there a way to set a timeout or something so it stops for 0.5 sec when variabel count increases or decreases by 1?
Current code:
var count = 1;
$(window).on('mousewheel DOMMouseScroll', function(e) {
if (e.originalEvent.wheelDelta / 120 > 0) {
count -= 1;
} else {
count += 1;
}
if (count < 1) count = 1;
if (count > 4) count = 4;
switch (count) {
case 1:
// do something
break;
case 2:
// do something
break;
case 3:
// do something
break;
case 4:
// do something
break;
}
$(".cd-background-wrapper").attr("data-slide", count);
});
I recommend other way.
You should use 'preventDefault' and delay effect using setTimeout.
I wrote a simple prototype code below link.
(only tested on Chrome and safari)
http://codepen.io/nigayo/pen/PNEvmY
[HTML]
<body>
<div id="wrap">
<section>section A</section>
<section>section B</section>
<section>section C</section>
<section>section D</section>
</div>
</body>
[CSS]
body {
overflow: hidden;
height: 100%;
}
#wrap {
position: relative;
width: 100%;
height: 100%;
top: 0;
}
section {
width: 100%;
height: 600px;
}
section:nth-child(1) {
background: red;
}
section:nth-child(2) {
background: blue;
}
section:nth-child(3) {
background: green;
}
section:nth-child(4) {
background: magenta;
}
[JavaScript]
(function() {
var currentPanel = 1;
var wrap = $('#wrap');
var panelsize = 600;
var step = 10;
var interval = 1000;
var direction = 1;
var bAnimation = false;
function animation() {
setTimeout(function() {
var currentTop = parseInt(wrap.css("top"));
if (direction < 0) {
if (currentTop <= minValue) {
setTimeout(function() {
bAnimation = false;
}, interval);
return;
}
} else {
if (currentTop >= minValue) {
setTimeout(function() {
bAnimation = false;
}, interval);
return;
}
}
wrap.css({
"top": currentTop - step
});
animation();
}, 16);
}
$(window).bind('mousewheel DOMMouseScroll', function(event) {
event.preventDefault();
if (bAnimation) return;
var currentTop = parseInt(wrap.css("top"));
if (event.originalEvent.wheelDelta < 0) {
//down scroll
minValue = currentTop - panelsize;
step = 10;
direction = -1;
} else {
//up scroll
minValue = currentTop + panelsize;
step = -10;
direction = 1;
}
console.log(minValue, bAnimation);
bAnimation = true;
animation();
});
})();
If you refer to my codes, you should use 'jquery animate function' or 'requestAnimationframe' for animation logic.
Answer thanks to A. Wolff. Using _.throttle with lodash.js did the trick! You can find more info here: https://css-tricks.com/the-difference-between-throttling-and-debouncing/

How to define a variable of multiple variables in JavaScript

I would like to know how can I define a bigger variable for a set of variables that I have in javascript: showFootnotesPanel();, showReferencesPanel();, showImagesPanel();, showInformationPanel();.
Would it be something like this?
function showPanel() {
var x = [showFootnotesPanel();showReferencesPanel();showImagesPanel();showInformationPanel();]
}
Update:
I have this function that used to open a side panel on the right side and color the content:
var els = document.getElementsByClassName('change-color'),
target = document.getElementsByClassName('resources'),
changeColor = function(a) {
elements = document.getElementsByClassName("note");
for (var i = 0; i < elements.length; i++) {
console.log(elements[i])
elements[i].style.backgroundColor = "";
}
target = a.getAttribute('href');
element = document.querySelector('[data-id="' + target.substring(1, target.length) + '"]');
element.style.backgroundColor = a.getAttribute('data-color');
};
for (var i = els.length - 1; i >= 0; --i) {
els[i].onclick = function() {
showFootnotesPanel();
changeColor(this);
}
Now I have 4 side panels that need to respond to the same script, and I thought that by defining something like showPanel() is showFootnotesPanel() or showReferencesPanel() or showImagesPanel() or showInformationPanel() I might simplify things, so the last line of the script would be this instead just:
els[i].onclick = function(){showPanel();changeColor(this);}
Update 2:
Or is it possible to do this with the logical operator OR?
els[i].onclick = function(){showFootnotesPanel(); || showReferencesPanel(); || showImagesPanel(); || showInformationPanel();changeColor(this);}
Update 3:
This is the new script that I am using to hide and show the panels:
function showPanel(myPanel) {
var elem = document.getElementById(myPanel);
if (elem.classList) {
console.log("classList supported");
elem.classList.toggle("show");
} else {
var classes = elem.className;
if (classes.indexOf("show") >= 0) {
elem.className = classes.replace("show", "");
} else {
elem.className = classes + " show";
}
console.log(elem.className);
}
}
function hideOthers(one, two, three, four) {
if (one > "") {
var elem1 = document.getElementById(one);
var classes = elem1.className;
elem1.className = classes.replace("show", "");
}
if (two > "") {
var elem2 = document.getElementById(two);
var classes = elem2.className;
elem2.className = classes.replace("show", "");
}
if (three > "") {
var elem3 = document.getElementById(three);
var classes = elem3.className;
elem3.className = classes.replace("show", "");
}
if (four > "") {
var elem4 = document.getElementById(four);
var classes = elem4.className;
elem4.className = classes.replace("show", "");
}
return;
}
And this is the script that calls the panels and highlights the text on them:
var els = document.getElementsByClassName('change-color'),
target = document.getElementsByClassName('resources'),
changeColor = function(a) {
elements = document.getElementsByClassName("note");
for (var i = 0; i < elements.length; i++) {
console.log(elements[i])
elements[i].style.backgroundColor = "";
}
target = a.getAttribute('href');
element = document.querySelector('[data-id="' + target.substring(1, target.length) + '"]');
element.style.backgroundColor = a.getAttribute('data-color');
};
for (var i = els.length - 1; i >= 0; --i) {
els[i].onclick = function() {
hideOthers('footnotes-section', 'references-section', 'images-section', 'information-section');
showPanel('references-section');
changeColor(this);
}
}
Thank you!
Updated with a final solution.
In javascript you can declare variables by this way:
var text = ""; // String variable.
var number = 0; //Numeric variable.
var boolValue = true; //Boolean variable.
var arrayValue = []; // Array variable. This array can contain objects {}.
var obj = {}; // Object variable.
Check this version of your code.
// var text = ""; => String variable.
// var number = 0; => Numeric variable.
// var boolValue = true; => Boolean variable.
// var arrayValue = []; => Array variable. This array can contain objects {}.
// var obj = {}; => Object variable.
// This section of code is only to explain the first question.
(function() {
function showFootnotesPanel() {
return 10; // Random value.
}
function showReferencesPanel() {
return 30; // Random value.
}
function showImagesPanel() {
return 50; // Random value.
}
function showInformationPanel() {
return 90; // Random value.
}
function showPanel() {
return [
showFootnotesPanel(), // Index = 0
showReferencesPanel(), // Index = 1
showImagesPanel(), // Index = 2
showInformationPanel() // Index = 3
];
}
var bigVariable = showPanel(); // bigVariable is array of numeric values.
// Using logical operator to check status of variable about this demo code.
if (bigVariable[0] === 10 || bigVariable[1] === 30) {
console.log("Hey, with these values can show the FootnotesPanel and ReferencesPanel.");
} else {
console.log("With the current values can't show anything...");
}
console.log(bigVariable);
})();
// https://jsfiddle.net/dannyjhonston/t5e8g22b/
// This section of code attempts to answer the question of this post.
(function() {
// This function can be executed when the page is loaded.
function showPanel(panels) {
var panel, panelVisible = "";
var selPanels = document.getElementById("selPanels");
// In panels array...
for (var i = 0; i < panels.length; i++) {
// panels[0] = "ReferencesPanel";
panel = document.getElementById(panels[i]); // Get in the DOM tag context of the panel to set in the variable "panel".
panelVisible = panel.getAttribute("data-visible"); // HTML5 data attribute.
if (panelVisible == "true") {
panel.setAttribute("class", "show");
} else {
panel.setAttribute("class", "hide");
}
}
}
// This function is for set panel visibilty.
function setPanel(panelId, status) {
panel = document.getElementById(panelId);
panel.setAttribute("data-visible", status);
// Calling the showPanel function to check in the DOM.
showPanel(["ReferencesPanel", "InformationPanel", "ImagesPanel", "FootnotesPanel"]);
}
// Binding the change event to the select tag.
selPanels.addEventListener("change", function() {
// Executes setPanel function with panelId and true to update the data-visible attribute in the DOM.
setPanel(this.options[this.selectedIndex].value, "true");
});
// Executes showPanel function with array argument with panels Id. You need to specify every panel that want to handle.
showPanel(["ReferencesPanel", "InformationPanel", "ImagesPanel", "FootnotesPanel"]);
})();
#global {
border: solid 1px #6291AD;
}
.tools {
background-image: linear-gradient(#FFFFFF, #8999CE);
}
#global div[data-visible] {
height: 80px;
padding: 5px 0;
}
#global div p {
padding: 10px;
}
#ReferencesPanel {
background-image: linear-gradient(#FFFFFF, #FD9A9A);
float: left;
width: 20%;
}
#InformationPanel {
background-image: linear-gradient(#FFFFFF, #A1C7F1);
float: left;
width: 80%;
}
#ImagesPanel {
background-image: linear-gradient(#C6E9FB, #FFF);
width: 100%;
}
#FootnotesPanel {
background-image: linear-gradient(#C6E999, #FFF);
width: 100%;
}
.clear {
clear: both;
}
.show {
display: block;
}
.hide {
display: none;
}
<div id="global">
<div class="tools">Show Panel:
<br />
<!-- Demo -->
<select id="selPanels">
<option value="">[SELECT]</option>
<option value="ReferencesPanel">ReferencesPanel</option>
<option value="InformationPanel">InformationPanel</option>
<option value="ImagesPanel">ImagesPanel</option>
<option value="FootnotesPanel">FootnotesPanel</option>
</select>
</div>
<!-- You need to set data-visible attribute with true or false to show or hide a panel. -->
<div id="ReferencesPanel" data-visible="false">
<p>References Panel</p>
</div>
<div id="InformationPanel" data-visible="false">
<p>Information Panel</p>
</div>
<div class="clear"></div>
<div id="ImagesPanel" data-visible="false">
<p>Images Panel</p>
</div>
<div id="FootnotesPanel" data-visible="false">
<p>Foot notes Panel</p>
</div>
</div>
I dont understand your question exactly, but if you want to define a variable that contains other variables then you can use an object.
e.g:
var footNotesPanel = true;
var referencesPanel = true;
var imagesPanel = true;
var showPanels = {
footNotesPanel: footNotesPanel,
referencesPanel: referencesPanel,
imagesPanel: imagesPanel
}
/*
Option 2 - for showing/hiding side panels
1 ) create all your panels as they would appear, with all the data, but hide them with display:none;
2 ) call show panel function to show a panel.
*/
var showPanel(panel_id) {
var panel_element = $("#" + panel_id); /*panel that you want to show ( is hidden atm but somewhere on the page */
if (!panel_element.length) {
return false; //no panel with this id currently on page
} else {
//check the panel id and do some custom editing if needed, eg.
if (panel_id == "main_side_panel") {
//add some additional classes to body element etc
}
panel_element.show();
//Or Another option that you probably are looking for is below
if (panel_id == "footnotes_panel") {
showFootnotesPanel();
} else if (panel_id == "images_panel") {
showImagesPanel();
}
}
}
// And use it like this:
<div id="footnotes_panel" onclick="showPanel('footnotes_panel')"></div>
// Or simply get the element id from `event.target` and use `showPanel()` without arguments.

.hover() seems to overwrite .click()

A little background of my problem:
I'm making a board-based game when the user is going to be able to make a path from a square to another one, the thing is that when a square is clicked it should stay highlighted no matter if pointer is over of it and then leaves it. It seems when the square is clicked and then the pointer leaves it the handlerIn of .hover() changes the state of the square's path-type attribute making possible to the square to be unhighlited when the pointer enter and leaves the square.
this is what I've got so far:
$(function() {
$('td.soccer-field').click(function(){
if ($('#dice1').text() != '' && $('#dice2').text() != '') {
if ($("[path-type='begin-path']").length == 0) {
$(this).attr('path-type','begin-path');
} else if ($("[path-type='begin-path']").length && $(this).attr('path-type') != 'end-path'){
$(this).attr('path-type','end-path');
$('[path-type="selecting-actual-path"]').attr('path-type','actual-path');
} else if ($(this).attr('path-type') == 'end-path'){
$(this).attr('path-type','');
};
}
});
$('td.soccer-field').hover(
function () {
if ($('#dice1').text() != '' && $('#dice2').text() != '') {
if ($("[path-type='begin-path']").length == 0) {
$(this).attr('path-type','select-begin-path');
} else if ($(this).attr('path-type') == ''){
var actualCell = $(this).attr('id') + $(this).parent().attr('id');
var cell, distance,dicesResult = parseInt($('#dice1').text())+ parseInt($('#dice2').text());
$("[path-type*='path']").each(function () {
cell = $(this).attr('id') + $(this).parent().attr('id');
distance = new Board().calculateDistanceSquares(actualCell,cell);
if (distance == 1 && $("[path-type='selecting-actual-path']").length < (dicesResult -2))
{
$(this).attr('path-type','selecting-actual-path');
return false;
}
});
}
};
},function () {
if ($(this).attr('path-type') == 'selecting-actual-path' || $(this).attr('path-type') == 'select-begin-path') {
$(this).attr('path-type','');
}
});
$('#diceRoller').click(function() {
$('#dice1').text(Math.floor(Math.random()*6)+1);
$('#dice2').text(Math.floor(Math.random()*6)+1);
$(this).attr('disabled',true);
});
});
//function Board(playerTurn, piecesPosition, gamePhase, gameBegginingType, container)
function Board(){
this.buildBoard = function (container) {
var board = $('<table></table>').attr('id','board');
var row, cell,containerHeight,containerWidth;
for (var i=0; i<10; i++){
row = $('<tr></tr>').attr('id',i+1);
for (var j=0; j<20; j++){
cell = $('<td></td>');
cell.attr('path-type','');
if ((j == 0 || j == 19) && (i >= 3) && (i <= 6)) {
cell.addClass('behind-goal');
}
else if ((j > 0) && (j < 19)){
cell.attr('id',String.fromCharCode(j+96));
cell.addClass("soccer-field");
};
row.append(cell);
}
board.append(row);
}
$('#'+container).append(board);
};
this.calculateHorizontalDistance = function (sq1,sq2) {
var column1 = sq1.substring(0,1).charCodeAt(0);
var column2 = sq2.substring(0,1).charCodeAt(0);
return ( Math.abs(column1-column2) );
};
this.calculateVerticalDistance = function (sq1, sq2) {
var row1 = parseInt(sq1.substring(1));
var row2 = parseInt(sq1.substring(1));
return ( Math.abs(row1-row2) );
};
this.calculateDistanceSquares = function(sq1, sq2){
return(this.calculateVerticalDistance(sq1,sq2)+this.calculateHorizontalDistance(sq1,sq2));
}
}
var board = new Board();
board.buildBoard('left');
#left table{
width: 60em;
height: 25em;
border:0.2em solid black;
border-collapse:collapse;
}
#left table tr{
height: 2.5em;
}
#left table tr td{
width: 3.33em;
}
td.soccer-field{
border: 0.1em solid black;
}
td.behind-goal{
background-color: #F8FAB4;
}
td[path-type*="path"]{
border: 0.15em solid #F8FAB4;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="boardContainer">
<div id="right">
<p id="dice1"></p><p id="dice2"></p>
<button id="diceRoller">Lanzar Dados</button>
</div>
<div id="left"></div>
</div>
A little help will be really appreciate
To prevent that you can add an attribute on the element whenever it is clicked and remove it later on second click. Now in the hover handler check for this attribute on the element, if it is present(or set) then don't do anything just return from the handler.
Something like this
$('td.soccer-field').click(function(){
$(this).data('clicked', !!$(this).data('clicked'));
...
...
});
$('td.soccer-field').hover(
function () {
if ($(this).data('clicked')) return;
...
...
},
function () {
if ($(this).data('clicked')) return;
...
...
});

Using sprite to create a rotation with Javascript

I'm creating an animation of a ring rotating.
On hover the right rotates 180 degrees, pauses and rotates back to the starting position. If the user removes the cursor off the ring while its animating it needs to reverse from the frame its currently on.
I haven't had much extensive experience with animation in my career as a front end developer so any advice on tech to use would be appreciated.
Currently I'm using CSS Animation with a sprite, as below but it lacks the ability to reverse from the frame it was on when the user leaves the ring.
Here is my working example, It's inspired by http://renren.com/
Example using CSS
$('body').on('mouseenter', '.item', function() {
$(this).removeClass('unactive').addClass('active');
});
$('body').on('mouseleave', '.item', function() {
$(this).removeClass('active').addClass('unactive');
});
.content {
width: 150px;
height: 150px;
background-color: #EBEBEB;
}
.content.ring {
background: url(http://a.xnimg.cn/nx/apps/login/cssimg/qrcode1-t.jpg) 0 0 no-repeat
}
.active .content {
background-position: 0 -1800px;
-moz-animation: movedown 2000ms steps(12) forwards;
-webkit-animation: movedown 2000ms steps(12) forwards
}
.unactive .content {
-moz-animation: moveup 2000ms steps(7) forwards;
-webkit-animation: moveup 2000ms steps(7) forwards
}
#-moz-keyframes movedown {
0% {
background-position: 0 0
}
100% {
background-position: 0 -1800px
}
}
#-moz-keyframes moveup {
0% {
background-position: 0 -1800px
}
100% {
background-position: 0 -2850px
}
}
#-webkit-keyframes movedown {
0% {
background-position: 0 0
}
100% {
background-position: 0 -1800px
}
}
#-webkit-keyframes moveup {
0% {
background-position: 0 -1800px
}
100% {
background-position: 0 -2850px
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
HTML
<div class="item active">
<div class="content ring">
</div>
</div>
I've also found plugins like:
motio
So my question is, is CSS able to have this much control or would a CANVAS or other jQuery plugin be better suited?
EDIT
I'm still having difficulties figuring this one out although I started writing a script to help control the animation.
I'm trying to control the background position to gain control of the sprite rotating.
Example using Javascript
;(function($) {
var Ring = function (options) {
// context
var self = this;
// defaults
var currFrame = 1, totalFrames, width, height, timeout;
// default frame array
var framesObj = {};
// option defaults
self.class = "";
self.spriteHeight = "";
//properties based on options
if (typeof options != 'undefined' && options != undefined && options != null)
{
self.class = options.class;
self.spriteHeight = options.spriteHeight;
self.speed = options.speed;
}
// fire off everything you need
self.init = function ()
{
self.buildArr();
}
// check for the container dimentions
self.frameDimentions = function ()
{
// double check we have a class to select the container with
var container = self.class ? true : false;
// I know I could just write self.class in the if..
if ( container )
{
var container = $("." + self.class + "");
var containerHeight = container.outerHeight();
var containerWidth = container.outerWidth();
return [containerHeight,containerWidth];
}
console.log("Please provide a class");
}
// calculate frames e.g. 3000 into 150 per frame is 20..
self.calcFrames = function()
{
var totalFrames = parseInt(self.spriteHeight) / self.frameDimentions()[0];
return totalFrames;
}
self.buildArr = function()
{
// these values need to be pushed in to the arr
for (var i = 0; i < self.calcFrames(); i++) {
framesObj[(i+1)] = self.frameDimentions()[0]*i;
}
}
self.startForwardAnimation = function(){
// to stop manic clicking../hover..
if( currFrame <= 1 )
{
timeout = setInterval( updateFrameForward, self.speed);
}
}
self.startBackwardAnimation = function(){
// to stop manic clicking../hover..
console.log("start backward animation");
if( currFrame != 1 )
{
backTimeout = setInterval( updateFrameBackward, self.speed);
}
}
self.stopAnimation = function(){
//currFrame = 1;
clearTimeout(timeout);
}
self.reset = function(){
clearTimeout(timeout);
clearTimeout(backTimeout);
currFrame = 1;
}
self.info = function(){
$('.info').html(currFrame);
}
// if currFrame less than total frames
// add one to it
// update the current frame variable
// stop and clear timer when reach the end
function updateFrameForward(){
//check if we are in available frames..
if ( currFrame == self.calcFrames() )
{
self.stopAnimation();
self.reset();
}
$("." + self.class + "").css({
'background-position-y': "-" + framesObj[currFrame] + "px"
});
self.info();
currFrame = currFrame + 1;
}
function updateFrameBackward(){
if( currFrame <= 1 )
{
self.stopAnimation();
self.reset();
}
$("." + self.class + "").css({
'background-position-y': framesObj[currFrame] + "px"
});
self.info();
console.log(currFrame);
currFrame = currFrame - 1;
}
}
var ringAniamtion = new Ring({
class: "animate",
spriteHeight: "3000",
speed: "20"
});
$('body').on('mouseenter', '.animate', function(event){
event.preventDefault();
console.log("mouse enter");
ringAniamtion.buildArr();
ringAniamtion.startForwardAnimation();
});
$('body').on('mouseleave', '.animate', function(event){
event.preventDefault();
console.log("mouse leave");
ringAniamtion.stopAnimation();
ringAniamtion.startBackwardAnimation();
});
$('body').on('click', '.stop', function(event){
event.preventDefault();
ringAniamtion.reset();
});
})( jQuery );
// timeout = setTimeout('timeout_trigger()', 3000);
// clearTimeout(timeout);
.content
{
width: 150px;
height: 150px;
background: url(http://a.xnimg.cn/nx/apps/login/cssimg/qrcode1-t.jpg) 0 0 no-repeat;
cursor: pointer;
}
<div class="content animate">
</div>
<div class="info">
</div>
stop
I figured out how to do it in the second code snippet..
;(function($) {
var Ring = function (options) {
// context
var self = this;
// defaults
var currFrame = 1, totalFrames, width, height, timeout;
// default frame array
var framesObj = {};
// option defaults
self.class = "";
self.spriteHeight = "";
//properties based on options
if (typeof options != 'undefined' && options != undefined && options != null)
{
self.class = options.class;
self.spriteHeight = options.spriteHeight;
self.speed = options.speed;
}
// fire off everything you need
self.init = function ()
{
self.buildArr();
}
// check for the container dimentions
self.frameDimentions = function ()
{
// double check we have a class to select the container with
var container = self.class ? true : false;
// I know I could just write self.class in the if..
if ( container )
{
var container = $("." + self.class + "");
var containerHeight = container.outerHeight();
var containerWidth = container.outerWidth();
return [containerHeight,containerWidth];
}
console.log("Please provide a class");
}
// calculate frames e.g. 3000 into 150 per frame is 20..
self.calcFrames = function()
{
var totalFrames = parseInt(self.spriteHeight) / self.frameDimentions()[0];
return totalFrames;
}
self.buildArr = function()
{
// these values need to be pushed in to the arr
for (var i = 0; i < self.calcFrames(); i++) {
framesObj[(i+1)] = self.frameDimentions()[0]*i;
}
}
self.startForwardAnimation = function(){
// to stop manic clicking../hover..
if( currFrame <= 1 )
{
timeout = setInterval( updateFrameForward, self.speed);
}
}
self.startBackwardAnimation = function(){
// to stop manic clicking../hover..
console.log("start backward animation");
if( currFrame != 1 )
{
backTimeout = setInterval( updateFrameBackward, self.speed);
}
}
self.stopAnimation = function(){
//currFrame = 1;
clearTimeout(timeout);
}
self.reset = function(){
clearTimeout(timeout);
clearTimeout(backTimeout);
currFrame = 1;
}
self.info = function(){
$('.info').html(currFrame);
}
// if currFrame less than total frames
// add one to it
// update the current frame variable
// stop and clear timer when reach the end
function updateFrameForward(){
//check if we are in available frames..
if ( currFrame == self.calcFrames() )
{
self.stopAnimation();
self.reset();
}
$("." + self.class + "").css({
'background-position-y': "-" + framesObj[currFrame] + "px"
});
self.info();
currFrame = currFrame + 1;
}
function updateFrameBackward(){
if( currFrame <= 1 )
{
self.stopAnimation();
self.reset();
}
$("." + self.class + "").css({
'background-position-y': framesObj[currFrame] + "px"
});
self.info();
console.log(currFrame);
currFrame = currFrame - 1;
}
}
var ringAniamtion = new Ring({
class: "animate",
spriteHeight: "3000",
speed: "20"
});
$('body').on('mouseenter', '.animate', function(event){
event.preventDefault();
console.log("mouse enter");
ringAniamtion.buildArr();
ringAniamtion.startForwardAnimation();
});
$('body').on('mouseleave', '.animate', function(event){
event.preventDefault();
console.log("mouse leave");
ringAniamtion.stopAnimation();
ringAniamtion.startBackwardAnimation();
});
$('body').on('click', '.stop', function(event){
event.preventDefault();
ringAniamtion.reset();
});
})( jQuery );

Categories

Resources