Incrementing in JavaScript - javascript

I'm trying to create a sliding sidebar and was wondering if there was a better way then what I am doing already.
<img id = "MenuIcon" src = "MenuIcon.png" alt = "Menu Icon" onclick = "slideSideBar()" />
At the moment I simply check if the sideSlideCount is even - if it is the sidebar must not be out, so when the function is called it slides out; if sideSlideCount is odd (i.e. % 2 != 0) then the sidebar should slide out of view.
var sideSlideCount = 0; // variable used with the side bar
var bodyHeight = $(window).height();
var bodyWidth = $(window).width();
console.log(bodyWidth);
function slideSideBar() {
if (sideSlideCount % 2 == 0) { // if sideSlideCount is even, i.e. the side bar is hidden
$("#SideBar").animate({width: bodyWidth / 6}, 600); // slide the bar out to 300 width, 0.6 seconds
$("#SideLinks").fadeTo(1000, 0.8); // fade the links into view, 1 second, to 100% opacity
}
else { // else, if the side bar is in view
$("#SideBar").fadeIn(300).animate({width: 0}, 600); // slide the bar back out of view (0 width), 0.6 seconds
$("#SideLinks").fadeTo(200, 0); // fade the links out of view, 0.2 seconds, to 0% opacity
}
sideSlideCount++; // increment the variable
}

You could simply make your code modular to avoid global variables. You should be looking into AMD modules, however to keep it simple you can create yourself a namespace where your code will live.
DEMO: http://jsfiddle.net/BzYuQ/
//Define a SlidingSidebar reusable component
!function (ns, $) {
function SlidingSidebar(el, animateDuration) {
this.$el = $(el);
this.animateDuration = animateDuration;
}
SlidingSidebar.prototype = {
constructor: SlidingSidebar,
toggle: function () {
this.$el.stop().animate({ width: 'toggle' }, this.animateDuration);
}
};
ns.SlidingSidebar = SlidingSidebar;
}(slideExampleSite = window.slideExampleSite || {}, jQuery);
$(function () {
//The following behavior could also be in a configurable "SlidebarFeature" module
//or you could integrate the button directly into the SlidingSidebar.
//I'm just showing how code can be modularized here.
var sideBar = new slideExampleSite.SlidingSidebar('#sidebar', 600);
$('#toggle-btn').click(function () {
sideBar.toggle();
});
});
Obviously in this case the SlidingSidebar component doesn't do much, but as your application grows, modularizing your code to get away from the $(function () {/*tons of code*/}); anti-pattern will pay off in many ways.

You didn't say what "better" is, but if the intention is just to avoid globals, you can use a closure:
var slideSideBar = (function() {
var sideSlideCount = false; // variable used with the side bar
var bodyHeight = $(window).height();
var bodyWidth = $(window).width();
console.log(bodyWidth);
// This function has access to all the above variables, but no other
// function does.
function slideSideBar() {
if (sideSlideCount) {
$("#SideBar").animate({width: bodyWidth / 6}, 600);
$("#SideLinks").fadeTo(1000, 0.8);
} else {
$("#SideBar").fadeIn(300).animate({width: 0}, 600);
$("#SideLinks").fadeTo(200, 0);
}
sideSlideCount = !sideSlideCount;
}
// Return a reference to the slideSideBar function so it's available
// globally, but access to variables is "private"
return slideSideBar;
}());
The only difference is that slideSideBar won't exist until the above has been executed, so don't try to call it until afterward.

Not sure on your definition of "better", but I see your using jQuery which has a nice $toggle feature which can help here.
function slidesideBar(){
$("#SideBar").toggle(function() {
$(this).animate({width: bodyWidth / 6}, 600); // slide the bar out to 300 width, 0.6 seconds
$("#SideLinks").fadeTo(1000, 0.8); // fade the links into view, 1 second, to 100% opacity
}, function() {
$(this).fadeIn(300).animate({width: 0}, 600); // slide the bar back out of view (0 width), 0.6 seconds
$("#SideLinks").fadeTo(200, 0); // fade the links out of view, 0.2 seconds, to 0% opacity
});​
}
Credit: jQuery Animation Toggle. Copy and paste:
When given a list of functions as arguments, the .toggle(fn1, fn2) method will alternate between the functions given starting with the first one. This automatically keeps track of the toggle state for you - you don't have to do that.
jQuery doc is here. There are multiple forms of .toggle() depending upon the arguments used so you don't always find the right one when searching the jQuery doc.

