Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using dot-lottie player programatically, #45

Open
martinstender opened this issue Aug 14, 2022 · 10 comments
Open

Using dot-lottie player programatically, #45

martinstender opened this issue Aug 14, 2022 · 10 comments

Comments

@martinstender
Copy link

In the documentation, it says that the Lottie-player can be set and loaded programmatically. For better (or maybe worse), we still use requirejs, and using the 'bodymovin' player, this works just fine:

require(['https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.9.6/lottie.min.js'], (bodymovin) => {
        const player = bodymovin.loadAnimation({
        container: document.getElementById('abc123'),
        autoplay: false,
        renderer: 'svg',
        loop: false,
        animationData: 'some-json-here'});
});

I'm trying to do something similar with the dotlottie-player - something like this:

require(['https://unpkg.com/@dotlottie/player-component@1.0.0/dist/dotlottie-player.js'], (player) => {
            console.log('player is available - here:', player); <-- I see the player in the console ({PlayerState: {…}, PlayMode: {…} etc)
            player = document.querySelector('dotlottie-player-element'); <-- this exists
            player.load('url-to-dot-lottie-file.lottie');
            player.play();
});

But it doesn't seem to work. What am I missing? And is there more documentation available somewhere for programmatic use?

TIA :)
Martin

@martinstender
Copy link
Author

martinstender commented Sep 30, 2022

Anyone?

For layout reasons, I need to change the inner svg's 'preserveAspectRatio'-attribute to 'xMidYMid slice'.

So in order to know when the dotlottie-player is ready, I now have to use a mutationobserver on the <dotlottie-player> node, looking for attribute changes. Then start a short interval, that continuously check if that node contains the '_lottie' object, and if that objects 'isLoaded' property is 'true'.
First then, I can get to the svg-element.
Isn't there a better way?

@zsmithjc
Copy link

zsmithjc commented Dec 12, 2022

@martinstender

I am using a Vue 2.6 app and attempting to grab the dotlottie-player element on component load also does not work for me - it returns the HTML element, but none of the methods or events that the documentation says.

I am seeing the same thing as what you said - I have to load the lottie animation first (using the src prop) before I can grab the lottie object from the element - which essentially makes the entire "programmatic loading" feature worthless.

Quick mockup:

AnimationComponent.vue

<template>
  <dotlottie-player
    v-if="renderAnimationElement"
    ref="lottieAnimationElement"
    :src="animationURL"
  </dotlottie-player>
</template>

<script>
export default {
  data: () => ({
    animationURL: '',
    renderAnimationElement: false,
  }),

  mounted() {
    this.handleLottieAnimationLoad();
  },

  methods: {
    handleLottieAnimationLoad() {
      const lottieFileURL = "https://my-animations.com/lottiefile.lottie";

      this.animationURL = lottieFileURL;
      this.renderAnimationElement = true;

      await this.$nextTick();
      const lottieElement = this.$refs.lottieAnimationElement;

      // at this point you need to "wait" for the lottie data to be populated
      await this.waitForLottieAnimationLoaded();

      // now, you should be able to hook in to the methods and events
      // initially advertised
    },

    async waitForLottieAnimationLoaded() {
      return new Promise(resolve => {
        // in here, create an `setInterval` that attempts to grab the lottie instance
        // using `lottieElement.getLottie()` and then the `isLoaded` field off of that.

        // Inspect the object returned from `lottieElement.getLottie()` for more info
        // Once you get `true` for `lottieElement.getLottie()`, you can resolve the promise
        // and clear the `setInterval`

        resolve();
      });
    }
  }
};
</script>

Honestly, the documentation for this lottie module and many others is poor. It's barebones at best and leaves out crucial implementation details and "gotchas" like this one.

You also can't supply a dummy URL to src in order to initialize lottie either - it needs to be a working lottie file URL.

@samuelOsborne
Copy link
Contributor

samuelOsborne commented Dec 20, 2022

hey @zsmithjc sorry for the frustration. I'll look in to bettering this.

But within your example, I think you can replace 'waitForLottieAnimationLoaded' with an event listener:

lottieElement.addEventListener('ready', () => {
 lottieElement.getLottie()
});

This is how I do it with React:

https://codesandbox.io/s/lotties-always-loop-false-forked-p70hnz?file=/src/App.tsx

@martinstender
Copy link
Author

martinstender commented Jan 3, 2023

Thank you, @samuelOsborne - that helped me a lot as well :)

Maybe you could point me in the right direction with another small issue I have:

With the bodymovin-player, I can do something like this:

const player = bodymovin.loadAnimation({
container: container,
autoplay: true,
renderer: 'svg',
loop: true,
rendererSettings: {
preserveAspectRatio: 'xMidYMid slice'
},
path:'https://path-to-json.json'
});

Is it possible to reach the 'rendererSettings' object with dot-lottie player in the same manner?
Right now I wait for the 'ready' event to fire, and then I go:
lottieElement._lottie.wrapper.querySelector('svg').setAttribute('preserveAspectRatio','xMidYMid slice');

It would be nice to be able to set it up correctly before it is created in the page.

Best regards

@samuelOsborne
Copy link
Contributor

hey @martinstender yes if you use the load method, you can pass an object that will be passed to the renderSettings:

For example:

      let firstPlayer = document.getElementById('one');

      firstPlayer.load('https://lottie.host/cba131d3-3e01-43be-b71c-2de700a12642/c5CK9Co8WD.json', {
        filterSize: {
          width: '200%',
          height: '200%',
          x: '-30%',
          y: '-30%',
        },
      });

@martinstender
Copy link
Author

Thank you, @samuelOsborne - can I set autoplay, loop etc. the same way?

@zsmithjc
Copy link

zsmithjc commented Feb 2, 2023

@samuelOsborne so, trying out your suggestion to replace the setInterval with an event listener on the element:

async handleLottieAnimationLoad() {
  ...

  await this.waitForLottieAnimationLoaded();
},

...

async waitForLottieAnimationLoaded() {
  return new Promise(resolve => {
    // errors below, citing TypeError: Cannot read properties of undefined (reading 'addEventListener')
    this.$refs.lottieAnimationElement.addEventListener('ready', () => {
      console.log('ready');
      resolve();
    });
},

Attempting to use this.$refs.lottieAnimationElement.getLottie().addEventLister also does not work, citing the same error but on getLottie(). Using @dotlottie/player-component v1.3.1.

Using the pre-existing interval is the only way I've seen to know when the element is loaded in - as the loading of the animation determines when methods like addEventListener are available. Maybe this is just a Vue thing.

@samuelOsborne
Copy link
Contributor

@zsmithjc Your listener shouldn't be on getLottie() but the lottieAnimationElement. Could you try that out?

@zsmithjc
Copy link

zsmithjc commented Feb 3, 2023

@samuelOsborne yes, I tried that in the code snippet.

this.$refs.lottieAnimationElement.addEventListener('ready', () => { ...

I was just saying neither option works before the animation loads in, and only lottieAnimationElement after the animation has loaded in.

@theashraf
Copy link
Member

Please have a look at the dotlottie react player -> https://www.npmjs.com/package/@dotlottie/react-player

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants