chenqingspring / ng-lottie

Render After Effects animations on Angular based on lottie-web
MIT License
340 stars 100 forks source link

How to switch animation after initialization? #23

Open laulaaa opened 6 years ago

laulaaa commented 6 years ago

Hello. I'm trying to figure out how to switch animation after initialization, but I don't see it in the documentation. Is it possible?

I found the same question in airbnb/ios. Here is the reference: LINK

Right now, I'm reloading the component of the animation using *ngif hiding and showing it again, it works, but not always. I'm looking for a better solution.

1pocketaces1 commented 6 years ago

Hi @laulaaa if you notice Im the one who asked in that ios thread how to do it for angular hah. So far the solution I have implemented is not ideal for loading times but it performs okay after initialization.

This performs fine after the views are initialized as the CSS changes in the "off" class do not trigger screen re-draws, and only one animtion is playing at one time. I have used this to allow a user to win a prize, and in the prize display I have all of the different prize animations, and I switch to the one that is won upon its display.

Hope this maybe helps as a temporary fix!

1pocketaces1 commented 6 years ago

And maybe it helps or doesnt but in the JS, I keep a variable to hold an ID for whichever animation is currently on, which helps with making the necessary changes

rccueva commented 5 years ago

Hi, please help.. I need the solution too.

kmturley commented 5 years ago

According to the documentation here: http://airbnb.io/lottie/#/web?id=html-player-installation

Available methods are:

anim.play() 
anim.stop() 
anim.pause() 
anim.setLocationHref(locationHref) 
anim.setSpeed(speed) 
anim.goToAndStop(value, isFrame)
anim.goToAndPlay(value, isFrame)
anim.setDirection(direction)
anim.playSegments(segments, forceFlag)
anim.setSubframe(flag)
anim.destroy()

So i'm guessing you would use them with ng-lottie by using the html: <lottie-animation-view class="animation" [options]="lottieConfig" (animCreated)="animCreated($event)"></lottie-animation-view>

And then the function:

animCreated(anim: any) {
  this.anim = anim;
  console.log('animCreated', anim);
}

and then later:

animLoad(url) {
  console.log('animLoad', url);
  if (this.anim) {
    this.anim.destroy();
  }
  this.lottieConfig = {
    path: url,
    renderer: 'canvas',
    autoplay: false,
    loop: false
  };
}

But doesn't seem to work for me...as destroy seems to destroy lottie instance but not reset the angular element.

Inspecting the lottie instance there are these methods available:

addEventListener: ƒ _addEventListener(t,e)
addPendingElement: ƒ ()
adjustSegment: ƒ (t)
advanceTime: ƒ (t)
checkLoaded: ƒ ()
checkSegments: ƒ ()
configAnimation: ƒ (t)
destroy: ƒ (t)
elementLoaded: ƒ ()
getAssetData: ƒ (t)
getAssets: ƒ ()
getAssetsPath: ƒ (t)
getPath: ƒ ()
goToAndPlay: ƒ (t,e,r)
goToAndStop: ƒ (t,e,r)
gotoFrame: ƒ ()
hide: ƒ ()
includeLayers: ƒ (t)
loadNextSegment: ƒ ()
loadSegments: ƒ ()
moveFrame: ƒ (t,e)
pause: ƒ (t)
play: ƒ (t)
playSegments: ƒ (t,e)
remove: ƒ (t)
removeEventListener: ƒ _removeEventListener(t,e)
renderFrame: ƒ ()
resetSegments: ƒ (t)
resize: ƒ ()
setCurrentRawFrameValue: ƒ (t)
setData: ƒ (t,e)
setDirection: ƒ (t)
setParams: ƒ (t)
setSegment: ƒ (t,e)
setSpeed: ƒ (t)
setSubframe: ƒ (t)
show: ƒ ()
stop: ƒ (t)
togglePause: ƒ (t)
trigger: ƒ (t)
triggerEvent: ƒ _triggerEvent(t,e)
updaFrameModifier: ƒ ()
updateAnimation: ƒ (t)
waitForFontsLoaded: ƒ ()

When resetting an animation it looks as though you have to do destroy then loadAnimation:

animation.destroy();
lottie.loadAnimation();

Example: https://codepen.io/kmtbynd/project/editor/Zrzqyj

which ng-loggie doesn't seem to have support for.

I managed to kind of get it working by modifying ng-lottie:

import { Component, Input, OnInit, Output, EventEmitter, ViewChild, ElementRef, PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformServer } from '@angular/common';

declare let require: any;
const lottie: any = require('lottie-web/build/player/lottie.js');

@Component({
  selector: 'app-lottie-animation-view',
  template: `<div #lavContainer [ngStyle]="{'width': viewWidth, 'height': viewHeight, 'overflow':'hidden', 'margin': '0 auto'}"></div>`
})

export class LottieAnimationViewComponent implements OnInit {
  private anim: any;
  public viewWidth: string;
  public viewHeight: string;
  private optionsData: any;

  @ViewChild('lavContainer') lavContainer: ElementRef;
  @Input() width: number;
  @Input() height: number;
  @Input()
  set options(options: any) {
    this.optionsData = {
      container: this.lavContainer.nativeElement,
      renderer: options.renderer || 'svg',
      loop: options.loop !== false,
      autoplay: options.autoplay !== false,
      autoloadSegments: options.autoloadSegments !== false,
      animationData: options.animationData,
      path: options.path || '',
      rendererSettings: options.rendererSettings || {}
    };
    this.load();
    console.log('optionsData', this.optionsData);
  }
  @Output() animCreated: any = new EventEmitter();

  constructor(
    @Inject(PLATFORM_ID) private platformId: string
  ) { }

  ngOnInit() {
    if (isPlatformServer(this.platformId)) {
      return;
    }
  }

  load(path?: string) {
    if (this.anim) {
      this.anim.destroy();
    }
    if (path) {
      this.optionsData.path = path;
    }

    this.viewWidth = this.width + 'px' || '100%';
    this.viewHeight = this.height + 'px' || '100%';

    this.anim = lottie.loadAnimation(this.optionsData);
    this.animCreated.emit(this.anim);
  }

  ngOnDestroy() {
    if (this.anim) {
      this.anim.destroy();
    }
  }
}

Usage: import { LottieAnimationViewModule } from './shared/lottieAnimationView.module';

and: <app-lottie-animation-view #animation class="animation" [options]="lottieConfig" (animCreated)="animCreated($event)"></app-lottie-animation-view>

FloLech commented 4 years ago

Any update on this? I ran into the same issue.