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

canvas回放时img空白 #851

Closed
pjxxcc opened this issue Mar 3, 2022 · 11 comments · Fixed by #859
Closed

canvas回放时img空白 #851

pjxxcc opened this issue Mar 3, 2022 · 11 comments · Fixed by #859
Assignees
Labels
bug Something isn't working

Comments

@pjxxcc
Copy link

pjxxcc commented Mar 3, 2022

问题

canvas回放时里面的img部分显示空白,控制台可以看到如下打印:

index.mjs?c1c8:29 [replayer] Has error on update canvas '1027' Object TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or OffscreenCanvas or SVGImageElement or VideoFrame)'.
    at e.applyIncremental (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:30:27725)
    at n (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:30:17695)
    at eval (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:30:18455)
    at Object.doAction (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:30:5036)
    at r (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:16:22300)

排查发现是因为录制的canvas事件中带有一个img元素:

{"type":3,"data":{"source":9,"id":978,"property":"drawImage","args":[img,-129.3076171875,-13,26,26]},"timestamp":1646289935254}

经过JSON.stringify转为json字符串后,dom元素img被处理成了{}

{"type":3,"data":{"source":9,"id":978,"property":"drawImage","args":[{},-129.3076171875,-13,26,26]},"timestamp":1646289935254}

解决

目前想到的方案是在JSON.stringify中对dom元素做转换,仅保留必要的属性,然后在JSON.parse时再逆向恢复为dom元素:

JSON.stringify(item, (name, value) => {
  if (value instanceof HTMLImageElement) {
    return { isHTMLImageElement: true, src: value.src };
  }
  return value;
})

这个方案应该能解决问题,但是感觉不是最佳方案。
我看本项目的文档示例中也是对录制数据进行JSON.stringify处理后存放,是否应该在rrweb.record得到的envent中不返回dom元素,而是简单的数据对象呢?

@YunFeng0817
Copy link
Member

@Juice10 https://github.com/rrweb-io/rrweb/blob/master/packages/rrweb/src/record/observers/canvas/2d.ts#L45-L59
I guess the cause for this issue is that if the recordArgs[0] is an image, it won't get serialized.

@YunFeng0817 YunFeng0817 added the bug Something isn't working label Mar 3, 2022
@Juice10 Juice10 self-assigned this Mar 3, 2022
@Juice10
Copy link
Contributor

Juice10 commented Mar 3, 2022

@Mark-Fenng I'm working on a version that uses the (webgl) serializer that support capturing image arguments. I'm hoping to be done in the next couple days with it. Keep an eye on the canvas-fps branch.

@pjxxcc
Copy link
Author

pjxxcc commented Mar 3, 2022

thanks.

@naimao001
Copy link

问题

canvas回放时里面的img部分显示空白,控制台可以看到如下打印:

index.mjs?c1c8:29 [replayer] Has error on update canvas '1027' Object TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or OffscreenCanvas or SVGImageElement or VideoFrame)'.
    at e.applyIncremental (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:30:27725)
    at n (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:30:17695)
    at eval (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:30:18455)
    at Object.doAction (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:30:5036)
    at r (webpack-internal:///./node_modules/rrweb-player/dist/index.mjs:16:22300)

排查发现是因为录制的canvas事件中带有一个img元素:

{"type":3,"data":{"source":9,"id":978,"property":"drawImage","args":[img,-129.3076171875,-13,26,26]},"timestamp":1646289935254}

经过JSON.stringify转为json字符串后,dom元素img被处理成了{}

{"type":3,"data":{"source":9,"id":978,"property":"drawImage","args":[{},-129.3076171875,-13,26,26]},"timestamp":1646289935254}

解决

目前想到的方案是在JSON.stringify中对dom元素做转换,仅保留必要的属性,然后在JSON.parse时再逆向恢复为dom元素:

JSON.stringify(item, (name, value) => {
  if (value instanceof HTMLImageElement) {
    return { isHTMLImageElement: true, src: value.src };
  }
  return value;
})

这个方案应该能解决问题,但是感觉不是最佳方案。 我看本项目的文档示例中也是对录制数据进行JSON.stringify处理后存放,是否应该在rrweb.record得到的envent中不返回dom元素,而是简单的数据对象呢?

我也出现这个问题了 楼主最后解决了吗 你那个解决方案 你试了 行得通吗 英语不好 看不懂楼下那个大神说的 他正在开发的canvas-fps分支 怎么整

@YunFeng0817
Copy link
Member

@naimao001 他说正在开发的那个分支解决了这个问题,等一段时间这个分支合并到主分支后就会发布一个新的版本

@naimao001
Copy link

@naimao001 他说正在开发的那个分支解决了这个问题,等一段时间这个分支合并到主分支后就会发布一个新的版本

好的,这个问题只是回放时候的问题是吧,大佬解决了 原来录屏的events就正常可以回放出来了吧

@YunFeng0817
Copy link
Member

@naimao001 他说正在开发的那个分支解决了这个问题,等一段时间这个分支合并到主分支后就会发布一个新的版本

好的,这个问题只是回放时候的问题是吧,大佬解决了 原来录屏的events就正常可以回放出来了吧

应该是在录制时的问题,录制出来的数据中

{"type":3,"data":{"source":9,"id":978,"property":"drawImage","args":[{},-129.3076171875,-13,26,26]},"timestamp":1646289935254}

args的第一个参数是空的{},需要等待问题解决后才能录制出正确的数据

@pjxxcc
Copy link
Author

pjxxcc commented Mar 10, 2022

@naimao001 我的那个方案可以解决呀,我就那么处理的,将img元素只保留src属性就行,然后加一个标记字段便于回放的时候识别并恢复成img元素就行。

@pjxxcc
Copy link
Author

pjxxcc commented Mar 10, 2022

当然也可以参考rrweb源码中的方式把img转换为base64数据之后再存,这样以后回放时不依赖外部链接

@naimao001
Copy link

@pjxxcc @Mark-Fenng

image
我这个好像还不太一样哎 我是用了vue-pdf 插件

@Juice10
Copy link
Contributor

Juice10 commented Mar 10, 2022

#859 should fix this issue. Both with recordCanvas set to true (as you are recording now), or with recordCanvas set to a number (example: 10).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants