动画

Add some well designed animations to build stunning graph.

Guide

Basically an animation is described by two 2 keyframes,
to make it more clear, it’s like something from width 200 to width 300, it will last 200ms.
You will create an animation with initial width 200.
When you start the animation, you will set a duration to 200ms, and the target is width 300. You keep getting intermediate values by updateAnimation when the animation is running.

We exposed a simple animation API in animation directory,
however, the other parts of the Pattaya does not depend on the animation,
so you can intergrate any other third-party animation libs if you don’t like the default one,
and it will not be packed into your graph because of the minimize dependencies policy.

1. Create Animation

To create an animation, you should create an animation first, it’s basically the size, color or some countable properties.

// state1 => state2
// or: state2 => state1
const state1 = { width: 200 };
const state2 = { width: 300 };

// easeInOut is easing function control the animation intermediate state
// it's like the CSS ease-in, ease-out, ease-in-out...
const ani = newAnimationStore(state1, easing.easeInOut),

2. Start Animation

If user click a button, or a timer timeout, you will start the animation. You need to set a duration and a final state.

onClick() {
  // start the animation, hope it will last 200ms, and it will finally change to state2
  startAnimation(ani, 200, state2);
}

3. Update Animation and Graph

When your graph should re-render, or just keep rendering each frame,
you can update your graph according to animation.

update the graph in Update callback in the most of the time,
updating with setInterval in not recommended, because the intermediate state will not be re-rendered immediately, it will waste CPU resource, but it still works.

update(timestamp) {
  // ani is our animation, you can get it from your code, or you can store it in data field of the element (get it from "this.data").
  const currentState = updateAnimation(ani, timestamp);
  // state now: width could be between (200, 300), for example: 280
  // you can set the width of a rectangle to 280 to render the animation
  console.log(currentState.width);
}

4. Check the Animation State

Sometime you may want to know if the animation has finished.

// running ?
console.log(animationRunning(ani));
// finished ?
console.log(animationCompleted(ani));

Example

const mutedStyle = {
  color: "rgba(200, 200, 200, 1)",
  fontColor: "rgba(100, 100, 100, 1)",
  scale: 0.9,
};

const activeStyle = {
  color: "rgba(255, 255, 255, 1)",
  fontColor: "rgba(20, 20, 20, 1)",
  scale: 1.0,
}

const n: ShadowElement = {
  x: 240,
  y: 120,
  shapes: [{
    path: nodes.rectangle.wireframe({ width: 160, height: 60, radius: 6 }),
    opts: {
      fill: mutedStyle.color,
      scale: mutedStyle.scale,
      border: false,
    }
  }],
  contain: rectContain(160, 60),
  data: newAnimationStore(mutedStyle, easing.easeInOut),
  texts: [{
    content: "Search",
    opts: {
      fill: mutedStyle.fontColor,
      font: "16px Arial",
      textAlign: "center",
      textBaseline: "middle",
    },
  }],
  update(ts) {
    const current = updateAnimation(this.data, ts);
    const opts = this.shapes[0].opts;
    const textOpts = this.texts[0].opts;
    opts.fill = current.color;
    opts.scale = current.scale;
    textOpts.fill = current.fontColor;
  },
  onMouseenter(render) {
    startAnimation(this.data, 250, activeStyle);
  },
  onMouseleave(render) {
    startAnimation(this.data, 250, mutedStyle);
  }
};

const graph = new Graph();
graph.onReady(() => {
  graph.updateLayerOptions(0, { dynamic: true, update: true });
  graph.resetGraph([[n]]);
});