基于有关如何将视频渲染到画布的
Konva
文档,我想通过直接从 Konva.Image
实例访问视频引用来播放视频。下面是一个人为的示例,用于模拟我从组件外部动态播放视频的目标。即使 imageRef.current.image()
返回视频元素引用,下面的内容也不会按预期播放视频。关于如何访问视频参考有什么建议吗?
import React, { useEffect, useContext, useState } from 'react'
import { Image } from "react-konva";
import Konva from 'konva'
export const MainVideo = ({ shape, dispatch }) => {
const imageRef = React.useRef(null);
const video = document.createElement('video');
video.setAttribute('src',shape.url);
useEffect(() => {
if(imageRef) {
imageRef.current.image().play();
const layer = imageRef.current.getLayer();
const anim = new Konva.Animation(() => {
}, layer);
anim.start()
}
}, [imageRef])
return (
<Image
ref={imageRef}
opacity={shape.o}
id={shape.id}
image={video}
x={shape.x}
y={shape.y}
zIndex={0}
height={360}
width={640} />
)
}
你可以这样做:
const Video = ({ src }) => {
const imageRef = React.useRef(null);
const [size, setSize] = React.useState({ width: 50, height: 50 });
// we need to use "useMemo" here, so we don't create new video elment on any render
const videoElement = React.useMemo(() => {
const element = document.createElement("video");
element.src = src;
return element;
}, [src]);
// when video is loaded, we should read it size
React.useEffect(() => {
const onload = function() {
setSize({
width: videoElement.videoWidth,
height: videoElement.videoHeight
});
};
videoElement.addEventListener("loadedmetadata", onload);
return () => {
videoElement.removeEventListener("loadedmetadata", onload);
};
}, [videoElement]);
// use Konva.Animation to redraw a layer
React.useEffect(() => {
videoElement.play();
const layer = imageRef.current.getLayer();
const anim = new Konva.Animation(() => {}, layer);
anim.start();
return () => anim.stop();
}, [videoElement]);
return (
<Image
ref={imageRef}
image={videoElement}
x={20}
y={20}
stroke="red"
width={size.width}
height={size.height}
draggable
/>
);
};
演示:https://codesandbox.io/s/react-konva-video-on-canvas-oygvf
import ReactDOM from "react-dom";
import React, { useEffect, useRef, useState } from "react";
import { Image, Layer, Stage } from "react-konva";
const VideoPlayer = () => {
const videoRef = useRef(null);
const [videoNode, setVidoeNode] = useState();
useEffect(() => {
const video = videoRef.current;
if (video) {
video.src =
"https://YOUR_VIDEO_LINK.mp4";
// Konva animation frame
const animate = () => {
if (video.paused || video.ended) {
return;
}
videoNode?.getLayer().batchDraw();
requestAnimationFrame(animate);
};
video.addEventListener("loadeddata", () => {
video.play();
animate();
});
}
}, [videoNode]);
return (
<>
<Stage width={window.innerWidth} height={window.innerHeight - 0.5}>
<Layer>
<Image
ref={(node) => {
setVidoeNode(node);
}}
image={videoRef.current}
width={window.innerWidth}
height={window.innerHeight - 0.5}
/>
</Layer>
</Stage>
<video ref={videoRef} hidden />
</>
);
};
export default VideoPlayer;
useEffect 挂钩用于设置视频播放和 Konva.js 集成。每当 videoNode 值发生变化时就会触发。 我们使用 videoRef 访问视频元素,将其源设置为您的视频 URL,并定义负责在视频播放期间更新 Konva.js 层的 animate 函数。 当视频的loadeddata事件被触发时,我们开始播放视频并调用animate函数来不断更新Konva.js层。