I'm using Raphael 2.1.0.
When I animate the opacity of a transparent PNG under IE8, the transparency animates well. ie: 'from' an opacity of 0.0 'to' an opacity of 1.0.
After the opacity animation has ended, I want to set/restore the image's position/opacity to a pre-animation state, but the alpha channel of the image becomes opaque. Where there was once a transparent background there is now a white square.
With an SVG renderer - Chrome and Firefox - things are fine. I've tried chaining the image, translation and alpha to no avail.
Here's the code:
var element = this._paper.image(image.Url(), 0, 0, width, height);
var removeOnStop = true;
var fromParams = {}
var toParams = {};
// From options
fromParams.opacity = options.from.alpha;
// ...
element.attr(fromParams);
// To options
toParams.transform = 'T300,300';
toParams.opacity = options.to.alpha;
// Animate
var anim = Raphael.animation(toParams, duration, 'linear', function() {
if (removeOnStop) {
element.attr({ opacity: defaultProperties.alpha });
element.transform('T' + defaultProperties.left + ',' + defaultProperties.top);
}
}).repeat(repeat);
element.animate(anim);
Any help would be greatly appreciated.
I tried the following
Animating the alpha, everywhere, but this causes null reference issues within Raphael
Chaining translate()/transform() and attr()
Applying filters directly to the object
Changing the order (attr before transform and vice versa)
In the end, the working solution is to translate AND set the opacity using attr:
if (removeOnStop) {
element.attr({ opacity: defaultProperties.alpha });
element.transform('T' + defaultProperties.left + ',' + defaultProperties.top);
}
became
if (removeOnStop) {
element.attr({ transform: 'T' + defaultProperties.left + ',' + defaultProperties.top,
opacity: defaultProperties.alpha });
}
Importantly, you must do this when initially creating the image and setting the initial opacity.
I hope this will save people future trouble.
Related
I am attempting to animate an svg doughnut circle with gsap. After much testing with code and layering, I am stumped with a glitchy hover effect (which I tried to resolve with pointer events) and the transform origin is only applied to a few of the expanded tabs. I am wondering if this might be that the tabs may have a different bounding box?
Comments added per request:
Side Note: I've tried applying fill-box to entire svg instead, I'm wondering if I need a parent layer thats an exact square so I can apply the transform origin for the child "expandtabs" to the center of that?
I assumed I needed to iterate through an array of both to have the tabs correspond. Unless the tabs were children of each other?
TLDR; Tabs are not scaling from center of circle, and glitchy hover effect
CodePen Example
.expandtab {
pointer-events: none;
transform: fill-box;
transform-origin: -15px 25%;
}
Javascript:
const subTabs = gsap.utils.toArray(".subtab");
const expandTabs = gsap.utils.toArray(".expandtab");
const tl = gsap.timeline({ defaults: { duration: .05, } });
tl.set(expandTabs, {
visibility: "hidden",
opacity: 0,
scale: 0,
});
subTabs.forEach((subTab, index) => {
let expandTab = expandTabs[index];
// Event Listener Hover on
subTabs[index].addEventListener("mouseover", (event) => {
console.log("you clicked region number " + index);
tl.to(expandTab, {
visibility: "visible",
opacity: 1,
scale: 1,
});
});
// Event Listener Hover off
subTabs[index].addEventListener("mouseout", (event) => {
console.log("you exited region number " + index);
tl.to(expandTab, {
opacity: 0,
scale: 0,
visibility: "hidden",
});
});
});
About the glitchy hover effect, the mouseenter and mouseleave will do the job better. mouseover is firering way to much...
For the "growing" effect, it is more complex. The transform-origin CSS property won't be enought. Any way, you will need different values for each five parts of the circle.
Additionnaly, you will need to adjust a transition to "fit" or "keep" the inner part of the circle in place. I suggest you to look at the fromTo method of GSAP. That will allow you to specify explicitely the starting and the landing coordinates.
Be patient! ;)
I'm developing a game engine in HTML5. Characters are div elements using an animated sprite for background. As sprite animation have fluid parameters and must be set by code, they can't be predefined in a static CSS definition, thus I use element.animate to set sprite animations to a given row at a given speed knowing my scales and frame counts.
// Applies the given frame and animation to the sprite
// Frame is an angle, clockwise direction: 0 = up, 1 = right, 2 = down, 3 = left
set_animation(frame, duration) {
const scale_x = this.settings.sprite.scale_x * this.settings.sprite.frames_x;
const pos_y = this.settings.sprite.scale_y * -frame;
// Cancel the existing animation
if(this.data_actors_self.anim) {
this.data_actors_self.anim.cancel();
this.data_actors_self.anim = null;
}
// Play the animation for this row or show the first frame if static
if(duration > 0) {
this.data_actors_self.anim = this.element.animate([
{
backgroundPosition: px([0, pos_y])
}, {
backgroundPosition: px([scale_x, pos_y])
}
], {
duration: duration * 1000,
direction: "normal",
easing: "steps(" + this.settings.sprite.frames_x + ")",
iterations: Infinity
});
this.data_actors_self.anim.play();
} else {
this.element.style.backgroundPosition = px([0, pos_y]);
}
}
Obviously that's a snippet from an actor class function: this.element is the div, this.settings is an object with parameters to be used who's names should make sense in this context, the px() function is a simple converter to turn arrays into pixel strings for HTML (eg: [0, 0] to "0px 0px").
The issue I'm having: While I can always run this function to set a new animation, I want the ability to change the speed of the animation without resetting it. It doesn't need to be a smooth transition, for all I care the new speed can be applied at the next iteration... I only want to avoid a visual snap or any kind of reset upon applying the change. Once an animation is set, I have no idea how to access and update its duration parameter. Does anyone have any suggestions?
When using console.log on this.data.anim I'm rightfully told it's an animation object. I tried using JSON.stringify to get more information but nothing relevant is printed. this.data.anim.duration returns undefined so the setting must be stored under some other property. Even if I know that property, I'd like to be sure web browsers will agree with me changing it like this.data.anim.options.duration = new_duration.
You can wait for the end of an iteration before changing the animation duration if that is what is required.
This snippet only sets an event listener for animationiteration event when you click the button to increase the speed.
function upthespeed() {
const div = document.querySelector('div');
div.addEventListener('animationiteration', function() {
div.style.animationDuration = '1s';
});
document.querySelector('button').style.display = 'none';
}
div {
width: 10vmin;
height: 10vmin;
background-color: magenta;
animation: move 10s linear infinite;
}
#keyframes move {
0% {
transform: translateX(50vw);
}
50% {
transform: translateX(0);
}
100% {
transform: translateX(50vw);
}
}
<div></div>
<button onclick="upthespeed()">Click me to increase the speed at the end of the next iteration (you may have to wait!)</button>
The value for the animation duration isn't in the Animation object itself but in the CSS animation-duration property for the Element: so this.data_actors_self.style.animationDuration = new_duration will do the job. It will however restart the animation if it is being played, but if I understand correctly that isn't a problem for you.
Edit: To change the animation's duration without restarting it, all you have to do is set the value of anim.startTime to what it was before. For example:
const startTime = anim.startTime;
this.data_actors_self.style.animationDuration = new_duration
anim.startTime = startTime;
First post, starting to explore JS.
I am using elearning software called Articualte Storyline. I export everything in my courses in html. It is basically a supercharged Powerpoint but one of the options is to create a trigger to run JS which opens up lots of additional options.
I have been using the JS below to set the browser background colour to something of my choosing.
I have then repeated the code on the next slide, so when the user moves through the exported course it changes the background colour.
However, this change of colour is very abrupt so I would prefer it to slowly fade between colour 1 and colour 2.
I imagine that on the second slide, I instruct the colour to be colour 1, then after a delay transition to the new colour 2, but I have become stuck!
Any help gratefully received, thanks!
document.body.style.background="linear-gradient(120deg, #f093fb 0%, #f5576c 100%)";
You can try this:
document.body.style.transition = "background 0.5s ease;"
Use a transition in the CSS
function rand() {
return Math.floor(Math.random() * 256);
}
function randomBG() {
var bgColor = "rgb(" + rand() + "," + rand() + "," + rand() + ")";
document.body.style.background = bgColor;
}
window.setInterval(randomBG, 2000);
body {
background-color: #AAEE33;
transition: background 500ms linear;
}
I'm trying to shift an image around based on the device orientation. But the values are very jumpy at rest, going between -1 to +2 with no movement, and I need a way to smooth it out a bit.
Is there an easy way to make this less jittery by averaging it out or something?
init();
var count = 0;
function init() {
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', function(eventData) {
// gamma is the left-to-right tilt in degrees, where right is positive
var tiltLR = eventData.gamma;
// beta is the front-to-back tilt in degrees, where front is positive
var tiltFB = eventData.beta;
// alpha is the compass direction the device is facing in degrees
var dir = eventData.alpha
// call our orientation event handler
deviceOrientationHandler(tiltLR, tiltFB, dir);
}, false);
}
}
function deviceOrientationHandler(tiltLR, tiltFB, dir) {
var logo = document.getElementById("imgLogo");
logo.style.webkitTransform = "rotate("+ tiltLR +"deg) rotate3d(1,0,0, "+ (tiltFB*-1)+"deg)";
logo.style.MozTransform = "rotate("+ tiltLR +"deg)";
logo.style.transform = "rotate("+ tiltLR +"deg) rotate3d(1,0,0, "+ (tiltFB*-1)+"deg)";
}
http://codepen.io/picard102/pen/zvOVLx
Use CSS transitions to smooth out setting CSS values.
You can try adding transition: all 0.5s;-webkit-transition: all 0.5s; to your logo. This will cause the browser to smoothly transition from one transform state to the next.
You might need to experiment a bit with this setting; and you may have to implement your own smoothing instead (in JavaScript, using JavaScript-based animation) if you're not happy with the results of CSS transition.
There's a big question for me which always comes on when I work on asynchronous loading of data e.g. an image with javascript.
In the past I placed a loader to show the user that something is in progress.
But at the time the data is loading the image won't animate properly. It's bucking all the time but only in Firefox Browser.
Same problem is with css3 animations e.g. a rotation.
Why is that happening?
var imgUrl = 'http://photojournal.jpl.nasa.gov/jpeg/PIA13932.jpg';
var aImagesToLoad = [];
var iLoaded = 0;
var runs = 3;
$(document).on('click', 'a#init-load', function(event) {
event.preventDefault();
if (confirm('A big image is loaded three times now')) {
var i, j;
var self = $(this);
self.fadeOut(500);
$('img').addClass('show');
for ( i = 0; i < runs; i += 1) {
var ts = new Date().getTime();
aImagesToLoad.push(new Image());
aImagesToLoad[aImagesToLoad.length - 1].onload = function(load) {
iLoaded += 1;
if (iLoaded === runs - 1) {
$('img').removeClass('show');
self.fadeIn(500);
}
};
aImagesToLoad[aImagesToLoad.length - 1].src = imgUrl + '?uq=' + (ts + i);
}
}
});
Made a jsfiddle with an ajaxloader image (animated gif) and a css rotation animation. Where it can be tested.
you neeed to add transalte3d(0,0,0) in your stylesheet so it kick in hardware acceleration rendering:
for example try:
transform: scale(1) rotate(359deg) translate3d(0,0,0.1);
the translate3d() property tells the browser to use hardware acceleration for smoother animation
#css-ajaxloader {
transform: scale(1) rotate(0deg) translate3d(0,0,0.1);
}
also i specify the scale at its default so the browser does not inherit any other scale.. since we want the scale at its default value of 1 .. normal size
adding Z to 0.1 will kick in hardware acceleration if the browser supports it
try that