This seamless marquee style kind of jitters each scroll - javascript

I am using this code to create a scroll-up marquee text but after 7000 miliseconds it jitters and thus doesn't offer a good look for the text inside.
Have you any idea where I can fix it ?
<script language="javascript">
jQuery(function() {
var marquee = jQuery("#marquee");
marquee.css({"overflow": "hidden", "height": "100%"});
marquee.wrapInner("<span>");
marquee.find("span").css({ "height": "50%", "display": "inline-block", "text-align":"left" });
marquee.append(marquee.find("span").clone());
marquee.wrapInner("<div>");
marquee.find("div").css("height", "200%");
var reset = function() {
jQuery(this).css("margin-top", "0%");
jQuery(this).animate({ "margin-top": "-100%" }, 7000, 'linear', reset);
};
reset.call(marquee.find("div"));
});
BTW, you can it like this
<div id="marquee">text</div>
[UPDATE]Sorry Kamal for having to edit this post to add the jsfiddle to reproduce the problem [I always know I can do this :-D]
http://jsfiddle.net/xRcwH/

why not use the <marquee> tags?
<marquee behavior="scroll" direction="up">Your upward scrolling text goes here</marquee>

I've already answered the same question at <marquee> html tag usage/replacment.
There is CSS3 WebKit specific -webkit-marquee-, that you can read about at http://davidwalsh.name/webkit-marquee-css. However, for whatever reason, even the native CSS marquee implementation is glitchy.
The same applies to the <marquee> element. It is well supported by the browsers, though, apart from being deprecated, it is glitchy.
I've been looking for the most efficient and cross-browser supported marquee implementation. None of the above fit the bill. The common approach is to use timer (or jQuery animate implementation) to adjust the CSS margin property of the element. This is what your script does. Unfortunately, this operation is very resource intensive. It requires applying new CSS every few milliseconds resulting in recalculation of the whole layout.
I came up with implementation that utilises CSS3 transitions for browsers that support it and otherwise animate the scrollLeft property of the containing element. It is an experimental implementation, though it works well with IE7+. The code is available at https://github.com/gajus/marquee (demo https://dev.anuary.com/60244f3a-b8b2-5678-bce5-f7e8742f0c69/).

Related

Rapahel js : dynamic positioning and animations

I'm new to js and web dev in general, and i want to add animations to my website using raphael js.
Here is the code I use for a basic slide-in animation:
paper.text('1000','25%','this is a\ntest').animate({x: '50'}, 1000, 'linear');
(test it here)
It works fine when i put fixed values for the x parameter. However, when i use dynamic positioning, the animation doesn't occur, and the text waits for the duration of the animation before positioning itself. At least the final positioning is what i'm looking for:
paper.text('300%','25%','this is a\ntest').animate({x: '50%'}, 1000, 'linear');
Why isn't it working ?
Is there a way around ?
I'm not sure raph can work like that (animating to a percentage), I may be wrong though.
Is this the sort of thing you are after ?
paper.text( paper.width * 3,'25%','this is a\ntest').animate({x: paper.width / 2}, 1000, 'linear');

Couple Issues with jQuery Animation

