Why css transition happens when CSS properties are not changed? - html

At first I change "left" css property, then I add transition property which looks for "left" changes and it executes animation. Could someone explain me why does it happen? I thought that it should change position of element and then looks for transition, but it doesn't.
var button = document.getElementById('slide');
button.onclick = function() {
var view = document.getElementById('view');
view.style.left = '-100px';
// Why does transition happen? O_o
view.style.transition = 'left 500ms ease-out';
}
http://jsfiddle.net/martyn0FF/20kvbvua/

Redraw and animation operations are deferred until the currently executing thread of JS finishes so that the browser can examine everything that has changed and act on those changes just once rather than trying to keep up with every change as it is made.
As such, it seems your changes to style.transition and style.left are connected and seen at the same time.
If you want to disconnect them, you can force a relayout by requesting one of several interesting properties (such as .offsetHeight) that trigger a relayout after you've set the .left property, but before you've set the .style.transition property like this:
var button = document.getElementById('slide');
button.onclick = function() {
var view = document.getElementById('view');
view.style.left = '-100px';
// trigger layout by requestion offsetHeight
var x = view.offsetHeight;
view.style.transition = 'left 500ms ease-out';
}
Notice in this jsFiddle with this code that the new left value takes place immediately and it is not animated.

Related

How to reset canvas context state entirely

