Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timeline transform element property multiple times with relative value #121

Closed
tomsercu opened this issue Mar 9, 2017 · 15 comments
Closed

Comments

@tomsercu
Copy link

tomsercu commented Mar 9, 2017

I just discovered anime.js for a svg animation project, so first off: thanks for this great library which fits my need exactly!

I ran into the problem with animating the same element property multiple times with relative values.

TL = anime.timeline().add({targets: '.el', translateX: '+=100'})
                     .add({targets: '.el', translateX: '+=100'})

I'd expect these relative transforms to be cumulative, but instead they restart from the same initial state.

Not sure if this is design or a bug, but in my opinion this takes away a lot of the value of relative transforms. With the velocity framework, $.Velocity.RunSequence() chains relative transforms in a cumulative way.

@tomsercu
Copy link
Author

Actually the behavior of animating a property multiple times with absolute value is also unexpected. In the above example, if I'd replace with translateX: 100 then translateX: 200, the second animation will have initial value 0. So on second translate, el will jump back to 0 then animate to 200.
Looked over the code a bit, and seems like this problem basically comes down to the fact that getOriginalTargetValue() is called at the time the animation is added, rather than when it is executed.

Lmk if this is a bug or design. I can imagine there being some performance benefits of not doing this at execution time.

@tomsercu
Copy link
Author

And another related issue here: restart() doesn't work properly in this scenario of multiple animations of the same property on a timeline.
Now I am supplying [from,to] pairs, i.e. translateX: [0,100] then translateX: [100, 200]
After TL.restart(), my el goes back to the initial value from the last animation, not the initial value of the timeline (ie goes back to 100).

@juliangarnier
Copy link
Owner

juliangarnier commented Mar 20, 2017

v2.0.2 will fix this, currently in beta here https://github.com/juliangarnier/anime/tree/v2.0.2.
It doesn't fix the restart()problem yet.

juliangarnier added a commit that referenced this issue Mar 21, 2017
@juliangarnier
Copy link
Owner

juliangarnier commented Mar 21, 2017

To make things easier, I created a branch to work on the timeline bugs / improvements.

I made some changes that should fix the relative transform values on the same target, fix the restart()problem, and #122

You can try it here : https://github.com/juliangarnier/anime/tree/v2.0.2-TL

@markoradak
Copy link

@juliangarnier, keep in mind that v2.0.2-TL breaks the behavior above, just in a different direction (sort of). I'll try to find some time to take a look at the code. Until then, all 3 versions (v2.0.1, v2.0.2, v2.0.2-TL) - respectively:

v2 0 1
v 2 0 2
v2 0 2-tl

@juliangarnier
Copy link
Owner

Can you share the code used in this example?

Thanks

@markoradak
Copy link

Sure thing:

/**
 * Cube
 */

const THREE = require('three')
const anime = require('../vendor/anime/anime.js')
// const anime = require('animejs')

var scene, camera, renderer, cube, floor

function init() {

  var ww = window.innerWidth,
      wh = window.innerHeight

  scene = new THREE.Scene()

  camera = new THREE.OrthographicCamera( ww / - 2, wh / 2, wh / 2, wh / - 2, 1, 1000 )
  camera.position.set( 500, 500, 500 )
  camera.lookAt(scene.position)

  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize( ww, wh )
  renderer.setClearColor( 0x292c33, 1 )
  renderer.setPixelRatio( window.devicePixelRatio )
  document.body.appendChild( renderer.domElement )

  var cubeGeometry = new THREE.BoxGeometry(50, 50, 50)
  var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff, shading: THREE.FlatShading})
  cube = new THREE.Mesh(cubeGeometry, cubeMaterial)
  scene.add(cube)

  var light = new THREE.DirectionalLight( 0xffffff, 1.8 )
	light.position.set( 60, 100, 20 )
	scene.add(light)

  anime.timeline({
    loop: true
  })
    .add ({
      targets: cube.scale,
      x: 2,
      duration: 500,
      easing: 'easeOutExpo'
    })
    .add ({
      targets: cube.scale,
      z: 2,
      duration: 500,
      easing: 'easeOutExpo'
    })
    .add ({
      targets: cube.scale,
      y: 2,
      duration: 1000
    })
    .add ({
      targets: cube.scale,
      x: 1,
      y: 1,
      z: 1,
      duration: 700,
      easing: 'easeOutExpo'
    })
    .add ({
      targets: cube.rotation,
      y: ( - Math.PI ),
      duration: 500,
      easing: 'easeOutExpo',
      offset: '-=700'
    })

}

