dotlottie-web icon indicating copy to clipboard operation
dotlottie-web copied to clipboard

Failed to construct 'ImageData': The source width is zero or not a number.

Open sulram opened this issue 1 year ago • 3 comments

Overview

Error that's occuring wrapper with display:none and framer motion of a <DotLottieReact /> component

Failed to construct 'ImageData': The source width is zero or not a number.

Sometimes

Consuming repo

What repo were you working in when this issue occurred?

@lottiefiles/dotlottie-react

sulram avatar Jun 21 '24 18:06 sulram

Hi @sulram, when using display: none, the width and height of the DotLottieReact canvas are set to zero, causing the error.

You can use the hidden prop directly on the DotLottieReact component. This keeps the component in the DOM without rendering it visibly:

<DotLottieReact hidden ... />

also you can use other CSS properties like visibility or opacity:

<DotLottieReact style={{ visibility: 'hidden' }} ... />
<DotLottieReact style={{ opacity: 0 }} ... />

theashraf avatar Jun 22 '24 06:06 theashraf

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs.

github-actions[bot] avatar Aug 22 '24 01:08 github-actions[bot]

I experience this issue with Web using vanilla JS, but the parent element also need to be set to display none because I'm working on a mobile nav which at the desktop screen should be hidden. Is there any other workaround to it?

Idowu-Adelekee avatar Sep 06 '24 14:09 Idowu-Adelekee

Still getting this issue with the following code:

import { Wordmark } from "@dub/ui";
import { DotLottieReact } from "@lottiefiles/dotlottie-react";

export default function AnimatedWordmark() {
  return (
    <div className="group relative h-6">
      <Wordmark className="absolute h-6 group-hover:opacity-0" />
      <DotLottieReact
        src="https://lottie.host/f53c93bf-8ae7-4f55-a73e-fbdf36e5c062/4KoxyK0Ruc.json"
        playOnHover
        loop
        className="absolute h-6 opacity-0 group-hover:opacity-100"
      />
    </div>
  );
}

steven-tey avatar Oct 13 '24 02:10 steven-tey

Thanks @steven-tey for the code, I'll investigate it further

theashraf avatar Oct 14 '24 02:10 theashraf

Solution Found ✅

I encountered the same issue with NextJS. I attempted to use Telegram animated emojis (convert TGS to JSON). While the animation works fine for the top emoji, it fails for others and displays an error message ('ImageData': The source width is zero or not a number.) 🧐. I added the same code to the other emojis animation sections, and they all started working without any errors. 😅 I have no idea why the animation works after adding <div className=“flex flex-col items-center gap-1”></div> as the parent container.

Code with Error:

<div
  key={`div-${id}`}
  ref={ref}
  style={{ width: `${size}px`, height: `${size}px` }}
>
  {inView ? (
    <DotLottieReact
      id={id}
      data={jsonData}
      autoplay={autoplay}
      loop={loop}
      className={className}
      renderConfig={{
        autoResize: true,
      }}
    />
  ) : (
    <></>
  )}
</div>;
Screenshot

MacBook M2 Pro MAX 2024-12-07 at 21 07 45

Working Code:

<div className="flex flex-col items-center gap-1">
  <div
    key={`div-${id}`}
    ref={ref}
    style={{ width: `${size}px`, height: `${size}px` }}
  >
    {inView ? (
      <DotLottieReact
        id={id}
        data={jsonData}
        autoplay={autoplay}
        loop={loop}
        className={className}
        renderConfig={{
          autoResize: true,
        }}
      />
    ) : (
      <></>
    )}
  </div>
</div>;

MacBook M2 Pro MAX 2024-12-07 at 21 26 14

Malith-Rukshan avatar Dec 07 '24 15:12 Malith-Rukshan

I encounter the exact same problem. The issue is very simple to reproduce: it occurs everytime you init a DotLottie when the canvas given in parameter is not shown (display none for instance)

I set up a very simple codepen here: https://codepen.io/nyroDev/full/VYZQdGZ

When using "Init on shown element", it's working correctly, nothing to say here.

When using "Init on hidden element", the canvas given in the config is under a div which is hidden by CSS. When clicking on it, we have the error:
"Failed to load animation data from URL: https://lottie.host/0cbdb3ef-2fa5-4d1d-9e4e-f66c879e010d/D0bRr9d93F.lottie. IndexSizeError: Failed to construct 'ImageData': The source width is zero or not a number."

After trying to dig a little bit on it, I found out that width and height of canvas is read on init here.

So I added a third test which add width and height as attribute of the canvas.
This it not working too.

I guess there might be something elsewhere trying to get the dimensions of the canvas which return 0 when i'ts not displayed.

For now, this bug make it impossible to instantiate a dotLottie located on a DOM element which is not displayed.

nyroDev avatar Jan 09 '25 13:01 nyroDev

After digging more, I found the exact reason why it's occurring.

On load, when doing it in browser, a call to the resize function is done.

On this resize function, the native getBoundingClientRect function is used.
This function will always return everything to 0 when element is hidden (display none)

And the width/height of the canvas is then rewritten into the DOM.

So it reinitialize the value to 0/0 and that's where the bug starts...

In my opinion, the resize should not rewrite value to the DOM canvas.
Or maybe we should have a new RenderConfig setting to control that? Moreover, the first resize should NOT depends on getBoundingClientRect.
Regarding the latter resizes, I guess it should be OK to rely on this function.

Right now, I came up with a very dirty way to fix this bug.
Just before initializing the DotLottie instance, I'm overwriting the getBoundingClientRect to return the value expected by the library.

I updated the codepen to show the working result: https://codepen.io/nyroDev/full/VYZQdGZ

nyroDev avatar Jan 20 '25 21:01 nyroDev

Thanks, @nyroDev, for the detailed investigation and for documenting the issue so clearly.

A possible improvement could be to offload the decision of resizing to the render loop. By comparing the canvas drawing area's width and height with the internal framebuffer dimensions: • If they match, we proceed with rendering • If not, we leave the canvas dimensions as-is and adjust the frame buffer to align with the drawing area

And if the canvas width and height are zeros as in this case, then we can skip rendering.

This approach could potentially address the issue without rewriting values to the DOM canvas unnecessarily. but, I’ll need to test this thoroughly to ensure it handles all edge cases and remains backward-compatible with the current behavior.

As for adding a RenderConfig setting to control this, I think it’s a viable idea worth exploring to give users more flexibility over how resizing is handled

In my opinion, the resize should not rewrite value to the DOM canvas. Or maybe we should have a new RenderConfig setting to control that? Moreover, the first resize should NOT depends on getBoundingClientRect. Regarding the latter resizes, I guess it should be OK to rely on this function.

Thanks again for raising this and for providing a working example, it’s very helpful for debugging

theashraf avatar Jan 21 '25 05:01 theashraf

The fix will be available in dotlottie-react v0.12.3

theashraf avatar Jan 27 '25 14:01 theashraf

The fix will be available in dotlottie-react v0.12.3

And dotlottie-wc v0.4.4 If I undestood correctly.

Thanks @theashraf

nyroDev avatar Jan 27 '25 14:01 nyroDev

The fix will be available in dotlottie-react v0.12.3

And dotlottie-wc v0.4.4 If I undestood correctly.

Thanks @theashraf

@nyroDev yes

theashraf avatar Jan 27 '25 14:01 theashraf

@nyroDev I’ve used your example as a way to check if the fix is working—super helpful!

I’ve made a tiny update to the 3rd canvas example, where we need to call the resize method after the canvas becomes visible. Alternatively, you can pass a property to the renderConfig called autoResize, which should handle this case automatically as well

https://codepen.io/lottiefiles/pen/EaYGbQK

theashraf avatar Jan 27 '25 15:01 theashraf

I can confirm that the last release fix this bug. Thanks for the quick release!

@theashraf the resize seems to be NOT required.
On your codepen, it's actually commented (and was in the 2nd exemple anyway)

nyroDev avatar Jan 27 '25 17:01 nyroDev

@theashraf @nyroDev This issue has been fixed in the latest release but the quality of the dotLottie seems to be poor quality which renders instead of the earlier error. However, when i reload the page, the quality is what it is supposed to be

surejainam avatar Feb 10 '25 10:02 surejainam

Also this another error occurs which seems apparently related but has no effect on UI : IndexSizeError: Failed to construct 'ImageData': The input data length is not equal to (4 * width * height).

surejainam avatar Feb 10 '25 10:02 surejainam

I think dotlottie-vue still have this issue, add autoResize: true will still happen this issue. but even if this issue occur, not affect the animation display

Jadddxx avatar Jun 16 '25 04:06 Jadddxx