How to clear interval inside a function calling itself javascript - javascript

I need to clear interval of function in this example
$.fn.bounce = function(options) {
var settings = $.extend({
speed: 10
}, options);
return $(this).each(function() {
var $this = $(this),
$parent = $this.parent(),
height = $parent.height(),
width = $parent.width(),
top = Math.floor(Math.random() * (height / 2)) + height / 4,
left = Math.floor(Math.random() * (width / 2)) + width / 4,
vectorX = settings.speed * (Math.random() > 0.5 ? 1 : -1),
vectorY = settings.speed * (Math.random() > 0.5 ? 1 : -1);
// place initialy in a random location
$this.css({
'top': top,
'left': left
}).data('vector', {
'x': vectorX,
'y': vectorY
});
var move = function($e) {
var offset = $e.offset(),
width = $e.width(),
height = $e.height(),
vector = $e.data('vector'),
$parent = $e.parent();
if (offset.left <= 0 && vector.x < 0) {
vector.x = -1 * vector.x;
}
if ((offset.left + width) >= $parent.width()) {
vector.x = -1 * vector.x;
}
if (offset.top <= 0 && vector.y < 0) {
vector.y = -1 * vector.y;
}
if ((offset.top + height) >= $parent.height()) {
vector.y = -1 * vector.y;
}
$e.css({
'top': offset.top + vector.y + 'px',
'left': offset.left + vector.x + 'px'
}).data('vector', {
'x': vector.x,
'y': vector.y
});
setTimeout(function() {
move($e);
}, 50);
};
move($this);
});
};
$(function() {
$('#wrapper li').bounce({
'speed': 7
});
});
So whenever I need I start the animating circle and when I don't want I can stop. So in the above code you can see move($this); is getting called in interval what I need to stop or clear the interval so the circle stop animating. and when again I need I can just click the button and it again start animation.

