GithubHelp home page GithubHelp logo

camille-hdl / animatepaper.js Goto Github PK

View Code? Open in Web Editor NEW
35.0 3.0 6.0 10.54 MB

An animation library for paper.js.

Home Page: http://camille-hdl.github.io/animatePaper.js/

License: MIT License

HTML 8.21% JavaScript 26.14% TypeScript 65.65%
animation-library vector-graphics paperjs easing-functions

animatepaper.js's Introduction

animatePaper.js

An animation library for paper.js.

See a live demo on jsbin.

TypeScript

TypeScript declarations are available as of 1.2.1, in dist/src/animatePaper.d.ts.

Changelog from 0.x to 1.x (details)

  • paper is now a peerDependency, this should remove unnecessary code from your dependency tree.
  • The segmentGrow property and grow effect have been removed (this feature was very buggy).
  • When using rotate or scale properties, you can provide a new setting : center (or rotateCenter/scaleCenter) (default is item.position).
  • Animation supports a new option repeat (defaults to 0).
  • settings.complete callback takes the Animationobject as 1st argument.
  • Color support for paper.Group animation (1.1.*)
  • rgb, gray, hsl, hbs Color formats are now supported (1.1.*)
  • bug fix : negative absolute position supported (relative values must be of string type) (1.2.*)
  • bug fix : allow 0 duration (1.2.*)
  • custom easings : you can now pass a function (p: number) => number to settings.easing (1.2.*)

How to use :

npm and browserify

npm install --save paper-animate
then
import * as animatePaper from "paper-animate"; or var animatePaper = require("paper-animate")

bower

bower install paper-animate --save

directly in the browser

(not recommended)
Get the minified file in dist/paper-animate-browser.min.js, and include it in your page, after paper.js.

Features :

  • Animation of multiple properties at the same time,
  • easing,
  • chaining

This is a work in progress, and any help or feedback is more than welcome.

So far, only opacity, position, scale, rotate, translate, fillColor and strokeColor are supported, but I add more whenever I have the time.

Animate an Item

(you can animate a Group too)

You can either use a predefined animation :

var myCircle = new paper.Path.Circle(new paper.Point(50,50),35);
animatePaper.fx.shake(myCircle);

Predefined animations available by default : shake, fadeIn, fadeOut, slideUp, slideDown, splash. You can try them on this demo.

Or animate properties :

var myCircle = new paper.Path.Circle(new paper.Point(50,50),35);
animatePaper.animate(myCircle, {
    properties: {
        translate: new paper.Point(100,50),
        scale: 3
    },
    settings: {
        duration: 4000,
        delay: 1000,
        easing: "easeInElastic",
        complete: function(item, animation) {
            console.log('complete !');
        }
    }
});

When animating position or color properties, you can provide either relative or absolute values :

var square = new paper.Path.Rectangle(new paper.Point(75, 75), new paper.Size(50,50));
square.strokeColor = 'green';
square.animate({
  properties: {
    position: {
      x: "+200", // relative to the current position of the item. At the end, `x` will be : 275
      y: 150     // absolute position. At the end, `y` will be : 150
    },
    strokeColor: {
      hue: "+100",
      brightness: "-0.4"
    }
  },
  settings: {
    duration:1500,
    easing:"easeInBounce"
  }
});

Note : Relative values must be strings.

Repeat

If you want your Animation to run more than once, you can use the settings.repeat option (defaults to 0).
If settings.repeat is a number > 0, your animation will run settings.repeat additional times.
If you set settings.repeat to true, the animation will repeat infinitely until you call animatePaper.stop(item, true, true) (the third parameter should be true, otherwise only the current Animation will be stopped).
If you set settings.repeat to a function, it will be called at the end of every "loop" and the Animation will repeat itself as long as settings.repeat returns true.
This feature works best with relative values (e.g. '+myVal' instead of myVal), if you repeat an animation with absolute values you won't get the desired result.

animatePaper.animate(item,{
    properties: {
      rotate: '+360'
    },
    settings: {
      center: new paper.Point(100, 50),
      duration: 2000,
      repeat: 2, // animation will run 3 times total
      easing: "linear"
    }
});
animatePaper.animate(item2,{
    properties: {
      rotate: '+360'
    },
    settings: {
      center: new paper.Point(100, 50),
      duration: 2000,
      repeat: true, // will loop until .stop() is called
      easing: "linear"
    }
});
setTimeout(function() {
  animatePaper.stop(item2, false, true);
}, 10000);

var c = 0;
animatePaper.animate(item3,{
    properties: {
      rotate: '+360'
    },
    settings: {
      center: new paper.Point(100, 50),
      duration: 2000,
      repeat: function(item, animation) { // will run until c >= 2
         c++;
         return (c < 2);
      },
      easing: "linear"
    }
});

The lib also extends Item.prototype with .animate() and .stop() methods, which means you can also use

myCircle.animate({
    /*
        Animation parameters ...
    */
});

If you want to perform multiple animations successively, you can provide an array of parameters objects :

var star = new paper.Path.Star(new paper.Point(45,50),5,25,45);
star.fillColor = "black";
star.opacity = 0;
star.animate([{
  properties: {
      translate: new paper.Point(200,50),
      rotate: -200,
      scale: 2,
      opacity:1
  },
  settings: {
      duration:3000,
      easing:"swing"
  }
},
{
  properties: {
      translate: new paper.Point(0,50),
      rotate: 200,
      scale: 1,
      opacity:0
  },
  settings: {
      duration:3000,
      easing:"swing"
  }
}]);

This is especially helpful when adding predefined animations to the library, it helps avoiding callback hell.

You can stop all running animations on an item by calling :

animatePaper.stop(star);
// or
star.stop();

The stop method can take a goToEnd argument. If true, all the animations will take their final value and complete callbacks will be called.

Easing

By default, the supported easing functions are : linear, swing, easeInSine, easeOutSine, easeInOutSine, easeInCirc, easeOutCirc, easeInOutCirc, easeInElastic, easeOutElastic, easeInOutElastic, easeInBack, easeOutBack, easeInOutBack, easeInBounce, easeOutBounce, easeInOutBounce, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, easeInQuint, easeOutQuint, easeInOutQuint, easeInExpo, easeOutExpo, easeInOutExpo.

If you want to use more easing functions, settings.easing can take a (p: number) => number function as a value, so that you can use your own or use some from an external library such as bezier-easing.

animatePaper.animate(item,{
    properties: {
      /** ... **/
    },
    settings: {
      /** ... **/
      easing: BezierEasing(0, 0, 1, 0.5)
    }
});

Alternatively, you can use the animatePaper.extendEasing(myEasingFunctions) method to add your own easing functions or override any existing easing.

The method takes only one argument : an object in which keys are easing names, and values are easing functions:

animatePaper.extendEasing({
    "triple": function(p) {
        return p*3;
    }
});

Learn more about easing here.

Extend property hooks

If you want to add support for a new property or override the library's behavior for properties that are already supported, you can use animatePaper.extendPropHooks(myPropHooks);.

myPropHooks should be an object in which keys are property names, and values are "hook objects".

Each "hook object" can have a get, set and ease method, and will be used to interface the animation with the property.

For example, say you want to add support for color animation:

animatePaper.extendPropHooks({
  "fillColor": {
    get: function(tween) {
      // my code ...
    },
    ease: function(tween,easedPercent) {
      // my code ...
    }
  }
});

When these functions are used, they are passed only one argument : the Tween object (see the doc in doc/ for more details), exept for the ease() function which gets the eased percent as second parameter.

  • The get() function must return the current value of the Tween.item's property.
  • The set() function must set the value of the Tween.item's property with Tween.now (which will most likely be the result of get() or ease())
  • The ease() function must return the eased value. The second parameter is the eased percent.

Add your own animations to the lib

To do so, simply add properties to animatePaper.fx, like so :

animatePaper.fx.wave = function(item,settings) {
  var myAnimations = [...];
  item.animate(myAnimations);
};
animatePaper.fx.wave(myItem);

Contributing

  • as of 1.2.1 the lib uses TypeScript, so make your changes in src/*.ts then build with gulp build-paper-animate and gulp build-paper-animate-browser.
  • run unit tests with npm test.
  • open tests/test.html in a browser to run integration tests.

TODOS

  • Change how item.data._animatePaperVals works to allow multiple animations of the same property at the same time.
  • Change Tween so that we garantee values are right at 0and 1 positions, to avoid problems with imprecise numbers (floating point). See "Negative position" in tests.js.
  • Add tests

Help needed !

I'm a beginner in paper.js, so if you spot a mistake or want to add something to the lib, any help would be appreciated :-)

Author

camille dot hodoul at gmail dot com

Contributors

  • User pueding for bug fixes and delay feature.
  • Users s-light and StratusBase for feedback, ideas and contributions (Group Color support, bug fixes).

@Eartz_HC

animatepaper.js's People

Contributors

camille-hdl avatar pueding avatar s-light avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

animatepaper.js's Issues

Use with ffmpegserver.js?

Hi,

Thanks for a great paper js animation lib. I tried to use it integrated with https://github.com/greggman/ffmpegserver.js but doesn't seem to work (CCapturer keeps recording but no animations seems to run).

Haven't looked too much into the animatePaper.js code but any clue on what could be preventing it would be much appreciated!

Thanks

Animate "position" with moveOnPath

[enhancement]
inspired by #7 i have made a animation to move an given item along a path:

    animatePaper.extendPropHooks({
            "moveOnPath": {
                get: function(tween) {
                    if (!tween.item.data._animatePaperVals) {
                        tween.item.data._animatePaperVals = {};
                    }
                    if (typeof tween.item.data._animatePaperVals.moveOnPath === "undefined") {
                        tween.item.data._animatePaperVals.moveOnPath = 0;
                    }
                    var output = tween.item.data._animatePaperVals.moveOnPath;
                    return output;
                },
                set: function(tween) {
                    var curOffsetOnPath = tween.item.data._animatePaperVals.moveOnPath;
                    tween.item.data._animatePaperVals.moveOnPath = tween.now;
                    if (tween.A.settings.targetPath instanceof paper.Path) {
                        const pathOffset = tween.A.settings.targetPath.length * curOffsetOnPath / 1;
                        const curPos = tween.A.settings.targetPath.getPointAt(pathOffset);
                        const curRot = tween.A.settings.targetPath.getTangentAt(pathOffset).angle;
                        tween.item.position = curPos;
                        tween.item.rotation = curRot;
                    } else {
                        // do nothing.
                    }
                }
            }
        });

and to use it:

    rect0.animate({
            properties: {
                moveOnPath: 1 // position on path from 0..1
            },
            settings: {
                targetPath: the_path_to_follow,
                duration: 6000,
                easing: "swing",
                complete: () => {
                    // Hack to allow animation to start again.
                    rect0.data._animatePaperVals.moveOnPath = 0;
                }
            }
        });

i have a working example at
https://github.com/s-light/paper.js_tests/blob/master/animation_moveonpath.html
https://github.com/s-light/paper.js_tests/blob/master/js/animation_moveonpath.js

TODO: would be good to have some nicer way to specify the start-conditions for a animation or find a good way how to handle the 'overflow' from 1 to 0.

segmentGrow example

Hi, I appreciate your abstraction lib.

I'm trying to use this segmentGrow facility but don't know how to adapt to my scenario. Can you provide an example?

I got this plunker to show you what I'm doing. It is a street route, it is buggy but it is a start.

How to animate scale when scaleX and scaleY are different?

Trying to animate the size of a rectangle shape based on width and height, but I can't see how to do it with paper-animate.

I already have the values for scaleX and scaleY. They work fine when scaling using the function of PaperJS, but it's not animated.

function resize(elem,width,height){
   var scaleX = width/elem.bounds.width;
   var scaleY = height/elem.bounds.height;
   elem.scale(scaleX,scaleY); 
}

Is the a way to use something like:

this.animate({
 properties: {
  scale: {
    x: 2.554
    y: 1.443
   }
  },
  settings: {
   duration: 400
  }
 });

Thanks guys.

Animate "rotate" with reference point

This is more of a suggestion rather than an issue. I saw in your tween.js source file that you're looking for a way to add parameters to the rotate animation. I extended the property hook with the following to get the desired result by adding a referencePoint value in the animation's settings property.

Here's my code:

  // Override rotate hook to support a reference point in animations
  animatePaper.extendPropHooks({
    rotate: {
        get: function(tween) {
            if (!tween.item.data._animatePaperVals) {
                tween.item.data._animatePaperVals = {};
            }
            if (typeof tween.item.data._animatePaperVals.rotate === "undefined") {
                tween.item.data._animatePaperVals.rotate = -0;
            }
            var output = tween.item.data._animatePaperVals.rotate;
            return output;
        },
        set: function(tween) {
            var curRotate = tween.item.data._animatePaperVals.rotate;
            var trueRotate = tween.now - curRotate;
            tween.item.data._animatePaperVals.rotate = tween.now;
            if (typeof tween.A.settings.referencePoint === "underfined") {
              tween.item.rotate(trueRotate);
            } else {
              tween.item.rotate(trueRotate, tween.A.settings.referencePoint);
            }
        }
    }});

And here's my example of the "revolve" animation with the specified referencePoint value:

revolve: function(target, referencePoint, loop) {
      target.animate([{
        properties: {
          rotate: 360
        },
        settings: {
          referencePoint: referencePoint,
          duration: 5000,
          easing: "linear",
          step: function(percent) {
            //console.log(percent, target.data._animatePaperVals.rotate);
            updateBoundingBox();
          },
          complete: function() {
            // Hack to fix rotation issues
            target.data._animatePaperVals.rotate = 0;
            if (!loop) return;
            ANIMATE.revolve(target, referencePoint, loop);
          }
        }
      }]); }

(Eartz: edited for styling)

why is 0 as duration not allowed? [question]

Is there a technical reason to only allow settings.durationvalues >= 1?
its explicitly checked for in animation.js#L268
for some of my animation sequences i would like to use duration: 0 to make hard jumps. and sometimes it seams to me that the duration:1 is visible..

Support animation "loop"

Could you please add basic support for looping animations?

Maybe add a new "loop" setting on the animation object that supports a true/false value for infinite / no loop [default]. Also, a "nice to have" would also be to support numeric values for X number of loops.

Thanks!

repeat for multiple Animation Steps (= repeat Group) [enhancement]

hi Eartz,
i like your solution for #5 (Support animation "loop")
for me currently most of the time i have some small animation sequences that needs to repeat.
for example:

  • fadein
  • pulse (repeat)
    • opacity 0.5
    • opacity 1
  • fadeout

so would be great if something like this is supported...
as Animation configuration this could look something like this:

animatePaper.animate(item, [
    // fade in
    {
        properties: {
            opacity: 1,
        },
        settings: {
            duration: 500,
        }
    },
    // pulse
    {
        properties: {
            scale: 1.5,
        },
        settings: {
            duration: 100,
            repeatGroupStart: 42,
        }
    },
    {
        properties: {
            scale: 1,
        },
        settings: {
            duration: 900,
            repeatGroupEnd: 42,
            repeat: true,
            complete: () => {
                console.log("loop done :-)");
            }
        }
    },
    // fade out
    {
        properties: {
            scale: 1,
            opacity: 0,
        },
        settings: {
            duration: 500,
            complete: () => {
                console.log("sequence done :-)");
            }
        }
    }
]);

here i have use two new settings: repeatGroupStart and repeateGroupEnd.
the idea is to define a repeat group with an id so you can have multiple groups.
so if an animation step ends it can check if it contains an repeatGroupEnd setting.
If this is true it reads the ID of this and checks if the needed loop_count is reached. if reached it starts the next animation step. If it has to repeat it starts the animation that contains the repeatGroupStart setting. (i think this has to be 'cached/saved' earlier...)
with this settings it would also be possible to nest these loops...
if an loop repeats infinite you can exit it with a simple next() or end() call - this would mean it just finishes the current running animation steps and exits the infinite loop to do the next step in the list.
(internally i think its possible to do this with 'just' setting the repeat count of the innermost running loop to 0.)

This are just 'out of my head' ideas..

pleas let me know if you think it makes sens to include something like this in the library itself or if its better to write something like this on top / externally.

animate position strange behavior

i tried to use the position animation.
based on the example given in the documentation.
changed to use absolute values - idea is that the box slideds to the position where you clicked with your mouse-cursor.
but the box does only the y property - the x is set to the same value as the y. so it slieds from the top left down-right in 45° up to the height where you click. that seems strange..
i have uploaded my example at
animation_simple.html
/js/animation_simple..js

basically i do the following:

    moveToPosition(event) {
        const position_new = new paper.Point(event.clientX, event.clientY);
        this.rect0.animate({
            properties: {
                position: position_new
            },
            settings: {
                duration: 500,
                easing: "swing"
            }
        });
    }

i also tried with

   moveToPosition(event) {
        this.rect0.animate({
            properties: {
                position: {
                    x: event.clientX,
                    y: event.clientY,
                }
            },
            settings: {
                duration: 500,
                easing: "swing"
            }
        });
    }

both had the same behavior.

is this a bug or have i missed something/didn't understand the concept?

Rotate animation only works once

When using the "rotate" property, I noticed that it can only be fired one time and subsequent rotation animations would never actually rotate (if re-using the same rotation angle). When logging the target object's data._animatePaperVals.rotate value, it would always properly adjust during the first animation. After that, it would always be the value that the property was set to.

A fix that I came up with (which is just a hack) is to use the complete callback and set the target object's data._animatePaperVals.rotate value to 0. This would allow subsequent animations to rotate properly.

target.animate({ properties: { rotate: 360 }, settings: { duration: 1000, easing:"linear", step: function(percent) { console.log(percent, target.data._animatePaperVals.rotate); updateBoundingBox(); }, complete: function() { target.data._animatePaperVals.rotate = 0; console.log(target.data._animatePaperVals.rotate); } } });

Browserify/AMD compatibility

This library is using 'paper' as dependency, but if 'paper' is loaded through Browserify paper doesn't load, so try to use require also:

// line 5
var paper = global.paper; // require('paper');

easing - is there a list of buildin functions?

I would like to know what easing functions are build in - and what they do -
is there some comparsion at som point available or a simple text list of possible values for build in functions?
from the examples i found

additionally in the source of easing.js there seems to be a bunch of additional variants -

  • linear
  • swing
  • Sine
  • Circ
  • Elastic
  • Back
  • Bounce
    and
  • Quad
  • Cubic
  • Quart
  • Quint
  • Expo
    for this some of the names makes some sense to me - but i don't know the math behind these things..
    after this there seems to be some 'combined' ones but i don't understand how this works or what they do... :-?
  • easeIn + name
  • easeOut + name
  • easeInOut + name

can you give some hints on this please :-)

allow for absolute negative position values

with the current 'relative animation' system it is not possible to for example move a item to a absolute position that is outside of the top/left space of the canvas. this absolute positions are negative and will therefore be interpreted as relative values.

i have made an example at js/animation_simple.js#L164
expected result: move rect to [200, 200] (fully visible) then move it to [-100, 200] (half visible)

fix for this would be to define that relative values must be strings and absolute values are Numbers.

i try to fix this in fixAbsoluteNegativePositions

add easing-option for CSS-style cubic-bezier curves

feature-request:
add support for Cubic Bezier Curves for easing like in CSS.
so that it is possible to add the Bezier Values directly in the settings - something like

animatePaper.animate(itemXX, [
    {
        properties: {
            opacity: 1,
        },
        settings: {
            duration: 500,
            easing: BezierEasing(0, 0, 1, 0.5),
        }
    }
]);

(eventually namespace the BezierEasing class under the animatePaper global. but this eventually would prevent optimization for bundling...)
library i found that could help with this:
https://github.com/gre/bezier-easing

additional information on cubic bezier & easing & editors
http://cubic-bezier.com/#.2,0,.8,1
http://easings.net/

[question] Why is it not possible to animate Group fillColor?

as the title asks - Why is it not possible to animate the fillColor of a Group?
this is a 'mandatory' feature to be able to work with imported svg files - as they are heavily structured with groups...

i understand that i have to fist define the fillColor of the group so it can be animated. but i have done this as in

    const group_active = new paper.Group([
            group_sub,
            step0_layer.children.Gx,
        ]);
        group_active.name = "group_active";
        step0_layer.addChild(group_active);
        // define fillColor
        group_active.fillColor = {
            red: 0.6,
            green: 0.7,
            blue: 0.7,
        };
        const ani_item = group_active;
        animatePaper.stop(ani_item);
        animatePaper.animate(ani_item, [
            {
                properties: {
                    fillColor: {
                        red: 0.9,
                        green: 0.1,
                        blue: 0.1,
                    },
                },
                settings: {
                    duration: 500,
                    easing: "swing",
                    complete: () => {
                        console.log("done :-)");
                    }
                }
            }
        ]);

and if i try it i get a TypeError: tween.item[tween.prop] is undefined in _tweenPropHooks.Color.set

would it be possible to add this with the Extend property hooks option?
is there somewhere an concrete example on how to implement a new hook?
the documentation is missing an example how to actual implement the set / get / ease functions..
but i will try and experiment with it... hope this works ;-)

sunny greetings stefan

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.