I have a simple canvas animation, as follows:
function animate(){
var canvas = document.getElementById("canvas");
canvas.width = $(window).width();
canvas.addEventListener("click", replay, false);
var context = canvas.getContext("2d");
//animation code
function replay(e){
animate();
}
}
So my expectation is when the user clicks the canvas the animation will replay because I am reassigning the width:
canvas.width = $(window).width();
which will reset the entire context state ( read it here http://diveintohtml5.info/canvas.html)
It works the first time you click the canvas but after that it remembers the context transformation state and shows some weird animation.
I tried adding this:
context.setTransform( 1, 0, 0, 1, 0, 0 );
to explicitly reset the transformation matrix to identity matrix before re-drawing but has no effect.
It is different from this How to clear the canvas for redrawing
because it is about how to clear the display of context but I want to clear everything the display plus the context state.
I tried logging the state of each variable during the animation I get something weird with the ff code.
function moveHorizontal(x){
if(x < 100 ){
context.translate(1, 0);
console.log("x:"+x);
drawImage();
x += 1;
setTimeout(moveHorizontal,10,x);
}
}
I am calling this function initially as moveHorizontal(0).
so the log is as expected the first time:
x:0
x:1
x:2
.
.
x:99
when I click "replay" I get same thing as above:
x:0
x:1
x:2
.
.
x:99
which is correct but when I click "replay" the second time
I am getting this:
x:0
x:0
x:1
x:1
.
.
.
x:99
x:99
which triples the translation leading to unexpected effect.
any explanation?
Update
With the new information this may be the cause of the problem (there is not enough code to be 100% sure but it should give a good pointer as to where the problem is):
As the code is asynchronous and seem to share a global/parent variable x, what happens is that when, at some point, the replay is invoked before one earlier has stopped, the x is reset to 0 causing both (or n number of loops) to continue.
To prevent this you either need to isolate the x variable for each run, or using a simpler approach blocking the loop from running if it's already running using x from a previous invocation. You can use a flag to do this:
var x = 0,
isBusy = false;
function animation(x) {
if (isBusy) return;
if (x < 100) {
isBusy = true;
// ...
setTimeout(...); // etc.
}
else {
isBusy = false;
}
}
optionally, store the timeout ID from setTimeout (reqID = setTimeout(...)) and use clearTimeout(reqID) when you invoke a new loop.
Old answer
The only way to reset the context state entirely is to:
Set a new dimension
Replace it with a new canvas (which technically isn't resetting)
The latter should be unnecessary though.
According to the standard:
When the user agent is to set bitmap dimensions to width and height,
it must run the following steps:
Reset the rendering context to its default state.
...
In the example code in your post you are using a mix of jQuery and vanilla JavaScript. When working with canvas (or video element) I always recommend using vanilla JavaScript only.
Since you are not showing more of the code it is not possible for us to pinpoint to any specific error. But as neither setting an identity matrix nor setting a size for canvas seem to work, it indicates that the problem is in a different part of the code. Perhaps you have persistent offsets involved for your objects that are not reset.
Try to eliminate any possible errors coming from using jQuery to set width as well:
canvas.width = window.innerWidth; // and the same for height
Two other things I notice is that you set the size of canvas inside a function that appears to be part of a loop - if this is the case it should be avoided. The browser will have to, in essence, build a new canvas every time this happens. Second, this line:
canvas.addEventListener("click", replay, false);
can simply be replaced with (based on the code as shown):
canvas.addEventListener("click", animate, false);
You will need to post more code to get a deeper going answer though. But as a conclusion in regards to context: setting a new size will reset it. The problem is likely somewhere else in the code.

Optimize ItemRenderer For Flex Mobile Application

I made this class, which is an ItemRenderer class, used in a DataGroup ( mobile application ),
and I am not entirely sure if I did the right thing or not, my issues are :
Is there a better way to show the image, which is 80x80 and directly loaded from the server;
How to make the height of the row dynamic, I mean, depending on the height of the 3 StyleableTextFeild
Is this the right way to add the listener on the image, that will trigger a simple HTTPService,
Here is the functions from the class, Any help would be much appreciated !!
Image
Declared it as a simple image :
var logo:Image;
On override createChildren
logo = new Image();
addChild(logo);
And I added on set Data
logo.source = "http://192.168.0.15:3000/"+value.logo_thumb_url;
Size
override protected function measure():void {
measuredWidth = measuredMinWidth = stage.fullScreenWidth;
measuredHeight = measuredMinHeight = 100;
}
Listener
override public function set data(value:Object):void {
tel.text = String(value.Tel);
description.text = String(value.Descricao);
nome.text = String(value.Nome);
logo.addEventListener(MouseEvent.CLICK, function():void{
var service:HTTPService = new HTTPService();
service.url = value.targer;
service.method = "GET";
// setting headers and other variables ...
service.send();
});
}
You can use URLLoader or Loader for loading the image if you are planning to cache the image on the client side, if you cache the image, it wil help you not load the image again when the users scrolls through the list. (What you have done is Ok, but you will hit performance issues)
For variable row height, if Datagroup does not work, use List. find it here Flex 4: Setting Spark List height to its content height
There should be a buttonMode property for some items, make it buttonMode for the logo, for variable row height, find something related to wordWrap and variableRowHeight properties on the datagroup.
There are a few suggestions, what you have coded is good, but, instead of adding the listeners on set data, add it in creation complete, as it is more appropriate. Also, the event listeners has to be weak referenced, http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/EventDispatcher.html#addEventListener()

Check if CSS3 transition is running

Is there a way to detect in my Javascript if an element is currently being animated with a CSS3 transition?
An "transitionstart"-event (equivalent to the 'transistionend' event) would also work out, but I can't find any mention of it in the specification.
Well, since there is only a transitionend event (http://www.w3.org/TR/css3-transitions/#transition-events) something ugly comes to my mind:
http://jsfiddle.net/coma/psbBg/6/
JS
$(function() {
var div = $('div');
var property = div.css('transition-property');
var lastValue = div.css(property);
setInterval(function() {
if(lastValue !== div.css(property)) {
console.log('changed!');
}
lastValue = div.css(property);
}, 10);
});
It can be improved implementing custom events, taking care of getting the correct transition property (or properties), and more ideas, but you get the picture right?
Maybe you need to take another path on solving your original problem...

How to wait a while before adding elements in css? javascript?

I have a problem that I will explain.
I'm doing an animation in HTML5 and CSS3. My idea is that a plane is flying around and it launches a missile after a while. What I want to do is to make the missile appear after that time. I thought about doing that changing the z-Index property of my div (because I have the missile image into a div container) using javascript after a while (any time I choose). For doing that I found the sleep function at the bottom. I created the "appear" function that I know it works because It changes my zIndex value but it doesn't wait the 2 seconds I want.
I also thought I had the solution by using the visibility property, but I have the same problem, sleep function doesn't wait at all.
Any suggestions? Thanks
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
function appear(object){
sleep(200000);
var objective = document.getElementById(object);
objective.style.zIndex=1;
You can pass a function to the setTimeout function which will call that function in x milliseconds.
function waitForMe() {
alert('triggered!');
}
// Call waitForMe in 200000ms
setTimeout(waitForMe, 200000);
So for your example, you would want to use 2000 (2 seconds), not 200000 (200 seconds):
function appear(object) {
setTimeout(function () {
var objective = document.getElementById(object);
objective.style.zIndex=1;
}, 2000);
}
Hiding and showing an element
You can hide and show a method in a few ways:
Use z-index as you suggest, probably not the best way as we can actually hide it instead of sending it to the back of the page.
objective.style.zIndex = 1;
Use display, this hide the object completely.
// hide
objective.style.display = 'none';
// show
objective.style.display = 'block';
Use visibility, this will hide the object but it will still take up space in the page. This wouldn't matter if you're using position:fixed or position:absolute.
// hide
objective.style.visibility = 'hidden';
// show
objective.style.visibility = 'visible';
You can either create a div around the objective, and add it in with javascript like this
document.getElementById('objectivespan').innerHTML=imagehere;
Other than that, you can use
objective.style.visibility='hidden';
and change it to
objective.style.visibility='visible';
for the delay, use
function sleep(){
alert('slept');
}
SetTimeout('sleep', 10000);

Is there a way to keep an object always at the top of the display list?

Is there a way to make a display object always be at the top of the display list?
For example, I know you can set the childIndex, i.e:
setChildIndex(myDisplayObject, numChildren-1);
But is there a way that an object has sensed that something else has been added to the display list and restack themselves accordingly?
You can listen to the Event.ADDED event on the container. This event will bubble up, so you'll get called whenever a display object is added to the container or any of its children.
Here's an example of how you could do this. You'll see the black box always stays on top.
var container:DisplayObjectContainer = this; // this is a frame script but just change this line as necessary
container.addEventListener(Event.ADDED,handleAdded,true);
function handleAdded(e:Event):void {
// this if tries to cover some edge cases, unlikely to happen in your code, from your description
if(container == topElement.parent && container.numChildren > 0 && container.getChildIndex(topElement) != container.numChildren - 1) {
container.setChildIndex(topElement,numChildren - 1);
}
}
function getSprite(c:uint):Sprite {
var sp:Sprite = new Sprite();
sp.graphics.beginFill(c);
sp.graphics.drawRect(0,0,100,100);
sp.graphics.endFill();
return sp;
}
var topElement:Sprite = getSprite(0);
container.addChild(topElement);
var sp:Sprite = getSprite(0xff0000);
container.addChild(sp);
sp.addChild(getSprite(0xff00));
var sp2:Sprite = getSprite(0xff);
container.addChild(sp2);
However, I think it's much simpler and cleaner just to have 2 containers, say, top and bottom, kind of like layers. In top you'd add the element that always must be on top (or this could be your element as you probably don't need to have this extra container). In bottom you'd add and remove whatever you want. Then you can forget about manually restacking stuff (at least to keep the top element atop).
You can override the addChild() method in the parent object. In that method you can move your child to the top using
setChildIndex(myDisplayObject, numChildren-1);
In this way everytime an object is added to the parent, the parent moves your object to the top.