I divided your code in bounce function into three section:
One for initialization where the element took their start positions.
Another for the logic of animation (with the start and stop added)
The last one is for the movement (the same function move but insetead of define it inside each (not good because it will get redifined for every element), I defined it outside the each).
The code contain tons of comments. If something is still unclear post a comment bellow.
$.fn.bounce = function(options) {
var settings = $.extend({
speed: 10
}, options);
// Keep a reference to this to use when we are inside bounded functions (where this is something different)
var that = this;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////// LOGIC FOR INITIALIZATION ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// function init to initialize the elements.
function init(){
$(that).each(function() {
var $this = $(this),
$parent = $this.parent(),
height = $parent.height(),
width = $parent.width(),
top = Math.floor(Math.random() * (height / 2)) + height / 4,
left = Math.floor(Math.random() * (width / 2)) + width / 4,
vectorX = settings.speed * (Math.random() > 0.5 ? 1 : -1),
vectorY = settings.speed * (Math.random() > 0.5 ? 1 : -1);
// place initialy in a random location
$this.css({
'top': top,
'left': left
}).data('vector', {
'x': vectorX,
'y': vectorY
});
});
}
// call it right away (initialize) before starting anything else
init();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////// LOGIC FOR ANIMATION ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// the boolean that will stop the animation
var keepGoing = false;
// If the selector for the start button is specified
if(settings.start){
// attach animate to its click event listener
$(settings.start).on("click", animate);
}
else // no button is provided then start automatically
animate();
// If the selector for the stop button is specified
if(settings.stop){
// attach stop to its click event listener
$(settings.stop).on("click", stop);
}
// the function that will start the animation
function animate(){
// If we are not already animating
if(!keepGoing){
keepGoing = true;
// call move on all the elements to start the magic.
// we use 'that' instead of 'this' here because 'this' is the button that have been clicked (see the event listener above=.
$(that).each(function() {
move($(this));
});
}
}
// the function that will stop the animation ...
function stop(){
// ... by simply set keepGoing to false
keepGoing = false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////// LOGIC FOR MOVEMENT ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// the move function responsible for moving the elements
function move($e) {
var offset = $e.offset(),
width = $e.width(),
height = $e.height(),
vector = $e.data('vector'),
$parent = $e.parent();
if (offset.left <= 0 && vector.x < 0) {
vector.x = -1 * vector.x;
}
if ((offset.left + width) >= $parent.width()) {
vector.x = -1 * vector.x;
}
if (offset.top <= 0 && vector.y < 0) {
vector.y = -1 * vector.y;
}
if ((offset.top + height) >= $parent.height()) {
vector.y = -1 * vector.y;
}
$e.css({
'top': offset.top + vector.y + 'px',
'left': offset.left + vector.x + 'px'
}).data('vector', {
'x': vector.x,
'y': vector.y
});
// if keep going, ... you know, keep going.
if(keepGoing){
setTimeout(function() {
move($e);
}, 50);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
// the options can have the 'start' and 'stop' selector optionally.
$(function() {
$('#wrapper li').bounce({
'speed': 7,
'start': '#startAnimation', // selector of the element that when clicked the animation will start. If not provided the animation will start automatically
'stop' : '#stopAnimation' // selector of the element that when clicked the animation will stop (pause). If not provided the animation will go for ever
});
});
body, * {
padding: 0 !important; margin: 0: }
#wrapper {
width:500px;
height: 500px;
border:
1px solid red; }
li {
position: absolute;
width: 60px;
height: 60px;
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
border-radius: 30px;
background-color:#0FF;
line-height: 60px;
text-align:center;
cursor:pointer; }
button{
width: 100px;
height: 30px;
}
<script src='http://code.jquery.com/jquery-3.1.1.min.js'></script>
<ul id="wrapper">
<button id="startAnimation">Start</button>
<button id="stopAnimation">Stop</button>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>

I think you want to be using setInterval for this problem. You can use clearInterval on the instance of setInterval you created to make it stop.
Why I think you should be using setInterval instead of setTimeout? Well because setInterval is meant for running functions in a certain time interval (which is what you want to do). Where as setTimeout is meant to delay a function call.
// sample code
var counter = 0;
var example = setInterval(function(){
console.log(counter);
if (counter == 10) {
console.log("I'm out");
clearInterval(example);
}
counter++;
}, 300);

You can assign timeout function to a variable and use clearTimeout method. Like below:
var timer = setTimeout(function() {
move($e);
}, 50);
clearTimeout(timer);

Related

Variable keeps growing even if condition is not met

I'm trying to animate a div on scroll. The point is that the div's width must grow until it reaches 80vw and stop. This does happen, but my variable keeps on growing (it's being logged to the console) even if the >=outerWidth*0.8 condition isn't met. Thanks to this, whenever I get to 80vw and scroll up and then down, the width becomes Xvw.
$(window).on('scroll',function(){
var scrollTop = $(this).scrollTop();
var outerHeight = $(this).outerHeight();
var outerWidth = $(this).outerWidth();
var scrollBottom = scrollTop + outerHeight;
var scrollTop = $(this).scrollTop();
console.log( growNaranja );
if (scrollTop > lastScrollTop){ // scroll down
if( naranjaWidth <= (outerWidth*0.8) ){
growNaranja = (naranja.outerWidth()*100) / outerWidth;
growNaranja = growNaranja+(scrollTop*0.05);
$('.grow.naranja').css( 'width', growNaranja + 'vw' );
}
} else { // scroll up
if( naranjaWidth >= (outerWidth*0.1) ){
growNaranja = (naranja.outerWidth()*100) / outerWidth;
$('.grow.naranja').css( 'width', growNaranja + 'vw' );
growNaranja = growNaranja - ((lastScrollTop-scrollTop)*0.05);
$('.grow.naranja').css( 'width', growNaranja + 'vw' );
}
}
lastScrollTop = scrollTop;
});
You can see a working example here.
Revisited this one, it was bugging me. First, the code was all spaghetti. Second, there was really function duplication. You had a function for scrolling up and one for scrolling down, and you were using the last scrollTop to calculate the next scroll step. Instead, I've made a single scale function that gets called regardless. The value of the percentage scrolled is multiplied by the step factor, and that is added to the ORIGINAL element width. By doing this, I'm not worried about where I was just prior to the scroll, only where I am now.
So I made the scaleWidthEl an object constructor, and simply wrapped the naranja div in that. The actual code to create it is the first three lines, and could be reduced to:
var scaleNaranja = new ScaleWidthEl($('.grow.naranja'), 0.8);
The rest is self-contained, allowing changes to be made without affecting anything else.
var maxElScale = 0.8;
var naranja = $('.grow.naranja');
var scaleNaranja = new ScaleWidthEl(naranja, maxElScale);
/***
* The rest of this is a black-box function, walled away from the main code
* It's a personal peeve of mine that code gets garbled otherwise.
***/
function ScaleWidthEl(el, maxScale) {
// I don't need a minScale, as I use the initial width for that
this.el = el;
this.vwConversion = (100 / document.documentElement.clientWidth);
this.startingWidth = el.outerWidth();
this.maxScale = maxScale;
this.max = $(window).outerWidth() * this.maxScale;
this.step = (this.max - this.startingWidth) / $(window).outerHeight();
// for the sake of clarity, store a reference to `this` for
// any nested functions.
var that = this;
/**
* function scaleEl
* handle the actual scaling of the element.
* Using a given step, we will simply add that
* to the element's current width, then update the CSS
* width property of the element.
**/
this.scaleEl = function() {
// First, calculate the percentage of vertical scroll
var winheight = $(window).height();
var docheight = $(document).height();
var scrollTop = $(window).scrollTop();
var trackLength = docheight - winheight;
// gets percentage scrolled (ie: 80 NaN if tracklength == 0)
var pctScrolled = Math.floor(scrollTop / trackLength * 100);
// console.log(pctScrolled + '% scrolled')
// Now, using the scrolled percentage, scale the div
var tempWidth = this.startingWidth * this.vwConversion;
tempWidth += pctScrolled * this.step;
// I want to fix the max of the scale
if (tempWidth > (this.maxScale * 100)) {
tempWidth = this.maxScale * 100;
}
this.el.css('width', tempWidth + 'vw');
};
$(window).on("scroll", function() {
that.scaleEl();
}).on("resize", function() {
/**
* In the case of a resize, we should
* recalculate min, max and step.
**/
that.min = $(window).outerWidth() * that.minScale;
that.max = $(window).outerWidth() * that.maxScale;
that.step = (that.max - that.min) / $(window).outerHeight();
})
}
body {
height: 10000px;
}
.grow {
position: fixed;
height: 100vh;
top: 0;
left: 0;
}
.grow.gris {
width: 35vw;
z-index: 2;
background: silver;
}
.grow.naranja {
width: 10vw;
z-index: 1;
background: orange;
}
<script src="https://code.jquery.com/jquery-3.1.1.min.js" crossorigin="anonymous"></script>
<div class="grow naranja"></div>
<!-- .naranja -->

Passing properties object to jQuery animate function

I have this piece of code:
var delta = _window.width() / 30, // resize hexagons by delta px
window_height = _window.height(); // .box-1/window height
$('.hexagon').each(function () { // get animated boxes
var $this = $(this),
width_1 = $this.width(),
height_1 = $this.height(),
multi = 0, // adjust resize to scroll speed (depends on delta)
ratio = 1.167; // to calculate height
// animation properties
var enlarge_obj = {
width: function() {return width_1 += (delta * multi)},
height: function() {return width_1 * ratio}
},
shrink_obj = {
width: function() {return width_1 -= (delta * multi)},
height: function() {return width_1 * ratio}
};
....
function scrollHandler() {
...
$this.animate(enlarge_obj, 0, 'linear');
...
$this.animate(shrink_obj, 0, 'linear');
}
}
I want to pass enlarge_obj and shrink_obj to jQuery animate function.
But it doesn't work.
If I write code like this:
$this.animate({width: width_1 += (delta * multi), height: width_1 * ratio},0,'linear');
it works fine.
What am I doing wrong? Thx.

CSS Animated type blocked/blocking Hero Image with JS effect attached

Hey UX Designer learning code here, please forgive my ignorance and crappy code.
I have a CSS animated type overlayed a Hero Image which also has a JS effect applied to it.
Originally I couldn't get both images to render. The type would render but you couldn't see the hero image behind it, or the hero image would appear but you couldn't see the type.
At first I thought it was some class applied to the type that was creating an opaque background over the hero image but I eliminated that possibility by selectively commenting out stuff.
Then I realized that I needed to put the type div inside the Hero Image div. I had done this before but I tried again and it worked! But the reason it worked is because I had just selectively commented out the Javascript effect that was being applied to the Hero Image.
So the problem must be the tilt-effect (the javascript effect) class. I however have very little knowledge of Javascript so I am unsure of what is causing this problem.
I'm guessing it has something to do with the way javascript is manipulating stuff on the page? I've had a similar problem before when I had a page with a footer and a responsive image gallery driven by JS. The html footer would render and then the JS gallery would re-position all the objects on the page. So I'm thinking something similar is happening here, maybe?
Here's a JSFiddle for the code: http://jsfiddle.net/thedonquixotic/8vv7t1as/2/
The Tilt FX stuff is the second section of code in the JS part, I've labeled it for ease of finding.
Relevant part of the HTML is as follows:
<!--Hero image with tilt effect-->
<div class="hero">
<div class="hero__imgwrap">
<!--<div class="grid__item">
<a class="link link--kumya" href="About.html"><span data-letters="David French">David French</span></a>
</div>-->
<img class="hero__img tilt-effect" data-tilt-options='{ "opacity" : 0.3, "extraImgs" : 3, "movement": { "perspective" : 1700, "translateX" : -7, "translateY" : -7, "rotateX" : -7, "rotateY" : -7 } }' src="https://cdn.tutsplus.com/craft/uploads/2013/11/14-snowflakes-lay-paper-copy.jpg" alt="Welcome!" />
</div>
</div>
<!--Hero image with tilt effect-->
Also here is the Javascript:
/**
* tiltfx.js
* http://www.codrops.com
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2015, Codrops
* http://www.codrops.com
*/
;(function(window) {
'use strict';
/**
* **************************************************************************
* utils
* **************************************************************************
*/
// from https://gist.github.com/desandro/1866474
var lastTime = 0;
var prefixes = 'webkit moz ms o'.split(' ');
// get unprefixed rAF and cAF, if present
var requestAnimationFrame = window.requestAnimationFrame;
var cancelAnimationFrame = window.cancelAnimationFrame;
// loop through vendor prefixes and get prefixed rAF and cAF
var prefix;
for( var i = 0; i < prefixes.length; i++ ) {
if ( requestAnimationFrame && cancelAnimationFrame ) {
break;
}
prefix = prefixes[i];
requestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ];
cancelAnimationFrame = cancelAnimationFrame || window[ prefix + 'CancelAnimationFrame' ] ||
window[ prefix + 'CancelRequestAnimationFrame' ];
}
// fallback to setTimeout and clearTimeout if either request/cancel is not supported
if ( !requestAnimationFrame || !cancelAnimationFrame ) {
requestAnimationFrame = function( callback, element ) {
var currTime = new Date().getTime();
var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
var id = window.setTimeout( function() {
callback( currTime + timeToCall );
}, timeToCall );
lastTime = currTime + timeToCall;
return id;
};
cancelAnimationFrame = function( id ) {
window.clearTimeout( id );
};
}
function extend( a, b ) {
for( var key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
// from http://www.quirksmode.org/js/events_properties.html#position
function getMousePos(e) {
var posx = 0;
var posy = 0;
if (!e) var e = window.event;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
return {
x : posx,
y : posy
}
}
// from http://www.sberry.me/articles/javascript-event-throttling-debouncing
function throttle(fn, delay) {
var allowSample = true;
return function(e) {
if (allowSample) {
allowSample = false;
setTimeout(function() { allowSample = true; }, delay);
fn(e);
}
};
}
/***************************************************************************/
/**
* TiltFx fn
*/
function TiltFx(el, options) {
this.el = el;
this.options = extend( {}, this.options );
extend( this.options, options );
this._init();
this._initEvents();
}
/**
* TiltFx options.
*/
TiltFx.prototype.options = {
// number of extra image elements (div with background-image) to add to the DOM - min:1, max:5 (for a higher number, it's recommended to remove the transitions of .tilt__front in the stylesheet.
extraImgs : 2,
// the opacity value for all the image elements.
opacity : 0.7,
// by default the first layer does not move.
bgfixed : true,
// image element's movement configuration
movement : {
perspective : 1000, // perspective value
translateX : -10, // a relative movement of -10px to 10px on the x-axis (setting a negative value reverses the direction)
translateY : -10, // a relative movement of -10px to 10px on the y-axis
translateZ : 20, // a relative movement of -20px to 20px on the z-axis (perspective value must be set). Also, this specific translation is done when the mouse moves vertically.
rotateX : 2, // a relative rotation of -2deg to 2deg on the x-axis (perspective value must be set)
rotateY : 2, // a relative rotation of -2deg to 2deg on the y-axis (perspective value must be set)
rotateZ : 0 // z-axis rotation; by default there's no rotation on the z-axis (perspective value must be set)
}
}
/**
* Initialize: build the necessary structure for the image elements and replace it with the HTML img element.
*/
TiltFx.prototype._init = function() {
this.tiltWrapper = document.createElement('div');
this.tiltWrapper.className = 'tilt';
// main image element.
this.tiltImgBack = document.createElement('div');
this.tiltImgBack.className = 'tilt__back';
this.tiltImgBack.style.backgroundImage = 'url(' + this.el.src + ')';
this.tiltWrapper.appendChild(this.tiltImgBack);
// image elements limit.
if( this.options.extraImgs < 1 ) {
this.options.extraImgs = 1;
}
else if( this.options.extraImgs > 5 ) {
this.options.extraImgs = 5;
}
if( !this.options.movement.perspective ) {
this.options.movement.perspective = 0;
}
// add the extra image elements.
this.imgElems = [];
for(var i = 0; i < this.options.extraImgs; ++i) {
var el = document.createElement('div');
el.className = 'tilt__front';
el.style.backgroundImage = 'url(' + this.el.src + ')';
el.style.opacity = this.options.opacity;
this.tiltWrapper.appendChild(el);
this.imgElems.push(el);
}
if( !this.options.bgfixed ) {
this.imgElems.push(this.tiltImgBack);
++this.options.extraImgs;
}
// add it to the DOM and remove original img element.
this.el.parentNode.insertBefore(this.tiltWrapper, this.el);
this.el.parentNode.removeChild(this.el);
// tiltWrapper properties: width/height/left/top
this.view = { width : this.tiltWrapper.offsetWidth, height : this.tiltWrapper.offsetHeight };
};
/**
* Initialize the events on the main wrapper.
*/
TiltFx.prototype._initEvents = function() {
var self = this,
moveOpts = self.options.movement;
// mousemove event..
this.tiltWrapper.addEventListener('mousemove', function(ev) {
requestAnimationFrame(function() {
// mouse position relative to the document.
var mousepos = getMousePos(ev),
// document scrolls.
docScrolls = {left : document.body.scrollLeft + document.documentElement.scrollLeft, top : document.body.scrollTop + document.documentElement.scrollTop},
bounds = self.tiltWrapper.getBoundingClientRect(),
// mouse position relative to the main element (tiltWrapper).
relmousepos = {
x : mousepos.x - bounds.left - docScrolls.left,
y : mousepos.y - bounds.top - docScrolls.top
};
// configure the movement for each image element.
for(var i = 0, len = self.imgElems.length; i < len; ++i) {
var el = self.imgElems[i],
rotX = moveOpts.rotateX ? 2 * ((i+1)*moveOpts.rotateX/self.options.extraImgs) / self.view.height * relmousepos.y - ((i+1)*moveOpts.rotateX/self.options.extraImgs) : 0,
rotY = moveOpts.rotateY ? 2 * ((i+1)*moveOpts.rotateY/self.options.extraImgs) / self.view.width * relmousepos.x - ((i+1)*moveOpts.rotateY/self.options.extraImgs) : 0,
rotZ = moveOpts.rotateZ ? 2 * ((i+1)*moveOpts.rotateZ/self.options.extraImgs) / self.view.width * relmousepos.x - ((i+1)*moveOpts.rotateZ/self.options.extraImgs) : 0,
transX = moveOpts.translateX ? 2 * ((i+1)*moveOpts.translateX/self.options.extraImgs) / self.view.width * relmousepos.x - ((i+1)*moveOpts.translateX/self.options.extraImgs) : 0,
transY = moveOpts.translateY ? 2 * ((i+1)*moveOpts.translateY/self.options.extraImgs) / self.view.height * relmousepos.y - ((i+1)*moveOpts.translateY/self.options.extraImgs) : 0,
transZ = moveOpts.translateZ ? 2 * ((i+1)*moveOpts.translateZ/self.options.extraImgs) / self.view.height * relmousepos.y - ((i+1)*moveOpts.translateZ/self.options.extraImgs) : 0;
el.style.WebkitTransform = 'perspective(' + moveOpts.perspective + 'px) translate3d(' + transX + 'px,' + transY + 'px,' + transZ + 'px) rotate3d(1,0,0,' + rotX + 'deg) rotate3d(0,1,0,' + rotY + 'deg) rotate3d(0,0,1,' + rotZ + 'deg)';
el.style.transform = 'perspective(' + moveOpts.perspective + 'px) translate3d(' + transX + 'px,' + transY + 'px,' + transZ + 'px) rotate3d(1,0,0,' + rotX + 'deg) rotate3d(0,1,0,' + rotY + 'deg) rotate3d(0,0,1,' + rotZ + 'deg)';
}
});
});
// reset all when mouse leaves the main wrapper.
/*this.tiltWrapper.addEventListener('mouseleave', function(ev) {
setTimeout(function() {
for(var i = 0, len = self.imgElems.length; i < len; ++i) {
var el = self.imgElems[i];
el.style.WebkitTransform = 'perspective(' + moveOpts.perspective + 'px) translate3d(0,0,0) rotate3d(1,1,1,0deg)';
el.style.transform = 'perspective(' + moveOpts.perspective + 'px) translate3d(0,0,0) rotate3d(1,1,1,0deg)';
}
}, 60);
});*/
// window resize
window.addEventListener('resize', throttle(function(ev) {
// recalculate tiltWrapper properties: width/height/left/top
self.view = { width : self.tiltWrapper.offsetWidth, height : self.tiltWrapper.offsetHeight };
}, 50));
};
function init() {
// search for imgs with the class "tilt-effect"
[].slice.call(document.querySelectorAll('img.tilt-effect')).forEach(function(img) {
new TiltFx(img, JSON.parse(img.getAttribute('data-tilt-options')));
});
}
init();
window.TiltFx = TiltFx;
})(window);
I hope I understand it well so I created some modify
CSS:
.grid__item {
position: absolute;
left: 50%;
z-index: 1;
display: flex;
justify-content: center;
top: 50%;
}
.link--kumya {
font-family: "Syncopate",sans-serif;
font-size: 6.5em;
overflow: hidden;
color: #242424;
position: relative;
left: -50%;
top: -70px;
text-align: center;
}
After you will change this part the type and animated background appear

Dragging elements on a scaled div

I've tried using jquery's built in draggable and I've tried using custom drag functions with no avail. Both have their respected issues and I will try to highlight both of them.
Basically, I am trying to allow the dragging of an element that is on a scaled div container. The following methods work okay on a scaled element that is less than around 2. But if you go any higher than that, we see some issues.
Any help would be appreciated. Thank you for your time.
HTML
<div id="container">
<div id="dragme">Hi</div>
</div>
Method 1 (Jquery draggable function)
I've tried the jquery draggable function as you can see in this jsfiddle example.
The problems I found in this example are the following:
Biggest concern: The droppable container does not change when it is scaled up. So if the element is being dragged over part of the scaled container that isn't a part of it's original size, it will fail.
When you click to drag a div, it teleports a little bit away from the mouse and is not a seamless drag.
JS
var percent = 2.5;
$("#dragme").draggable({
zIndex: 3000,
appendTo: 'body',
helper: function (e, ui) {
var draggable_element = $(this),
width = draggable_element.css('width'),
height = draggable_element.css('height'),
text = draggable_element.text(),
fontsize = draggable_element.css('font-size'),
textalign = draggable_element.css('font-size');
return $('<div id="' + draggable_element.id + '" name="' + draggable_element.attr('name') + '" class="text">' + text + '</div>').css({
'position': 'absolute',
'text-align': textalign,
'background-color': "red",
'font-size': fontsize,
'line-height': height,
'width': width,
'height': height,
'transform': 'scale(' + percent + ')',
'-moz-transform': 'scale(' + percent + ')',
'-webkit-transform': 'scale(' + percent + ')',
'-ms-transform': 'scale(' + percent + ')'
});
},
start: function (e, ui) {
$(this).hide();
},
stop: function (e, ui) {
$(this).show();
}
});
$("#container").droppable({
drop: function (event, ui) {
var formBg = $(this),
x = ui.offset.left,
y = ui.offset.top,
drag_type = ui.draggable.attr('id');
var element_top = (y - formBg.offset().top - $(ui.draggable).height() * (percent - 1) / 2) / percent,
element_left = (x - formBg.offset().left - $(ui.draggable).width() * (percent - 1) / 2) / percent;
$(ui.draggable).css({
'top': element_top,
'left': element_left
});
}
});
Method 2 - Custom drag function
I've tried using a custom drag function but it unusable after around a 2 scale.
jsfiddle on a scale(2) - Looks like the draggable div is having a seizure.
jsfiddle on a scale(2.5) - The draggable div flys away when you try to drag it.
JS
(function ($) {
$.fn.drags = function (opt) {
opt = $.extend({
handle: "",
cursor: "move"
}, opt);
if (opt.handle === "") {
var $el = this;
} else {
var $parent = this;
var $el = this.find(opt.handle);
}
return $el.css('cursor', opt.cursor).on("mousedown", function (e) {
if (opt.handle === "") {
var $drag = $(this).addClass('draggable');
} else {
$(this).addClass('active-handle')
var $drag = $parent.addClass('draggable');
}
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top + drg_h - e.pageY,
pos_x = $drag.offset().left + drg_w - e.pageX;
follow = function (e) {
$drag.offset({
top: e.pageY + pos_y - drg_h,
left: e.pageX + pos_x - drg_w
})
};
$(window).on("mousemove", follow).on("mouseup", function () {
$drag.removeClass('draggable');
$(window).off("mousemove", follow);
});
e.preventDefault(); // disable selection
}).on("mouseup", function () {
if (opt.handle === "") {
$(this).removeClass('draggable');
} else {
$(this).removeClass('active-handle');
$parent.removeClass('draggable');
}
});
}
})(jQuery);
$("#dragme").drags({}, function (e) {});
Here are a few of my findings to make sure dragging on a scaled container works for method one. The only caveat is to make sure you have var percent as the scaled percentage declared before any of these actions happen.
First, use this code at the top of your javascript. This wil help making sure that the droppable area works with a sacled container.
$.ui.ddmanager.prepareOffsets = function( t, event ) { var i, j, m = $.ui.ddmanager.droppables[ t.options.scope ] || [], type = event ? event.type : null, list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); droppablesLoop: for ( i = 0; i < m.length; i++ ) { if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { continue; } for ( j = 0; j < list.length; j++ ) { if ( list[ j ] === m[ i ].element[ 0 ] ) { m[ i ].proportions().height = 0; continue droppablesLoop; }  } m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; if ( !m[ i ].visible ) { continue; } if ( type === "mousedown" ) { m[ i ]._activate.call( m[ i ], event ); } m[ i ].offset = m[ i ].element.offset(); m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth * percent, height: m[ i ].element[ 0 ].offsetHeight * percent }); } };
Here are a few functions that are necessary to fix the drag so it works on a scaled container.
function dragFix(event, ui) { var changeLeft = ui.position.left - ui.originalPosition.left, newLeft = ui.originalPosition.left + changeLeft / percent, changeTop = ui.position.top - ui.originalPosition.top, newTop = ui.originalPosition.top + changeTop / percent; ui.position.left = newLeft; ui.position.top = newTop; }
function startFix(event, ui) { ui.position.left = 0; ui.position.top = 0;  var element = $(this); }
You will want this if you want to enable the element to be resizable on a scaled container.
function resizeFix(event, ui) { var changeWidth = ui.size.width - ui.originalSize.width, newWidth = ui.originalSize.width + changeWidth / percent, changeHeight = ui.size.height - ui.originalSize.height, newHeight = ui.originalSize.height + changeHeight / percent;  ui.size.width = newWidth; ui.size.height = newHeight; }
To make an element draggable, I use the following function.
$("ELEMENT").resizable({ minWidth: - ($(this).width()) * 10, minHeight: - ($(this).height()) * 10, resize: resizeFix, start: startFix });
$("ELEMENT").draggable({ cursor: "move", start: startFix, drag: dragFix }); }
A similar problem is mentioned here: jquery - css "transform:scale" affects '.offset()' of jquery
It seems the problem arises from the fact that jQuery fails to return exact size for scaled elements and therefore failing setting right offset values to the element.
To solve this, he is suggesting first setting scale to 1 and setting offset and then again resetting scale value.
But this alone does not solve the problem here. Since mouse position is taken while it is scaled, position values should also be divided by scale value.
Here is an edited version of code:
var scl = 2.5;
var
drg_h = $drag.outerHeight(),
drg_w = $drag.outerWidth(),
pos_y = $drag.offset().top/scl + drg_h - e.pageY/scl,
pos_x = $drag.offset().left/scl + drg_w - e.pageX/scl;
follow = function(e) {
var size = {
top:e.pageY/scl + pos_y - drg_h+scl*2,
left:e.pageX/scl + pos_x - drg_w+scl*2
};
$drag.parent().css("transform","scale(1)");
$drag.offset(size);
$drag.parent().css("transform","scale("+scl+")");
};
Note: I only replaced scale value for transform tag, since I am using chrome. You can also replace all instances or instead you can use a different class with 1 scale value.
JSFiddle is also here.
Here is an example of simple drag with scaling, however, in prue dom.
<style>
#dragme {
position:absolute;
border:1px solid red;
background:pink;
left:10px;
top:20px;
width:100px;
height:200px;
}
#container {
transform: scale(2,2) translate(100px,100px);
position:relative;
border:1px solid green;
background:grey;
width:200px;
height:300px;
}
</style>
<body>
<div id="container">
<div id="dragme">Hi</div>
</div>
<script>
var dragme=document.getElementById("dragme");
var container=document.getElementById("container");
dragme.onmousedown=function Drag(e){
this.ini_X = this.offsetLeft-e.clientX/2;
this.ini_Y = this.offsetTop-e.clientY/2;
container.onmousemove = move;
container.onmouseup = release;
return false;
}
function move(e){
e.target.style.left = e.clientX/2 + e.target.ini_X + 'px';
e.target.style.top = e.clientY/2 + e.target.ini_Y + 'px';
}
function release(){
container.onmousemove=container.onmouseup=null;
}
</script>
</body>