I am using jQuery Animate to create a Pan-Zoom effect on an image. Overall it works well with two exceptions.
First it starts the animation and seems to hit a wall then continue to zoom in. Is there a way to prevent this and make the motion one smooth motion.
Second is the motion is a bit jerky, especially at the end. Is there a way to smooth this out? I am using easing on the page if I should try adding some form of easing. (This was testing in Firefox and Chrome and both are jerky.)
Here is a jsFiddle of the animation.
Notes: I am using jQuery 1.8.3 and I could use CSS but sticking with jQuery for cross browser compatibility. (Majority of my users are on IE unfortunately.)
HTML
<div style="width:1140px; height:500px; overflow:hidden; text-align:center;">
<img id="pan-zoom" style="width:900px; height:600px; position:relative; top:-80px; left:0;" alt="European Bee-eaters" src="http://upload.wikimedia.org/wikipedia/commons/9/96/Pair_of_Merops_apiaster_feeding.jpg" />
</div>
JS
$(window).load(function() {
$('#pan-zoom').animate({
width: '2141px',
height: '1428px',
top: '-200px',
left: '-405px'
}, 8000, function() {
// Fade In Hidden DIV
});
});
If you speed up the animation, it will appear to be smoother. The slower the animation, the more noticeable any roughness of it will be.
Changing the easing to linear seemed to help as well. The slowness at end of the default easing (swing) makes the roughness of the animation very noticeable. The code below uses linear easing and is sped up twice as fast (as well changing the outer width to 900px, as #loxxy suggested), and it looked reasonably good.
$(window).load(function() {
$('#pan-zoom').animate({
width: '2141px',
height: '1428px',
top: '-200px',
left: '-405px'
}, 4000, 'linear', function() {
// Fade In Hidden DIV
});
});
Getting a large animation to be both smooth and slow may only be possible with hardware support like WebGL. Short of that, choose between smooth and slow, whichever is more important.
Change
<div style="width:1140px; ...
To
<div style="width:900px; ...
The idea is, that before zooming in, the image is scaled to fit the parent width, which is the effect you want to remove.
Updated fidde.
EDIT : Or position absolute, as commented.
Both problems would be resolved if you used the scale function of the css transform property. I think (it has been a long time since i've user jquery and did not follow up) that the jquery.animate function is not compatible with these. You should use a plugin or write one that does if you want to keep using jquery.
In your fiddle you use the left, top, width and height properties. This will be especially jerky in webkit.
Jquery transform plugin top google result:
http://ricostacruz.com/jquery.transit/

How can I "snap" scroll to the nearest predefined position?

I have a website that is essentially four divs - each of which is set to the height of the window so that the total document is four times the height of the window.
The idea is that a click on a div advances the scroll by one "window height" - which works fine, like this:
// on click event
if(cur_frame<number_slides){
scrolling = true;
$('html,body').animate({scrollTop:window_height*cur_frame},function(){
scrolling=false;
});
}
After the user scrolls the page manually, however, I'd like to "snap" the position to the nearest multiple of the window height - so a given div is once again centered on the screen. I tried using a timeout, figuring that a small delay would keep it from triggering a thousand times a second...
// on scroll event
clearTimeout(scroll_timer);
if(!scrolling) scroll_timer = setTimeout(function(){
if(cur_scroll!=window_height*(cur_frame-1)) {
scrolling = true;
$('html,body').stop().animate({scrollTop:window_height*(cur_frame-1)},function(){
scrolling = false;
});
}
},100); //20? 400? 1000?
...but couldn't strike a balance between the script fighting the user over scroll position, or a seriously long delay that defeats the "snapping" effect.
Any suggestions how this might be achieved?
There is a CSS spec for this, and it is well supported with native rendering and very nice touch behavior except on Chrome: http://caniuse.com/#feat=css-snappoints
For the laggard browser, there's a polypill: https://github.com/ckrack/scrollsnap-polyfill
See also How to emulate CSS Scroll Snap Points in Chrome?
The jquery scrollsnap plugin for this supports down to IE9.
What you're looking for is called "Scroll Snap".
<script src="demo/foundation/javascripts/jquery.js"></script>
<script src="src/jquery.event.special.js"></script>
<script src="src/jquery.easing.min.js"></script>
<script src="src/jquery.scrollsnap.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$(document).scrollsnap({
snaps: '.snap',
proximity: 50
});
});
</script>
What about using a simple scrollTo? Plain Javascript and CSS used, no frameworks or libraries.
Here are two examples, one for vertical scrolling and the other for horizontal scrolling:
Vertical: https://jsfiddle.net/x9z5tpye/
Horizontal: https://jsfiddle.net/bwsyn6q4/
If you want to consider a cross-browser javascript re-implementation of the native CSS Scroll Snap spec, as already answered here: How to emulate CSS Scroll Snap Points in Chrome?, you can use
this library:
The main reason to use this instead of the native css solution is that it works in all modern browsers and has a customizable configuration to allow custom timing in transitions and scrolling detection.
The library re-implements the css snapping feature using vanilla javascript easing functions, and works using the values of the container element's scrollTop/scrollLeft properties and the scroll Event Listener
Here is an example that shows how to use it:
import createScrollSnap from 'scroll-snap'
const element = document.getElementById('container')
const { bind, unbind } = createScrollSnap(element, {
snapDestinationX: '0%',
snapDestinationY: '90%',
timeout: 100,
duration: 300,
threshold: 0.2,
snapStop: false,
easing: easeInOutQuad,
}, () => console.log('snapped'))
// remove the listener
// unbind();
// re-instantiate the listener
// bind();
You could do this with javascript or for a slightly simpler and older solution you can use page anchors.
If you change your document.location.hash to an anchor that exists in the page then the browser will scroll to it.
So in your HTML put some anchors in the page:
<a name="anchor1" id="anchor1"></a>
then in your js put:
document.location.hash = "anchor1";

