# # Progressive Line With Easing

const config = { type: 'line', data: { datasets: [{ borderColor: Utils.CHART_COLORS.red, borderWidth: 1, radius: 0, data: data, }, { borderColor: Utils.CHART_COLORS.blue, borderWidth: 1, radius: 0, data: data2, }] }, options: { animation, interaction: { intersect: false }, plugins: { legend: false, title: { display: true, text: () => easing.name } }, scales: { x: { type: 'linear' } } } };

    const config = {
      type: 'line',
      data: {
        datasets: [{
          borderColor: Utils.CHART_COLORS.red,
          borderWidth: 1,
          radius: 0,
          data: data,
        },
        {
          borderColor: Utils.CHART_COLORS.blue,
          borderWidth: 1,
          radius: 0,
          data: data2,
        }]
      },
      options: {
        animation,
        interaction: {
          intersect: false
        },
        plugins: {
          legend: false,
          title: {
            display: true,
            text: () => easing.name
          }
        },
        scales: {
          x: {
            type: 'linear'
          }
        }
      }
    };

let easing = helpers.easingEffects.easeOutQuad; let restart = false; const totalDuration = 5000; const duration = (ctx) => easing(ctx.index / data.length) * totalDuration / data.length; const delay = (ctx) => easing(ctx.index / data.length) * totalDuration; const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y; const animation = { x: { type: 'number', easing: 'linear', duration: duration, from: NaN, // the point is initially skipped delay(ctx) { if (ctx.type !== 'data' || ctx.xStarted) { return 0; } ctx.xStarted = true; return delay(ctx); } }, y: { type: 'number', easing: 'linear', duration: duration, from: previousY, delay(ctx) { if (ctx.type !== 'data' || ctx.yStarted) { return 0; } ctx.yStarted = true; return delay(ctx); } } };

    let easing = helpers.easingEffects.easeOutQuad;
    let restart = false;
    const totalDuration = 5000;
    const duration = (ctx) => easing(ctx.index / data.length) * totalDuration / data.length;
    const delay = (ctx) => easing(ctx.index / data.length) * totalDuration;
    const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y;
    const animation = {
      x: {
        type: 'number',
        easing: 'linear',
        duration: duration,
        from: NaN, // the point is initially skipped
        delay(ctx) {
          if (ctx.type !== 'data' || ctx.xStarted) {
            return 0;
          }
          ctx.xStarted = true;
          return delay(ctx);
        }
      },
      y: {
        type: 'number',
        easing: 'linear',
        duration: duration,
        from: previousY,
        delay(ctx) {
          if (ctx.type !== 'data' || ctx.yStarted) {
            return 0;
          }
          ctx.yStarted = true;
          return delay(ctx);
        }
      }
    };

const data = []; const data2 = []; let prev = 100; let prev2 = 80; for (let i = 0; i < 1000; i++) { prev += 5 - Math.random() * 10; data.push({x: i, y: prev}); prev2 += 5 - Math.random() * 10; data2.push({x: i, y: prev2}); }

    const data = [];
    const data2 = [];
    let prev = 100;
    let prev2 = 80;
    for (let i = 0; i < 1000; i++) {
      prev += 5 - Math.random() * 10;
      data.push({x: i, y: prev});
      prev2 += 5 - Math.random() * 10;
      data2.push({x: i, y: prev2});
    }

function restartAnims(chart) { chart.stop(); const meta0 = chart.getDatasetMeta(0); const meta1 = chart.getDatasetMeta(1); for (let i = 0; i < data.length; i++) { const ctx0 = meta0.controller.getContext(i); const ctx1 = meta1.controller.getContext(i); ctx0.xStarted = ctx0.yStarted = false; ctx1.xStarted = ctx1.yStarted = false; } chart.update(); } const actions = [ { name: 'easeOutQuad', handler(chart) { easing = helpers.easingEffects.easeOutQuad; restartAnims(chart); } }, { name: 'easeOutCubic', handler(chart) { easing = helpers.easingEffects.easeOutCubic; restartAnims(chart); } }, { name: 'easeOutQuart', handler(chart) { easing = helpers.easingEffects.easeOutQuart; restartAnims(chart); } }, { name: 'easeOutQuint', handler(chart) { easing = helpers.easingEffects.easeOutQuint; restartAnims(chart); } }, { name: 'easeInQuad', handler(chart) { easing = helpers.easingEffects.easeInQuad; restartAnims(chart); } }, { name: 'easeInCubic', handler(chart) { easing = helpers.easingEffects.easeInCubic; restartAnims(chart); } }, { name: 'easeInQuart', handler(chart) { easing = helpers.easingEffects.easeInQuart; restartAnims(chart); } }, { name: 'easeInQuint', handler(chart) { easing = helpers.easingEffects.easeInQuint; restartAnims(chart); } }, ];

    function restartAnims(chart) {
      chart.stop();
      const meta0 = chart.getDatasetMeta(0);
      const meta1 = chart.getDatasetMeta(1);
      for (let i = 0; i < data.length; i++) {
        const ctx0 = meta0.controller.getContext(i);
        const ctx1 = meta1.controller.getContext(i);
        ctx0.xStarted = ctx0.yStarted = false;
        ctx1.xStarted = ctx1.yStarted = false;
      }
      chart.update();
    }
    const actions = [
      {
        name: 'easeOutQuad',
        handler(chart) {
          easing = helpers.easingEffects.easeOutQuad;
          restartAnims(chart);
        }
      },
      {
        name: 'easeOutCubic',
        handler(chart) {
          easing = helpers.easingEffects.easeOutCubic;
          restartAnims(chart);
        }
      },
      {
        name: 'easeOutQuart',
        handler(chart) {
          easing = helpers.easingEffects.easeOutQuart;
          restartAnims(chart);
        }
      },
      {
        name: 'easeOutQuint',
        handler(chart) {
          easing = helpers.easingEffects.easeOutQuint;
          restartAnims(chart);
        }
      },
      {
        name: 'easeInQuad',
        handler(chart) {
          easing = helpers.easingEffects.easeInQuad;
          restartAnims(chart);
        }
      },
      {
        name: 'easeInCubic',
        handler(chart) {
          easing = helpers.easingEffects.easeInCubic;
          restartAnims(chart);
        }
      },
      {
        name: 'easeInQuart',
        handler(chart) {
          easing = helpers.easingEffects.easeInQuart;
          restartAnims(chart);
        }
      },
      {
        name: 'easeInQuint',
        handler(chart) {
          easing = helpers.easingEffects.easeInQuint;
          restartAnims(chart);
        }
      },
    ];

## # Api

- Chart
  - `getDatasetMeta`
- Scale
  - `getPixelForValue`

## # Docs

- Animations
  - animation
    - `delay`
    - `duration`
    - `easing`
    - `loop`
  - Easing
- Line
- Options
  - Scriptable Options
    - Data Context