ScrollTo with animation

how can i add an easing/animation/slowly moving to this function?
At the moment it just jumps.
Now it should move to the "anchor" with an animation.
<script type='text/javascript'>
setTimeout("window.scrollBy(0,270);",3000);
</script>
also possible with plain javascript using request animation frame..
// first add raf shim
// http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
// main function
function scrollToY(scrollTargetY, speed, easing) {
// scrollTargetY: the target scrollY property of the window
// speed: time in pixels per second
// easing: easing equation to use
var scrollY = window.scrollY,
scrollTargetY = scrollTargetY || 0,
speed = speed || 2000,
easing = easing || 'easeOutSine',
currentTime = 0;
// min time .1, max time .8 seconds
var time = Math.max(.1, Math.min(Math.abs(scrollY - scrollTargetY) / speed, .8));
// easing equations from https://github.com/danro/easing-js/blob/master/easing.js
var PI_D2 = Math.PI / 2,
easingEquations = {
easeOutSine: function (pos) {
return Math.sin(pos * (Math.PI / 2));
},
easeInOutSine: function (pos) {
return (-0.5 * (Math.cos(Math.PI * pos) - 1));
},
easeInOutQuint: function (pos) {
if ((pos /= 0.5) < 1) {
return 0.5 * Math.pow(pos, 5);
}
return 0.5 * (Math.pow((pos - 2), 5) + 2);
}
};
// add animation loop
function tick() {
currentTime += 1 / 60;
var p = currentTime / time;
var t = easingEquations[easing](p);
if (p < 1) {
requestAnimFrame(tick);
window.scrollTo(0, scrollY + ((scrollTargetY - scrollY) * t));
} else {
console.log('scroll done');
window.scrollTo(0, scrollTargetY);
}
}
// call it once to get started
tick();
}
// scroll it!
scrollToY(0, 1500, 'easeInOutQuint');
For anyone viewing this question in 2019: this can now be done natively by using
window.scrollBy({
top: 0,
left: 270,
behavior: 'smooth'
});
This works in all major browsers except edge and safari. See https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollBy#Examples
Adapted from this answer:
function scrollBy(distance, duration) {
var initialY = document.body.scrollTop;
var y = initialY + distance;
var baseY = (initialY + y) * 0.5;
var difference = initialY - baseY;
var startTime = performance.now();
function step() {
var normalizedTime = (performance.now() - startTime) / duration;
if (normalizedTime > 1) normalizedTime = 1;
window.scrollTo(0, baseY + difference * Math.cos(normalizedTime * Math.PI));
if (normalizedTime < 1) window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
}
This should allow you to smoothly scroll by the specified distance.
This will Work, Assume you need to Smooth-scrolls to the top of the page.
const scrollToTop = () => {
const c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, c - c / 8);
}
};
Another example with jQuery, uses the easing plugin for some nice effects:
http://tympanus.net/codrops/2010/06/02/smooth-vertical-or-horizontal-page-scrolling-with-jquery/
got it myself. because of wordpress and the jquery.noConflict Mode i hade to modify the code:
<script type="text/javascript">
(function($){
$(document).ready(function(){
setTimeout(function() {
$('body').scrollTo( '300px', 2500 );
}, 3000);
});
}(jQuery));
</script>
thanks for everybody!!!
When using jQuery, you could easily use the .animate function.
Here's an example on how it should work.
Using jQuery makes this much easier, perhaps with the scrollto plugin. http://flesler.blogspot.se/2007/10/jqueryscrollto.html
Consider a solution such:
<script type='text/javascript' src='js/jquery.1.7.2.min.js'></script>
<script type='text/javascript' src='js/jquery.scrollTo-min.js'></script>
<script type='text/javascript' src='js/jquery.easing.1.3.js'></script><!-- only for other easings than swing or linear -->
<script type='text/javascript'>
$(document).ready(function(){
setTimeout(function() {
$('html,body').scrollTo( {top:'30%', left:'0px'}, 800, {easing:'easeInBounce'} );
}, 3000);
});
</script>
Of course you need to dl the scripts.
See http://jsfiddle.net/7bFAF/2/ for a working example
We can make it simpler by using the css property scroll-behavior
html {
scroll-behavior: smooth;
}

Categories

Resources