Why are style assignments performed immediately after creation not animated?

Opening this fiddle on Webkit will show what I'm talking about.
How can I specify an element's style when it is first specified, and then its final state?
It should be possible to specify a single step animation fully this way (without having to start using #keyframes) but it seems like there is a lot of implementation specific strangeness I must deal with at this point. Note how in Firefox no animation is performed...
Seems to be the same issue as described here: CSS3 transitions to dynamically created elements
so
$("#one").on('click',function(){
var word = $("<div style='opacity: 0; height:0'>word</div>");
$('body').prepend(word);
window.getComputedStyle(word[0]).getPropertyValue("top");
word.css({height: 100, opacity: 1});
});
also works in this case: http://jsfiddle.net/wWnnH/3/
Alternatively, you can use jQuery.animate()
word.animate({height: 100, opacity: 1}, 5000);
Will work without the CSS, and on both webkit and mozilla. Although this defeats the purpose of trying to use CSS3 I guess.

jQuery example (in jsfiddle) working in firefox but not in IE8, 7

Why this example not working in IE http://jsfiddle.net/8RZVt/
I'm getting this error in IE8.
Message: Invalid argument.
Line: 156
Char: 295
Code: 0
URI: http://code.jquery.com/jquery-1.4.4.min.js
According to jQuery, this is because, as stated on the animate documentation page:
All animated properties should be a
single numeric value (except as noted
below); properties that are
non-numeric cannot be animated using
basic jQuery functionality....
So, in fact, in Firefox you are using undefined behavior. The correct thing to do would be to animate on backgroundPositionX, however Firefox does not support this.
There is, however, a jQuery plugin that does what you want:
http://plugins.jquery.com/project/backgroundPosition-Effect
Update
On closer inspection, the plugin does not support += or -= formats.
I hacked it into this example:
http://jsfiddle.net/CxqSs/ (See new example at bottom.)
Could definitely use some cleanup, and should probably be added to that plug-in, but it works in both browsers and doesn't rely on undefined behavior.
BTW, I don't know if it's worth noting, but if you leave this animation running a long time, it will eventually overflow the value and break. This could be overcome by animating the full length of the background image and then resetting the offset to 0px in the callback before the next animate. This would also avoid needing the += format.
Also,
It should be noted that speed: 1, step: 1 and speed: 50, step: 50 are equivalent.
The reason they look different speeds is because
There is more overhead in a speed of 1 (which is really a millisecond duration) because animate gets called more often.
The default easing is "swing", meaning that the animation speeds up and slows down slightly throughout it's course, meaning that the overall speed is affected a bit. You should change the easing to "linear" for your scrolling case:
var animate = function() {
element.animate({
...
}, speed, "linear", animate);
};
This means that you could use the backgroundPosition-Effect plugin, without the '+=', by setting your step to 2247 (the width of the image), like I stated above.
And that finally brings us to... wait for it...
http://jsfiddle.net/zyQj3/20/
Cross-platform, non-kludgy, non-overflowing, correctly easing, extra parameter-lacking, solution.
The script fails at this point because you are passing an invalid CSS value:
element.animate({
backgroundPosition: animStep + " 0px" /* evaluates to "+=50px 0px" */
}, speed, animate);
OK here we go again :D
http://jsfiddle.net/c7rKV/1/
Again identical to original however again just animating backgroundPositionX when in IE.
Apologies on not actually looking at FF/Chrome last time.
Additionally: this of course is not very graceful and Adam Prax is absolutely correct on what the problem is. I just wanted to post a solution to it.
If you check the source code of jQuery, you will see it uses this regexp to parse the parameter (which in your case is +=50px 0px). So it will see it as += (increase) 50 (to fifty) px 0px (unit, append after the number). When trying to read the current value, jQuery uses parseFloat, which just grabs the number at the start of the string. So it works perfectly, even if a multi-dimensional property is probably not what the jQuery programmers had in mind.
Except that IE8 does not support getting the current value of background-position. There is background-position-x and background-position-y but no background-position. Duh. So your best bet is checking the browser type, and animating either background-position or background-position-x depending on that: http://jsfiddle.net/22UWW/
(There is actually a jQuery bug report about this, with a more elegant solution.)

Categories

Resources