function render() {
  requestAnimationFrame(render)
  renderer.render(scene, camera)
}

init()
render()

@juliangarnier
Copy link
Owner

Hoo ok, the problem occurs after the first loop.
Will look into this, thanks for reporting the bug.

@tomsercu
Copy link
Author

tomsercu commented Mar 24, 2017

With v2.0.2-TL the cumulative translateX animations on timeline work nicely.

restart() is somwhat fixed, though I find it unintuitive that play() call after completed, ie without explicit restart() does restart the animation. After this restart, pause and play calls work as expected.

But v2.0.2 and v2.0.2-TL did break behavior which worked before, with non-numerical fill values ie fill:'url(#pattern)'
MWE is

TL.add({targets: '#myel', opacity: 1, easing:'linear'});
TL.add({targets: '#myel', fill:'url(#pattern)', easing: 'linear'});
TL.add({targets: '#myel', fill:'#9fc5e8', easing: 'linear'});

This works fine on master, on v2.0.2 branches it just fills with url(#pattern) and then doesnt change to the new color.
Let me know if I shoud open a new issue for this.

Thanks!
Tom

juliangarnier added a commit that referenced this issue Mar 24, 2017
@juliangarnier
Copy link
Owner

The last commit should fix the loop issue.
It also fix any seek(t) related issues, where animations values on the same targets were not properly set in some cases.

You're right about the play() behaviour after animation completed being unintuitive.
I think I did this before implementing the restart()and reset() features, and forgot about it.
It's now fixed, and play / pause will do nothing after animation completed.

Let me know if it works for you that way.

Regarding the fill:'url(#pattern)', I didn't even know it was possible to make a transition between an URL and an hex value.

Can you share the full SVG and JS code concerning this issue?

Thanks!

@tomsercu
Copy link
Author

tomsercu commented Mar 24, 2017

I made a MWE here: http://codepen.io/tsercu/pen/RpJEVX
If you change the script src from master to v2.0.2-TL it breaks.
Even on master which works, it's not a smooth transition but it takes the url fill right away.
Will look for a different solution with masking/clipping on top of the original element.

@juliangarnier
Copy link
Owner

juliangarnier commented Mar 26, 2017

It should breaks since animation between non-numerical values like 'url(#pattern)'are not possible.
It was working before because the values weren't cumulative (the original problem), they all started from "#0FF", so the last animation was #0FF => #FF3, not 'url(#pattern)' => #FF3.

@tomsercu
Copy link
Author

On the canary branch, this all works for me now.
Currently on v2.0.2 branch, restarting and seeking is broken, but straightforward play does work.

@juliangarnier
Copy link
Owner

I re-tested all of this, and everything looks fine.

@ClaartjeBarkhof
Copy link

I am not following all the technical details described above (JavaScript newbie), but I think I encounter the same issue. I would like to move shapes around randomly, so make a random translation again and again, but not returning to the initial value:

anime({
  targets: '.collage-snipper',
  left: function() { return '+=' + anime.random(-30, 30) + 'px'; },
  top: function() { return '+=' + anime.random(-30, 30) + 'px'; },
  duration: 8000,
  loop: true
});

It seems like you guys have a solution to this issue, would it be possible to lay that out for me once again in simple steps?

Thanks in advance! (+ Beautiful library & documentation!!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants