svga/SVGAPlayer-Web-Lite

何时能支持svga2.0呢

haliluya4 opened this issue · 7 comments

目前播放2.0版的svga动画,会直接报错。用SVGAPlayer-Web就可以播。

Uncaught TypeError: Cannot read properties of undefined (reading 'replace')
at drawBezier (index.min.js:2:1)
at drawShape (index.min.js:2:1)
at eval (index.min.js:2:1)
at Array.forEach ()
at drawSprite (index.min.js:2:1)
at eval (index.min.js:2:1)
at Array.forEach ()
at render (index.min.js:2:1)
at e.drawFrame (index.min.js:2:1)
at animator.onUpdate (index.min.js:2:1)

wcldyx commented

目前播放2.0版的svga动画,会直接报错。用SVGAPlayer-Web就可以播。

Uncaught TypeError: Cannot read properties of undefined (reading 'replace') at drawBezier (index.min.js:2:1) at drawShape (index.min.js:2:1) at eval (index.min.js:2:1) at Array.forEach () at drawSprite (index.min.js:2:1) at eval (index.min.js:2:1) at Array.forEach () at render (index.min.js:2:1) at e.drawFrame (index.min.js:2:1) at animator.onUpdate (index.min.js:2:1)

大佬有找到解决方案吗?,我这边也遇到同样的问题

Naeemo commented

可以提供一下 svga 文件。2.0应该是支持的,可能是个问题。

可以提供一下 svga 文件。2.0应该是支持的,可能是个问题。

可以试下这个,把后缀名改成svga就行。因为github不支持上传svga的,所以后缀名改成gif上传了。

收藏 svga

Naeemo commented

@haliluya4 用的什么版本?我用 master 分支试验可以正常播放。

2.1.0的,通过npm install svga --save安装的。
在vue2的项目里,即使将这个文件放在public目录下,通过this.parser.load("./xxx.svga")的方式加载后,播放也是报同样的错。看起来文件是正常加载了,但是播放时出问题了。我们有其他的svga动画,也是2.0版本,也能正常播。
就是部分会报错。

代码类似以下这种

<canvas ref="player" v-if="localUrl"></canvas>

import { Parser, Player } from "svga";

      this.localUrl = "./xxx.svga";
      this.parser = new Parser();
      this.parser.load(this.localUrl).then((svga) => {
        if (this.isDestroyed) {
          return;
        }
        if (!svga) {
          console.error(`svga数据加载异常 ${this.localUrl}`);
          return;
        }

        this.player = new Player(this.$refs.player as HTMLCanvasElement);
        this.player.mount(svga).then(() => {
          if (this.isDestroyed || !this.player) {
            return;
          }

          this.player.start();
        });
      });
    });

image

能否提供一个最小能重现的 Github Repo 地址带上有问题的 SVGA 文件?

能否提供一个最小能重现的 Github Repo 地址带上有问题的 SVGA 文件?

你好,我在使用svga的时候,遇到了同样的问题,经排查定位到问题出在是render.ts里的drawBezier函数,该函数的第二个入参d,replace操作没有处理d为undefined的异常,才导致运行时报错。以下是修改后的代码:

function drawSprite (
  context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
  sprite: VideoSprite,
  currentFrame: number,
  bitmap: Bitmap | undefined,
  replaceElement: ReplaceElement | undefined,
  dynamicElement: DynamicElement | undefined
): void {
  const frame = sprite.frames[currentFrame]

  if (frame.alpha < 0.05) return

  context.save()
  context.globalAlpha = frame.alpha

  context.transform(
    frame.transform?.a ?? 1,
    frame.transform?.b ?? 0,
    frame.transform?.c ?? 0,
    frame.transform?.d ?? 1,
    frame.transform?.tx ?? 0,
    frame.transform?.ty ?? 0
  )

  if (bitmap !== undefined) {
    if (frame.maskPath !== null) {
      drawBezier(context, frame.maskPath.d, frame.maskPath.transform, frame.maskPath.styles)
      context.clip()
    }
    if (replaceElement !== undefined) {
      context.drawImage(replaceElement, 0, 0, frame.layout.width, frame.layout.height)
    } else {
      context.drawImage(bitmap, 0, 0, frame.layout.width, frame.layout.height)
    }
  }

  if (dynamicElement !== undefined) {
    context.drawImage(dynamicElement, (frame.layout.width - dynamicElement.width) / 2, (frame.layout.height - dynamicElement.height) / 2)
  }

  // shape的path属性可能为空,所以需要判断
  frame.shapes.forEach(shape => drawShape(context, shape))

  context.restore()
}

function drawBezier (
  context: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
  d: string | undefined,
  transform: Transform | undefined,
  styles: VideoStyles
): void {
  context.save()
  resetShapeStyles(context, styles)
  if (transform !== undefined) {
    context.transform(
      transform.a,
      transform.b,
      transform.c,
      transform.d,
      transform.tx,
      transform.ty
    )
  }
  const currentPoint: CurrentPoint = { x: 0, y: 0, x1: 0, y1: 0, x2: 0, y2: 0 }
  context.beginPath()
  if (d !== undefined) {
    d = d.replace(/([a-zA-Z])/g, '|||$1 ').replace(/,/g, ' ')
    d.split('|||').forEach(segment => {
      if (segment.length === 0) return
      const firstLetter = segment.substr(0, 1)
      if (validMethods.includes(firstLetter)) {
        const args = segment.substr(1).trim().split(' ')
        drawBezierElement(context, currentPoint, firstLetter, args)
      }
    })
  }

  if (styles.fill !== null) {
    context.fill()
  }
  if (styles.stroke !== null) {
    context.stroke()
  }
  context.restore()
}