I've been looking around for how to create animations in Om, I've tried creating a RaphaelJs component with moderate success. I get the animation I want, but for some reason Om renders multiple instances of the SVG element.
Looking at the animation example in the Om github folder uses setInterval to change the values you want to animate, which is less than ideal.
I'm aware of the CSSTransitionGroup addon, but it looks like you can only flip between preset animations defined in the CSS, you can't decide to do something like rendering a path and having a shape following it with randomised timings. Please feel free to correct me if you can dynamically define animations using it.
Does anyone have any good examples of performing simple animations? Just translating or rotating simple shapes would give me an idea of how to start tackling it from there.
You can use CSSTransitionGroup to animate position/movement, orientation and other visual properties like opacity, color, borders or shadows (perhaps using keyframes) or more complex hacks. The major limitation of this approach is that it only allows you to animate mounting and unmounting of components and then only through animation defined in CSS.
If you need to animate components during their mounted lifetime or you want more fine-grained control over what you can animate, you might want to take another approach like what I do in this code.
This is how you would use CSSTransitionGroup from Om.
For this to work, you need to use the with-addons version of React (eg react-with-addons-0.12.1.js or react-with-addons-0.12.1.min.js).
(def css-trans-group (-> js/React (aget "addons") (aget "CSSTransitionGroup")))
(defn transition-group
[opts component]
(let [[group-name enter? leave?] (if (map? opts)
[(:name opts) (:enter opts) (:leave opts)]
[opts true true])]
(apply
css-trans-group
#js {:transitionName group-name
:transitionEnter enter?
:transitionLeave leave?}
component)))
Then to use it, you can do:
(transition-group "example" (when visible? (om/build my-component data)))
Now toggle visible? to animate my-component being mounted and unmounted. If you want to disable either the enter or leave animation:
(transition-group
{:name "example"
:enter false} ; Only animate when component gets unmounted, not when mounted
(when visible? (om/build my-component data)))
You can also animate adding or removing from/to lists of items:
(transition-group "example" (om/build-all my-component list-of-data))
Or using map, perhaps something like:
(transition-group "example" (map #(dom/li %) list-of-data))
You also need to add the correct CSS:
.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
Note that unless you disable one of the animations, you need to include both in the CSS. For example, if you leave out the leave animation, then your component may not get unmounted as React will hang waiting for the animation to complete. Simple fix is to disable it using {:leave false} or to include the leave animation in your CSS.
One other gotcha to be aware of: this will only animate child components if the transition group is mounted before the children. If the children and the transition group are mounted at the same time, then they won't be animated. This can be a bit awkward sometimes. For example, the above code snippets would not animate without the (when visible? ...) as without toggling, the child would be mounted at the same time as the transition group. Also, the build-all example below works best if list-of-data is not prepopulated but instead populated after mounting. For this reason, CSSTransitionGroups work best for code that switches between views/components or lists of data that gets modified by the user, but doesn't work for animating initial display of components on page load.
Perhaps something like:
(transition-group "view-selection"
(condp = current-view
"home" (om/build home-page data)
"blog" (om/build blog-page data)
"about" (om/build about-page data)
:else (om/build error-404-page data)))
-
Finally, if you do not wish to use a helper function, you can use css-trans-group directly:
(css-trans-group
#js {:transitionName "example"}
(when visible? (om/build my-component data)))))
Or, if using a lists of child components (eg through map or build-all):
(apply
css-trans-group
#js {:transitionName "example"}
(om/build-all my-component list-of-data))))
I have not yet used the low-level TransitionGroup API. More information can be found on the React CSSTransitionGroup page.
Care to look into a ClojureScript port of https://github.com/chenglou/react-tween-state or https://github.com/chenglou/react-state-stream?
TransitionGroup provides nothing but helpers for hooking onto some lifecycle events. It theoretically has nothing to do with animation. If you want an actual animation API, give a look at the two things I made above. The readmes should provide enough information for the rest.
Related
I have a scene that is mostly static, i.e. without user interaction it doesn't change (animations).
The user interacts with the scene. For example:
when the user clicks on certain location in a map, another image opens in another pane
the user may move the camera by moving the mouse
etc...
Originally I implemented the rendering via animate(), which calls:
function animate() {
requestAnimationFrame( animate );
render();
controls.update();
}
This works fine (in terms of response) except that
the rendering happens constantly, which is not necessary.
for one of the admin pages, which does not show the scene, I'm getting runtime errors when the scene does not exist, but the rendering still goes on...
So I re-implemented the rendering by calling, explicitly, after user action which change the scene
render();
controls.update();
This requires more work, because I have to cover all the cases where the scene changes.
In one of the cases, the behaviour is not as expected (the rendered scene is black and explicit call to render does not fix the problem).
The link here says that if your scene is static, there is no reason for an animation loop.
The link here suggests to use animate().
My questions:
Is explicit render, a good pattern to use in three js for static scenes?
Are there pros to render only when needed, instead of calling animate which renders constantly, when this is not needed?
In terms of resource load in general
The link here says that if your scene is static, there is no reason for an animation loop.
The answer of the respective stackoverflow question is also the correct one. The second link is unrelated to question whether to use on-demand rendering or not.
In general, having an animation loop requires more resources since you constantly render no matter if the scene changes or not. However, certain application like 3D viewers (without animation playback) do not need to do this. It's sufficient to render only when certain events happen (e.g. user interaction).
Is explicit render, a good pattern to use in three js for static scenes?
Yes, it is. It is a good pattern for 3D applications in general.
Are there pros to render only when needed, instead of calling animate which renders constantly, when this is not needed? In terms of resource load in general
The app requires less resources which is always a good thing. E.g. mobile device will save a lot of battery and laptops or desktops will be more quiet.
I want to use enter/leave transitions in vue.js, using the built in javascript hooks for transitions:
https://v2.vuejs.org/v2/guide/transitions.html#JavaScript-Hooks
My animation library of choice is GSAP: https://greensock.com/
Both, my enter function enter: function(el, done) {} and my leave function leave: function(el, done) {} are called correctly.
The enter animation works just fine — but the leave animation doesn't do anything.
I guess it is a GSAP related thing I do not understand yet. I tried resetting the animation and clearing the inline styles of the animated element. Didn't help.
Here is the codepen:
https://codepen.io/Sixl/pen/oGwOKW?editors=0011
Here's a fixed version: https://codepen.io/GreenSock/pen/veJGmR?editors=0010
I noticed a few problems:
You were calling done() immediately instead of waiting for the animation to complete. I just moved it to an onComplete callback.
You created a single timeline that you were adding all your animations to, but that isn't very appropriate in this case because it's not a linear thing - the clicks could happen anytime. So the playhead on the timeline reaches the end of the first animation, and then when you place a new one at the end (much later, when someone clicks), the playhead would already be way past that spot where you're placing it, causing it to jump to the end on the next render (appropriately). It's cleaner to simply use a TweenMax here instead. Or you could create a new TimelineLite each time there's a click (don't worry - it's fast).
--
TweenMax.to(el, 0.5, {
x: 150,
autoAlpha: 0,
scale: 0.5,
onComplete: done
});
If you have any more questions, don't hesitate to swing by the GreenSock forums. https://greensock.com/forums/ where there's a great community focused on helping people with GSAP questions.
Happy tweening!
I have a simple Polymer app consisting of two elements. The first, x-app, element has the second element, x-inner, inside its local dom.
Inside the x-inner element I define a keyframe animation that is called spin that I apply on the :host. Inside the x-app I also apply the same animation name, spin, but the keyframe animation is not defined. Although, the spin animation works on both elements. It seems to me that the #keyframe leaks out from the inner element.
Is this the behaviour that is expected? Or do I define the #keyframe animation incorrectly?
Please see my jsbin for an example: jsbin
It is because you are using "Shady" DOM, which doen't really isolate the components CSS styles, as a real Shadow DOM would do.
Try defining shadow instead of shady and it will work.
jsbin example
I've been trying to accomplish this for like two weeks now. Does anyone here have any idea of how do this? I won't even paste my code because it's the worst ever.
Thanks.
Have you check fullpage.js?
You might be able to get the same scrolling effect by creating your own CSS3 function with the CSS Easing Animation Tool of Matthew Lein.
Then pass it to the parameter easingcss3 of fullPage.js.
easingcss3: 'cubic-bezier(1.000, 0.000, 0.000, 1.005) 0.5s',
Or, if you prefer, you can go for jQuery easing effects and use css3:false. (although it will be smoother with css3)
Regarding the elements dissappearing on scroll, you'll have to do it by yourself by animating them on a callback such as onLeave or by using the classes added to the body as in this example.
body.fp-viewing-page2-slide1 #section1 .moveOut{
transform: translate3d(0, -400px, 0);
}
Something in this line.
I'm an engineer and we are currently porting our Red5 + Flash game into a Node.js + Easeljs html5 application.
Basicly: it's a board game, not an rpg. The layer system means we have multiple canvasses, based on functionally. For example there is a static background stage, with images. There is a layer for just the timers.
At default, all canvas size is 1920x1080, if needed we downscale to fit to the resolution.
The first approach used kinetic.js, but the performance fallen when the game got complex. Then we switched to easel, because it's abstraction level is lower, so we can decide how to implement some more function, not just use the provided robust one.
I was optimistic, but now it's starting to show slowness again, that's why I want to look deeper inside and do fine performance tuning. (Of course everything is fine in Chrome, Firefox is the problem, but the game must run smoothly on all modern browser).
The main layer (stage) is the map, contains ~30 containers, in each there is a complex custom shape, ~10 images. The containers are listening to mouse events, like mouseover, out, click. Currently, for example on mouseover I refill the shape with gradient.
Somehow, when I use cache, like the way in the tuts the performance get even worse, so I assume I'm messing up something.
I collected some advanced questions:
In the described situation when can I use cache and how? I've already tried cache on init, cacheUpdate after fill with other color or gradient, then stage.update(). No impact.
If I have a static, never changing stage cache doesn't make sense on that layer, right?
What stage.update() exactly do? Triggering the full layer redraw? The doc mentions some kind of intelligent if changed then redraw effect.
If I want to refill a custom shape with new color or gradient I have to completely redraw its graphics, not just use a setFill method, right?
In easel there is no possibility to redraw just a container for example, so how can I manage to not update the whole stage, but just the one container that changed? I thought I can achieve this with caching, cache all containers the just update the one that changed, but this way didn't work at all for me.
Does it make sense to cache bitmap images? If there are custom shapes and images in a container what is better? Cache the container or just the shape in container.
I found a strange bug, or at least an interesting clue. My canvas layers totally overlapping. On the inferior layers the mouseover listening is working well, but the click isn't on the very same container/object.
How can I produce a click event propagation to overlapped layers those have click listeners? I've tried it with simple DOM, jquery, but the event objects were far away from what canvas listeners wanted to get.
In brief, methods and props I've already played with bare success when tried tuning: cache(), updateCache(), update(), mouseEnabled, snapToPixel, clear(), autoClear, enableMouseOver, useRAF, setFPS().
Any answer, suggestion, starting point appreciated.
UPDATE:
This free board game is a strategy game, so you are facing a world map, with ~30 territories. The custom shapes are the territories and a container holds a territory shape and the icons that should be over the territory. This container overlapping is minimal.
An example mouse event is a hover effect. The player navigate over the territory shape then the shape is getting recolored, resized, etc and a bubble showing up with details about the place.
Basically, maximum amount of 1-3 container could change at once (except the init phase -> all at this time). Not just the animations and recoloring slow in FF, but the listener delay is high too.
I wrote a change handler, so I only stage.update() up on tick the modified stages and the stages where an animation is running (tweenjs).
In my first approach I put every image to the container that could be needed at least once during the game, so I only set visible flags on images (not vectors).
Regarding caching:
There are some strange caching-issues, somehow the performance can drop with certain sizes of the caching rectangle: CreateJS / EaselJS Strange Performance with certain size shapes
(2) Depending on how often you call stage.update();
(3)
Each time the update method is called, the stage will tick any
descendants exposing a tick method (ex. BitmapAnimation) and render
its entire display list to the canvas. Any parameters passed to update
will be passed on to any onTick handlers.
=> Afaik it rerenders everything if not cached
(4) Yes.
(5) No. (I don't know of any)
(6) If the content's of the container don't change often, I'd cache the whole container, otherwise the container will be reconstructed every frame.
I have a question though: Why do you use multiple canvases? How many do you use? I could imagine that using multiple canvases might slow down the game.
How many sprites do you use in total?
2: if your layer or stage doesn't change, don't call stage.update() for that layer (so it doesn't gets rerendered, gives me a much lower cpu!)
For example, keep a global "stagechanged" variable and set this to true when something has changed:
createjs.Ticker.addEventListener("tick",
function() {
if (stagechanged)
{
stagechanged = false;
stage.update();
}
});
(or do you already use this, as stated in your "update"?)
4: I found a way to update for example the fill color :)
contaier1.shape1.graphics._fillInstructions[0].params[1] = '#FFFFFF';
(use chrome debugger to look at the _fillInstructions array to see which array position contains your color)
5: I found a way to just paint one container :)
//manual draw 1 component (!)
var a = stage.canvas.getContext("2d");
a.save();
container1.updateContext(a); //set position(x,y) on context
container1.draw(a);
a.restore();