Related

javascript to be activate on page scroll

i've got some code from codepen where a progress bar fills up depending on a given number out of 100. i want it to activate when it is scrolled to, instead of on reload, which it currently is set to. I cant find anything on here already.
Javascript is new to me, so trying to get the hang of it, thanks
$('.progress-wrap').each(function(){
percent = $(this);
bar = $(this).children('.progress-bar');
moveProgressBar(percent, bar);
});
// on browser resize...
$(window).resize(function() {
$('.progress-wrap').each(function(){
percent = $(this);
bar = $(this).children('.progress-bar');
moveProgressBar(percent, bar);
});
});
// SIGNATURE PROGRESS
function moveProgressBar(percent, bar) {
var getPercent = (percent.data('progress-percent') / 100);
var getProgressWrapWidth = percent.width();
var progressTotal = getPercent * getProgressWrapWidth;
var animationLength = 1000;
// on page load, animate percentage bar to data percentage length
// .stop() used to prevent animation queueing
bar.stop().animate({
left: progressTotal
}, animationLength);
}
<div class="progress-wrap progress star" data-progress-percent="70">
<div class="progress-bar progress"></div>
</div>
This should work:
Replace #someElement with the Id of the element that when in view fires the function you want.
someFunction() is the function that you want to run when the element is in view
$(document).on('scroll', function() {
if( $(this).scrollTop() >= $('#someElement').position().top ) {
someFunction();
}
});
Looks like you are using jquery - it would be easier to do this in vanilla javascript like so:
window.onscroll = function (e) {
// called when the window is scrolled.
}
You may want to have a look at: Detect if user is scrolling for jquery options.

Rearranging js to accommodate more flexibility

How can I make this js affect only the child elements of the original hovered element without giving all of the individual .g_scroll or .left/.right tags id's?
function loopRight(){
$('.g_scroll').stop().animate({scrollLeft:'+=20'}, 'fast', 'linear', loopRight);
}
function loopLeft(){
$('.g_scroll').stop().animate({scrollLeft:'-=20'}, 'fast', 'linear', loopLeft);
}
function stop(){
$('.g_scroll').stop();
}
$('#right').hover(function () {
loopRight().children();
},function () {
stop();
});
$('#left').hover(function () {
loopLeft();
},function () {
stop();
});
JSfiddle for (confusing, but necessary) html structure: https://jsfiddle.net/6rbn18cL/
To demonstrate how it would have to be renamed: https://jsfiddle.net/z9u3azqy/
So here, I "merged" both arrow handlers.
Then, there is a calculation needed to determine the "scroll" speed, based on width to be scrolled, which may no always be 100% of the element's width.
This script allows you to easily determine a speed for 100% scrolling.
Then, it calculates the speed if there is already a distance scrolled.
$(document).ready(function(){
function moveit(arrow){
// Adjust you delay here
var delay = 2000; // delay to scroll 100%
var animationDelay;
var slider = arrow.siblings(".g_scroll");
var distance = slider.width();
var scrolled = slider.scrollLeft()+1; // +1 is to avoid infinity in the math below
if(arrow.hasClass("scroller_l")){
distance = -distance;
animationDelay = -distance * (-distance/delay)*(-distance+scrolled);
}else{
animationDelay = distance * (distance/delay)*(distance-scrolled);
}
slider.stop().animate({scrollLeft:distance}, animationDelay, 'linear');
}
function stop(arrow){
arrow.siblings(".g_scroll").stop();
}
$('.scroller_l, .scroller_r').hover(function(){
moveit($(this));
},function() {
stop($(this));
});
}); // ready
CodePen
--First answer--
First, you can't use the same id more than once.
So I removed id="left" and id="right" from your HTML.
Now the trick is to pass which arrow is hovered to your functions, using $(this).
And find the .g_scroll element which is a sibling of it.
$(document).ready(function(){
function loopRight(arrow){
arrow.siblings(".g_scroll").stop().animate({scrollLeft:'+=20'}, 'fast', 'linear', loopRight);
}
function loopLeft(arrow){
arrow.siblings(".g_scroll").stop().animate({scrollLeft:'-=20'}, 'fast', 'linear', loopLeft);
}
function stop(arrow){
arrow.siblings(".g_scroll").stop();
}
$('.scroller_r').hover(function(){
loopRight($(this));
},function() {
stop($(this));
});
$('.scroller_l').hover(function(){
loopLeft($(this));
},function() {
stop($(this));
});
});
CodePen
You can pass the event object and find the proper container from there.
$('.scroller_l').hover(loopRight, stop);
$('.scroller_r').hover(loopLeft, stop);
This is done automatically if you pass functions as parameters like the above.
To find the scrolling container dynamically for each instance you can use the classes to find the container relative to the current target:
var el = $(ev.currentTarget),
parent = el.closest('.country_holder'),
container = parent.find('.g_scroll');
See a working example here.
At this point you can ask yourself whether loopRight and loopLeft can be combined in one function. The only difference is the '-=20' and '+=20'.
With polymorphism you can refactor this even further.

