jeremyckahn/shifty

Passing easing as a function

kimmobrunfeldt opened this issue · 16 comments

I was thinking to improve easing support for progressbar.js. Currently it supports only easing strings defined in shifty's formulas. I would like to be able to add support for passing easing as a function. Currently shifty takes a string, or object containing multiple strings. If you want to add new easing functions, they have to be added to prototype.

Could you add possibility to pass easing also as a function?

For example:

function easeInOutQuad(pos) {
      if ((pos /= 0.5) < 1) {return 0.5 * Math.pow(pos,2);}
      return -0.5 * ((pos -= 2) * pos - 2);
}

function myBadEasing(pos) {
    return pos / 2;
}

tweenable.tween({
  from: {
    x: 0,
    y: 0
  },
  to: {
    x: 250,
    y: 150
  },
  easing: {
    x: easeInOutQuad,
    y: myBadEasing
  }
});

Or just one easing function:

  easing: myBadEasing

I can do a pull request, but I think you know the library internals a bit better and shouldn't be a big change :)

Hi @kimmobrunfeldt, thanks for the suggestion! I think this feature idea fits pretty well with the library, and shouldn't be too difficult to implement. I think most of the changes will have to occur in composeEasingObject. I should have some time today to try this out, I'll let you know when I have something.

Okay @kimmobrunfeldt, I made an implementation for this feature. Please pull down the feature/per-tween-easing-fn branch and let me know how it works for you. You will need to run grunt build to generate the binaries in dist/. If this looks good to you, I will merge to master and put out a new release.

@kimmobrunfeldt, have you had a chance to try this out?

Sorry, I haven't yet had time to try

Ping again on this. Do you think the feature/per-tween-easing-fn branch is good to merge?

Sorry, has been a busy few weeks. Tested this now. Looks great but I found a problem:

Does not work if I have easing function, and also from and to objects defined. It'll give this error: Uncaught TypeError: easingObject[prop].split is not a function, inside this function:

  function expandEasingObject (easingObject, tokenData) {
    Tweenable.each(tokenData, function (prop) {
      var currentProp = tokenData[prop];
      var chunkNames = currentProp.chunkNames;
      var chunkLength = chunkNames.length;
      var easingChunks = easingObject[prop].split(' ');
      var lastEasingChunk = easingChunks[easingChunks.length - 1];

      for (var i = 0; i < chunkLength; i++) {
        easingObject[chunkNames[i]] = easingChunks[i] || lastEasingChunk;
      }

      delete easingObject[prop];
    });
  }

My from and to objects are:

        from: {
            color: '#f00'
        },
        to: {
            color: '#0f0'
        },

Also another thing, I didn't dig deep to your new code but this should also be implemented to be supported in .interpolate() functions. I'm in certain scenarios using .interpolate() in ProgressBar.js: https://github.com/kimmobrunfeldt/progressbar.js/blob/master/src/path.js#L141

Oh interesting, looks like my code isn't handling colors properly. This works:

var tweenable = new Tweenable();
var easingFunction = function (pos) {
  return Math.pow(pos, 2);
};

tweenable.tween({
  from: {
    x: 0
  },
  to: {
    x: 250
  },
  easing: easingFunction,
  step: function (state) {
    console.log(state)
  }
});

But this triggers the exception you found:

var tweenable = new Tweenable();
var easingFunction = function (pos) {
  return Math.pow(pos, 2);
};

tweenable.tween({
  from: {
    x: '#000'
  },
  to: {
    x: '#fff'
  },
  easing: easingFunction,
  step: function (state) {
    console.log(state)
  }
});

Good catch! I'll figure out what's going on with this.

Ok, I just pushed a fix — please give this another try (remember to build first). interpolate should be supported. Fixing the token extension should resolve that issue as well. If not, please provide some sample code to demonstrate the issue.

@kimmobrunfeldt, have you had a chance to review my updated branch?

The basic examples which I tested are now working.

It's good at least for my needs with progressbar :)

Thanks for checking! This is now available in the 1.5.0 release.

Great! Thanks. I'll provide this functionality to progressbar.js too when I have time to code.

Support for this is now released in progressbar.js@0.9.0.

Great, thanks for the update!