Reputation: 1076
Building off of Konva
documentation on how to render a video to the canvas, I would like to play the video by accessing the video reference directly from the Konva.Image
instance. Below is a contrived example to simulate my goal of playing the video dynamically from outside the component. The below does not play the video as expected, even though imageRef.current.image()
returns the video element reference. Any suggestions on how I can access the video reference alternatively?
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} />
)
}
Upvotes: 2
Views: 3134
Reputation: 11
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}>
<Layer>
<Image
ref={(node) => {
setVidoeNode(node);
}}
image={videoRef.current}
width={window.innerWidth}
height={window.innerHeight}
/>
</Layer>
</Stage>
<video ref={videoRef} hidden />
</>
);
};
export default VideoPlayer;
The useEffect hook is employed to set up the video playback and Konva.js integration. It triggers whenever the videoNode value changes. We use the videoRef to access the video element, set its source to your video URL, and define the animate function that will be responsible for updating the Konva.js layer during video playback. When the video's loadeddata event is triggered, we start playing the video and call the animate function to update the Konva.js layer continuously.
Upvotes: 0
Reputation: 20373
You can do this:
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
/>
);
};
Demo: https://codesandbox.io/s/react-konva-video-on-canvas-oygvf
Upvotes: 3