Photoswipe 4.0: Initiate 'swipe to next' programatically

SITUATION
I have been trying to trigger the 'slide to next picture' animation when the NEXT button is clicked, but i have not found a solution for this.
There is an ongoing discussion about this on GitHub, but it is only about adding the option for a slide animation, not about how to actually do it with PS as it is right now.
There was an option for it in 3.0 but as 4.0 is a complete rewrite it does not work anymore.
QUESTION
Instead of just 'jumping' to the next/prev picture when an arrow is clicked, i need the 'slide transition' that is also used when swiping/dragging the image.
There is no option to trigger that, so how can i manually trigger this effect with JS?
PhotoSwipe Slide Transitions
So, I added slide transitions to Photoswipe, and it's working nicely without disturbing native behavior.
http://codepen.io/mjau-mjau/full/XbqBbp/
http://codepen.io/mjau-mjau/pen/XbqBbp
The only limitation is that transition will not be applied between seams in loop mode (for example when looping from last slide to slide 1). In examples I have used jQuery.
Essentially, it works by simply adding a CSS transition class to the .pswp__container on demand, but we need to add some javascript events to prevent the transition from interfering with Swipe, and only if mouseUsed. We also add a patch so the transition does not get added between loop seams.
1. Add the below to your CSS
It will be applied on-demand from javascript when required.
.pswp__container_transition {
-webkit-transition: -webkit-transform 333ms cubic-bezier(0.4, 0, 0.22, 1);
transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1);
}
2. Add javascript events to assist in assigning the transition class
This can go anywhere, but must be triggered after jQuery is loaded.
var mouseUsed = false;
$('body').on('mousedown', '.pswp__scroll-wrap', function(event) {
// On mousedown, temporarily remove the transition class in preparation for swipe. $(this).children('.pswp__container_transition').removeClass('pswp__container_transition');
}).on('mousedown', '.pswp__button--arrow--left, .pswp__button--arrow--right', function(event) {
// Exlude navigation arrows from the above event.
event.stopPropagation();
}).on('mousemove.detect', function(event) {
// Detect mouseUsed before as early as possible to feed PhotoSwipe
mouseUsed = true;
$('body').off('mousemove.detect');
});
3. Add beforeChange listener to re-assign transition class on photoswipe init
The below needs to be added in your PhotoSwipe init logic.
// Create your photoswipe gallery element as usual
gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
// Transition Manager function (triggers only on mouseUsed)
function transitionManager() {
// Create var to store slide index
var currentSlide = options.index;
// Listen for photoswipe change event to re-apply transition class
gallery.listen('beforeChange', function() {
// Only apply transition class if difference between last and next slide is < 2
// If difference > 1, it means we are at the loop seam.
var transition = Math.abs(gallery.getCurrentIndex()-currentSlide) < 2;
// Apply transition class depending on above
$('.pswp__container').toggleClass('pswp__container_transition', transition);
// Update currentSlide
currentSlide = gallery.getCurrentIndex();
});
}
// Only apply transition manager functionality if mouse
if(mouseUsed) {
transitionManager();
} else {
gallery.listen('mouseUsed', function(){
mouseUsed = true;
transitionManager();
});
}
// init your gallery per usual
gallery.init();
You can just use a css transition:
.pswp__container{
transition:.3s ease-in-out all;
}
This might not be ideal for performance on mobile, but I just add this transition in a media query and allow users to use the swipe functionality on smaller screens.
I finally bit the bullet and spent some time making this work as nobody seemed to have a solution for that, not here neither on GitHub or anywhere else.
SOLUTION
I used the fact that a click on the arrow jumps to the next item and triggers the loading of the next image and sets the whole slide state to represent the correct situation in an instant.
So i just added custom buttons which would initiate a slide transition and then triggered a click on the original buttons (which i hid via CSS) which would update the slide state to represent the situation i created visually.
Added NEW next and prev arrows
Hid the ORIGINAL next and prev arrows via css
Animated the slide myself when the NEW next or prev arrows were clicked
Then triggered the click on the ORIGINAL next or prev arrows programmatically
So here is the code:
HTML
// THE NEW BUTTONS
<button class="NEW-button-left" title="Previous (arrow left)">PREV</button>
<button class="NEW-button-right" title="Next (arrow right)">NEXT</button>
// added right before this original lines of the example code
<button class="pswp__button pswp__button--arrow--left ...
CSS
pswp__button--arrow--left,
pswp__button--arrow--right {
display: none;
}
NEW-button-left,
NEW-button-right {
/* whatever you fancy */
}
JAVASCRIPT (helper functions)
var tx = 0; // current translation
var tdir = 0;
var slidepseactive = false;
// helper function to get current translate3d positions
// as per https://stackoverflow.com/a/7982594/826194
function getTransform(el) {
var results = $(el).css('-webkit-transform').match(/matrix(?:(3d)\(-{0,1}\d+(?:, -{0,1}\d+)*(?:, (-{0,1}\d+))(?:, (-{0,1}\d+))(?:, (-{0,1}\d+)), -{0,1}\d+\)|\(-{0,1}\d+(?:, -{0,1}\d+)*(?:, (-{0,1}\d+))(?:, (-{0,1}\d+))\))/)
if(!results) return [0, 0, 0];
if(results[1] == '3d') return results.slice(2,5);
results.push(0);
return results.slice(5, 8);
}
// set the translate x position of an element
function translate3dX($e, x) {
$e.css({
// TODO: depending on the browser we need one of those, for now just chrome
//'-webkit-transform': 'translate3d(' +String(x) + 'px, 0px, 0px)'
//, '-moz-transform': 'translate3d(' +String(x) + 'px, 0px, 0px)'
'transform': 'translate3d(' +String(x) + 'px, 0px, 0px)'
});
};
JAVASCRIPT (main)
// will slide to the left or to the right
function slidePS(direction) {
if (slidepseactive) // prevent interruptions
return;
tdir = -1;
if (direction == "left") {
tdir = 1;
}
// get the current slides transition position
var t = getTransform(".pswp__container");
tx = parseInt(t[0]);
// reset anim counter (you can use any property as anim counter)
$(".pswp__container").css("text-indent", "0px");
slidepseactive = true;
$(".pswp__container").animate(
{textIndent: 100},{
step: function (now, fx) {
// here 8.7 is the no. of pixels we move per animation step %
// so in this case we slide a total of 870px, depends on your setup
// you might want to use a percentage value, in this case it was
// a popup thats why it is a a fixed value per step
translate3dX($(this), tx + Math.round(8.7 * now * tdir));
},
duration: '300ms',
done: function () {
// now that we finished sliding trigger the original buttons so
// that the photoswipe state reflects the new situation
slidepseactive = false;
if (tdir == -1)
$(".pswp__button--arrow--right").trigger("click");
else
$(".pswp__button--arrow--left").trigger("click");
}
},
'linear');
}
// now activate our buttons
$(function(){
$(".NEW-button-left").click(function(){
slidePS("left");
});
$(".NEW-button-right").click(function(){
slidePS("right");
});
});
I used info from those SE answers:
jQuery animate a -webkit-transform
Get translate3d values of a div?
The PhotoSwipe can do this by itself when you use swipe gesture. So why not to use the internal code instead of something that doesn't work well?
With my solution everything works well, the arrow clicks, the cursor keys and even the loop back at the end and it doesn't break anything.
Simply edit the photoswipe.js file and replace the goTo function with this code:
goTo: function(index) {
var itemsDiff;
if (index == _currentItemIndex + 1) { //Next
itemsDiff = 1;
}
else { //Prev
itemsDiff = -1;
}
var itemChanged;
if(!_mainScrollAnimating) {
_currZoomedItemIndex = _currentItemIndex;
}
var nextCircle;
_currentItemIndex += itemsDiff;
if(_currentItemIndex < 0) {
_currentItemIndex = _options.loop ? _getNumItems()-1 : 0;
nextCircle = true;
} else if(_currentItemIndex >= _getNumItems()) {
_currentItemIndex = _options.loop ? 0 : _getNumItems()-1;
nextCircle = true;
}
if(!nextCircle || _options.loop) {
_indexDiff += itemsDiff;
_currPositionIndex -= itemsDiff;
itemChanged = true;
}
var animateToX = _slideSize.x * _currPositionIndex;
var animateToDist = Math.abs( animateToX - _mainScrollPos.x );
var finishAnimDuration = 333;
if(_currZoomedItemIndex === _currentItemIndex) {
itemChanged = false;
}
_mainScrollAnimating = true;
_shout('mainScrollAnimStart');
_animateProp('mainScroll', _mainScrollPos.x, animateToX, finishAnimDuration, framework.easing.cubic.out,
_moveMainScroll,
function() {
_stopAllAnimations();
_mainScrollAnimating = false;
_currZoomedItemIndex = -1;
if(itemChanged || _currZoomedItemIndex !== _currentItemIndex) {
self.updateCurrItem();
}
_shout('mainScrollAnimComplete');
}
);
if(itemChanged) {
self.updateCurrItem(true);
}
return itemChanged;
},

