I have the following function that ties into a bunch of different plugin settings, allowing you to configure the handles, speed, and angles for rotating objects. Everything runs crystal clear and really nice in IE9, but firefox is jerky.
// 1. FUNCTION ROTATE ANIMATIONS IN
function rotate_on(degree, index){
clearTimeout(rotateofftimer); /* CLEAR ANIMATION OUT TIMER */
// A. APPLY THE CROSS-BROWSER CSS FOR ROTATIONS
if((ievers==6)||(ievers==7)||(ievers==8)){ if(ievers==8){ /* IE 8 CODE */ current_obj.css({/* IE8 */'-ms-filter':'"progid:DXImageTransform.Microsoft.BasicImage(rotation='+degree+')"',/* IE<8 */'filter':'progid:DXImageTransform.Microsoft.BasicImage(rotation='+degree+')'});} else { /* IE 6/7 CODE */ };
} else { /* NON IE */
current_obj.css({/* W3C CSS3 standard */'transform':'translateX(0)rotate('+degree+'deg)','transform-origin':OS.rotate_handle_on_set[index],/* Firefox */'-moz-transform':'translateX(0)rotate('+degree+'deg)','-moz-transform-origin':OS.rotate_handle_on_set[index],/* Chrome, Safari, Mobile, Etc. */'-webkit-transform':'translateX(0)rotate('+degree+'deg)','-webkit-transform-origin':OS.rotate_handle_on_set[index],/* Opera */'-o-transform':'translateX(0)rotate('+degree+'deg)','-o-transform-origin':OS.rotate_handle_on_set[index],/* IE>=9 */'-ms-transform':'rotate('+degree+'deg)','-ms-transform':'translateX(0)rotate('+degree+'deg)','-ms-transform-origin':OS.rotate_handle_on_set[index]});};
// B. TEST FOR REPEAT ROTATIONS - IF VALUES ARE THE SAME, REPEAT ROTATIONS
if(OS.rotate_on_set[index]==OS.rotate_off_set[index]){
// SAVE THE ENDING VALUE TO PICKUP ON NEXT PLAY (IF LOOPING)
OS.rotate_on_set[index]=degree;OS.rotate_off_set[index]=degree; degree++;
}else{ if(degree<OS.rotate_off_set[index]){ degree++ };};
// C. TRIGGER THE FUNCTION IN A TIMER, BASED ON USER SPEED
rotateontimer = setTimeout(function(){rotate_on(degree, index)},OS.rotate_speed_on_set[index]);};
The strange thing is, when I turn the speed down so that the animation is really slow, it's basically jerking through 1 frame at a time in Firefox, but IE9 seems to know how to translate that into a smooth/slow animation. Could it be something to do with the timers?
Thanks!
This just seems to be the way Firefox is. I have the same problem of choppy JS animations and ONLY when viewed with Firefox. Internet Explorer 9 (in standard mode plus compatibility modes "IE7" and "IE8") and Chrome both display smooth animations under all circumstances.
Trust me, we're not the only ones with this problem and to day no clear solution exists.
Related
I have created a web interface where the user can drag and drop SVG elements on screen. I am struggling with the performance of moving the SVGs via touch events on iPhone iOS using the webkit engine.
Everything is fine on desktop browsers and on Android phones that I could get hold of, but iOS on iPhones shows very bad performance (seems fine on iOS on one iPad that I could get hold of, but it sometimes leaves some traces of the SVG after moving).
There seems to be a delay before the touchstart event kicks in after touching the device and a delay before the touchend event is triggered after releasing the touch: An audio sample (already loaded) that is supposed to play after picking up or dropping the element plays with a delay of ~1.5 seconds. The touchmove event seems to be handled smoothly though - no delay with moving the SVG (after touchstart has ended).
I have already checked iOS Delay between touchstart and touchmove? - but the site that's linked to doesn't help me. I fail to get the scroll event on any element (window, document, svgElement) - and even if I did, I wouldn't know how this could help me.
I assumed the the issue might be related to the size of the base64 encoded background image that the SVGs are using, but reduzing that size even dramatically didn't help.
I read about some 300-350ms delay that iOS might have if there's no "fast tap" mode set, but a) the delay between touching/releasing the screen and playing the audio is longer than 350ms (rather 1.5 seconds) and b) playing with the touch-action CSS property did not help. (Eliminate 300ms delay on click events in mobile Safari)
I am really not sure if I am doing anything wrong (very well possible!) or if the webkit engine on (iPhone) iOS is simply so bad (compared to e.g. Blink on Android that runs flawlessly) that it cannot handle to render/move SVGs? Testing this is particularly iffy, because Browserstack doesn't issue TouchEvents properly and I never succeded to hook up the single physical iOS device that I have (a 2015 iPod Touch) to my Linux machine for remote debugging (while it's very simple for Android on Chromium). I'd really be grateful for hints!
An SVG roughly follows the following pattern (some attributes like viewBox, stroke-width etc. omitted):
<svg>
<defs><pattern id="SOME_ID"><img href="data:SOME_BASE64_ENCODED_IMAGE" /></pattern></defs>
<path fill="url(#SOME_ID)" d="SOME_SIMPLE_PATH"></path>
<path d="SOME_OTHER_SIMPLE_PATH"></path>
</svg>
The SVGs can be moved by MouseEvent or TouchEvent using the following logic:
// this.svgElement is the DOM element within the class
this.svgElement.addEventListener('touchstart', this.handleMoveStarted, false);
this.svgElement.addEventListener('mousedown', this.handleMoveStarted, false);
// Keep track of start position and add move/end listeners
handleMoveStarted(event) {
event.preventDefault();
event.stopPropagation();
if (event.type === 'touchstart') {
this.moveInitialX = event.touches[0].clientX;
this.moveInitialY = event.touches[0].clientY;
this.svgElement.addEventListener('touchmove', this.handleMoved, false);
this.svgElement.addEventListener('touchend', this.handleMoveEnded, false);
}
else {
// Same principle for event.clientX/Y and MouseEvent
}
// Callback to play audio here
}
// Compute delta position and update
handleMoved(event) {
event.preventDefault();
event.stopPropagation();
let deltaX = 0;
let deltaY = 0;
if (event.type === 'touchmove') {
deltaX = this.moveInitialX - event.touches[0].clientX;
deltaY = this.moveInitialY - event.touches[0].clientY;
this.moveInitialX = event.touches[0].clientX;
this.moveInitialY = event.touches[0].clientY;
}
else {
// Same principle for event.clientX/Y and MouseEvent
}
this.svgElement.style.left = `${parseFloat(this.svgElement.style.left) - deltaX}px`;
this.svgElement.style.top = `${parseFloat(this.svgElement.style.top) - deltaY}px`;
}
// Used to remove listeners on tochenend/mouseup
handleMoveEnded(event) {
event.preventDefault();
event.stopPropagation();
this.svgElement.removeEventListener('mousemove', this.handleMoved);
this.svgElement.removeEventListener('touchmove', this.handleMoved);
this.svgElement.removeEventListener('mouseup', this.handleMoveEnded);
this.svgElement.removeEventListener('touchend', this.handleMoveEnded);
// Callback to play audio here
}
I have investigated this issue some more, and it turns out that it's not the SVG dragging that's causing the huge delay in iOS, but it's the callbacks that follow. It seems that iOS has quite some trouble with playing plain HTML5 audio in a timely (real-time) fashion and I'll have to revert to some other solution (HTML 5 audio .play() delay on mobile).
there is a very interesting situation I am facing right now that I would like to ask about, I have a web site which is called from any device (Tablet, smarthphone, Laptop, etc.) and I have a problem only with Firefox on the smarthphones, here is the scenario:
There is a page that has a text box at the end, when the text box is focused the keyboard comes out (I mean in the smarthphones) and takes part of the screen, for the user to see the textbox and what is he writing I execute a javascript function in the onfocus event of the textbox that scrolls to the end of the page, I have tried with two different aproaches having the same result:
function scrollToMe(tBox) {
var element = document.getElementById(tBox);
setTimeout(function () { element.scrollIntoView(true); }, 600);
return false;}
Here tBox is the textbox, I just scroll down to him after 600 miliseconds.
function scrollInPage() {
var element = document.getElementById('theDIV');
setTimeout(function () { element.scrollTop = element.scrollHeight; }, 600);
return false;}
Here I apply scroll to the general div.
Both functions work perfect in all mobile browsers I have tested except in Firefox, the div mentioned above has nothing special, just has the overflow:scroll; property in the css, here is how it looks the page after the scroll down function in all other mobile browsers I have tested:
The page moves to the end, this works in Chrome, Opera Mini, Safari, Dolphin, Default Android Browser, Web Browser, Chrome Dev and Ghostery.
But this is what Mozilla does after the scroll function is executed:
It just resizes the div, only Firefox in the Smarthphones does it and after more than 8 hours trying to solve it and searching in Internet any clue on how to do it I would like to ask if someone has an idea of what could be the issue.
I am testing with a galaxy Note 4, a Galaxy S4 and Galaxy S3 Mini (Firefox 48 for all of them), it does the same in all of them.
Many thanks in advance for any answer and comment.
I have added smooth scrolling to a site of mine using this piece of JavaScript when clicking on hash links.
$('a[href*=#]')
.click(onAnchorClick);
function onAnchorClick(event)
{
return ! scrollTo(this.hash);
}
function scrollTo(target)
{
var e = $(target);
var y = e.exists() ? e.offset().top : 0;
if(y == 0 && target != '#top')
return false;
if(Math.max($('html').scrollTop(), $('body').scrollTop()) != y)
$('html,body')
.animate({scrollTop: y}, 500, function() { location.hash = target; } );
else
location.hash = target;
return true;
}
$.fn.exists = function()
{
return this.length > 0 ? this : false;
}
Works fantastic in desktop browsers and looks to work fine on at least iOS devices as well. However, on my WinPhone 8 device it was garbage. Scrolling was a mess and didn't even end up where it should. So I decided to not enable it there through an if( ! /Windows Phone 8\.0/.test(navigator.userAgent)).
Now it works well, and seems the browser on the WinPhone actually is smooth scrolling by default, which is great.
But it is of course a bit dumb to have a smooth scroll script active if the browser already does this by default. Is there a way I can detect if a browser already has a smooth scrolling feature enabled?
I managed to solve it this way:
<style>
body {
scroll-behavior: smooth;
}
</style>
<script>
if(getComputedStyle(document.body).scrollBehavior === 'smooth'){
console.log('This browser supports scrollBehavior smooth');
}
</script>
Yes and no. Unfortunately there are no standards for these types of things. However there are work arounds, one of which you are already doing: browser sniffing.
Basically, that's about as advanced as this kind of detection goes because some browsers don't yet even support smooth scrolling officially or without experimental developments (like Chromium). And standards won't be set unless the majority are on the same page. Not only that but it also comes down to GPU hardware abilities as some devices and computers struggle with smooth scrolling and animations. So technically speaking, even if a browser did support smooth scrolling, who's to say the device or desktop running it can render fast enough to even display the effect. That's another bottle neck.
I believe someday in the future there will be more of a need for browser feature specifications such as this to better improve user interactions, but until that day you're doing it right.
Several years later, there now is a CSS property in the Working Draft for this:
scroll-behavior 🎉
So instead of the Javascript in my original question, or similar, we can just do this:
html {
scroll-behavior: smooth;
}
#media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
}
Right now, it seems to work for all browsers except IE and Edge, and since this is just a nice-to-have feature that makes things look a bit nicer... Yeah, I don't really care about IE or Edge. 😛👍
I'm having a problem with animating transform rotateX and rotateY. I'm using the GSAP jQuery plugin.
Basically executing this:
$(element).animate({transform: "rotateX(-180deg)"});
has the same effect as executing:
$(element).animate({transform: "rotateX(180deg)"});
I do have perspective set up, in case you were wondering.
Is there a special way I have to define negative values or is this a bug?
UPDATE: I have found a property "shortRotationX" and "shortRotationY" mentioned here: http://codepen.io/GreenSock/pen/ydIgf
However this seems to be a temporary workaround. I would like to know what the correct way is to animate rotations with jQuery + GSAP.
Thank you guys!
Kyryll
This was answered in the GreenSock forums at http://forums.greensock.com/topic/9099-cannot-animate-rotate-negative-jquery-gsap/#entry36552
A rotation of 180 is identical to a rotation of -180 in terms of the browser's transform matrix (use getComputedStyle() to see for yourself), so there's no way to truly discern the difference unless you leverage GSAP's native transform properties like "rotationX", "rotation", "rotationY", etc. When you do that, GSAP can track everything properly for you. Plus it's more optimized for speed. So:
//OLD
$(element).animate({transform: "rotateX(-180deg)"});
//NEW
$(element).animate({rotationX:-180});
//or use GSAP's native API:
TweenLite.to("#element", 0.4, {rotationX:-180});
Also, "shortRotationX" is deprecated ever since we came out with DirectionalRotationPlugin which uses a more intuitive syntax that can also be used to specify clockwise or counter-clockwise movement:
//OLD
{shortRotationX:-180}
//NEW
{rotationX:"-180_short"}
//and to specify a clockwise direction:
{rotationX:"-180_cw"}
//or counter-clockwise:
{rotationX:"-180_ccw"}
It should have the same effect. Turning object 180 degrees will be displayed in same way how it will be displayed if you turn it -180 degrees.
I made you a simple example, if it clears you out:
Fiddle here (just HTML & CSS) so you can see that it has the same effect.
div {
width:200px;
}
#rotate1 {
height:100px;
background-color:yellow;
/* Rotate div */
transform:rotate(180deg);
-ms-transform:rotate(180deg); /* IE 9 */
-webkit-transform:rotate(180deg); /* Opera, Chrome, and Safari */
}
#rotate2 {
height:100px;
background-color:red;
/* Rotate div */
transform:rotate(-180deg);
-ms-transform:rotate(-180deg); /* IE 9 */
-webkit-transform:rotate(-180deg); /* Opera, Chrome, and Safari */
}
I'm working on a site using css3 animations, it works perfectly in Safari and Firefox, but for some reason performance in Chrome is awful. (around 15 fps)
http://triple-tested.com/animations/
The animations are quite simple, basically a few large circles layered up. I've also added a few png sprite animations using javascript.
I know about hardware acceleration but I don't think that is the problem, it seems to be some quirk that is unique to Chrome. The css animations perform 'OK' alone but once I add the sprites performance drops considerably.
$.fn.spriteme = function(options) {
var settings = $.extend({ framerate: 30 }, options);
return this.each(function(){
var $el = $(this),
curframe = 0,
width = settings.width,
fr = 1000/settings.framerate;
(function animloop(){
if(curframe == settings.frames) { curframe = 0; }
$el.css('background-position', (curframe*width)*-1 + 'px center');
curframe++;
setTimeout( animloop, fr );
})();
});
};
This is the code I've wrote to animate my sprites, but as I said it performs perfect in Safari and Firefox so I don't think it's the problem. Chrome seems to have an issue with animating using css alongside sprites.
I've tried everything I can find online but if anyone has any suggestions please let me know.
I'm using the latest stable chrome on mac btw (17.0.963.93)
You can see the css (using less) here btw
http://triple-tested.com/animations/css/style.less
Thanks for the replies guys, I think it is an issue with certain versions of chrome as it works perfect in the latest canary builds.
I ended up stripping back some of the animations for chrome, falls back gracefully to static images.