Fixing the animation properties

I am doing some research at the moment into creating a new maths game for primary school children where divs from 0-9 appear at random inside a container.
A question is given at the beginning. Something like, multiples of 20. The user will then have to click on the correct ones, and they will then be counted at the end and a score will be given.
I have just changed the speed in which the divs appear so that they appear for longer and more than one at a time to make the game easier for younger children.
I used "fadeIn" like so..
$('#' + id).animate({
top: newY,
left: newX
}, 'slow', function() {}).fadeIn(2000);
}
My problem is that now when I shoot the correct or incorrect number the animation is very glitchy and I cannot figure out why.
Fiddle: http://jsfiddle.net/cFKHq/6/ (See version 5 to see what it was like before)
Inside startplay(), control the concurrency when calling scramble() , I do it with a global var named window.cont, so I replaced your following call:
play = setInterval(scramble, 1800);
for this one:
play = setInterval(function() {
if (window.cont){
window.cont = false;
scramble();
}
}, 1000);
The var window.cont needs to be set globally at the start of your code, like so:
var miss = 0;
var hit = 0;
var target = $("#target");
window.cont = true;
So with window.cont you now can control that animations are executed one after another, without overlapping, like so:
$('#'+id).css({
top: newY,
left: newX
}).fadeIn(2000, function() {
setTimeout(function() {
$('#' + id).slideUp('fast');
window.cont = true;
}, 1500);
});
See working demo

smooth auto scroll by using javascript

I am trying to implement some code on my web page to auto-scroll after loading the page. I used a Javascript function to perform auto-scrolling, and I called my function when the page loads, but the page is still not scrolling smoothly! Is there any way to auto scroll my page smoothly?
Here is my Javascript function:
function pageScroll() {
window.scrollBy(0,50); // horizontal and vertical scroll increments
scrolldelay = setTimeout('pageScroll()',100); // scrolls every 100 milliseconds
}
It's not smooth because you've got the scroll incrementing by 50 every 100 milliseconds.
change this and the amount you are scrolling by to a smaller number to have the function run with the illusion of being much more 'smooth'.
turn down the speed amount to make this faster or slower.
function pageScroll() {
window.scrollBy(0,1);
scrolldelay = setTimeout(pageScroll,10);
}
will appear to be much smoother, try it ;)
Try to use jQuery, and this code:
$(document).ready(function(){
$('body,html').animate({scrollTop: 156}, 800);
});
156 - position scroll to (px), from top of page.
800 - scroll duration (ms)
You might want to look at the source code for the jQuery ScrollTo plug-in, which scrolls smoothly. Or maybe even just use the plug-in instead of rolling you own function.
Smoothly running animations depends on the clients machine. No matter how fairly you code, you will never be satisfied the way your animation runs on a 128 MB Ram system.
Here is how you can scroll using jQuery:
$(document).scrollTop("50");
You might also want to try out AutoScroll Plugin.
you can use jfunc function to do this.
use jFunc_ScrollPageDown and jFunc_ScrollPageUp function.
http://jfunc.com/jFunc-Functions.aspx.
Since you've tagged the question as 'jquery', why don't you try something like .animate()? This particular jquery function is designed to smoothly animate all sorts of properties, including numeric CSS properties as well as scroll position.
the numbers are hardcoded, but the idea is to move item by item (and header is 52px) and when is down, go back
let elem = document.querySelector(".spfxBirthdaysSpSearch_c7d8290b ");
let lastScrollValue = 0
let double_lastScrollValue = 0
let scrollOptions = { top: 79, left: 0, behavior: 'smooth' }
let l = console.log.bind(console)
let intScroll = window.setInterval(function() {
double_lastScrollValue = lastScrollValue //last
lastScrollValue = elem.scrollTop // after a scroll, this is current
if (double_lastScrollValue > 0 && double_lastScrollValue == lastScrollValue){
elem.scrollBy({ top: elem.scrollHeight * -1, left: 0, behavior: 'smooth' });
} else {
if (elem.scrollTop == 0){
elem.scrollBy({ top: 52, left: 0, behavior: 'smooth' });
} else {
elem.scrollBy(scrollOptions);
}
}
}, 1000);
Here's another take on this, using requestAnimationFrame. It gives you control of the scroll time, and supports easing functions. It's pretty robust, but fair warning: there's no way for the user to interrupt the scroll.
// Easing function takes an number in range [0...1]
// and returns an eased number in that same range.
// See https://easings.net/ for more.
function easeInOutSine(x) { return -(Math.cos(Math.PI * x) - 1) / 2; }
// Simply scrolls the element from the top to the bottom.
// `elem` is the element to scroll
// `time` is the time in milliseconds to take.
// `easing` is an optional easing function.
function scrollToBottom(elem, time, easing)
{
var startTime = null;
var startScroll = elem.scrollTop;
// You can change the following to scroll to a different position.
var targetScroll = elem.scrollHeight - elem.clientHeight;
var scrollDist = targetScroll - startScroll;
easing = easing || (x => x);
function scrollFunc(t)
{
if (startTime === null) startTime = t;
var frac = (t - startTime) / time;
if (frac > 1) frac = 1;
elem.scrollTop = startScroll + Math.ceil(scrollDist * easing(frac));
if (frac < 0.99999)
requestAnimationFrame(scrollFunc);
}
requestAnimationFrame(scrollFunc);
}
// Do the scroll
scrollToBottom(document.getElementById("data"), 10000, easeInOutSine);

Categories

Resources