From 3369897afc5485e13aea5c576d9cc5384d45fa04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Fri, 1 Dec 2023 09:44:01 +0100 Subject: [PATCH 1/6] Add avatar video to `RealmPin` --- .../Island/IslandRealmsDetails/RealmPin.tsx | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/ui/Island/IslandRealmsDetails/RealmPin.tsx b/src/ui/Island/IslandRealmsDetails/RealmPin.tsx index 04b6df5b4..b1dd60941 100644 --- a/src/ui/Island/IslandRealmsDetails/RealmPin.tsx +++ b/src/ui/Island/IslandRealmsDetails/RealmPin.tsx @@ -10,8 +10,7 @@ import { } from "redux-state" import { FIGMA_FACTOR, getRealmMapData } from "shared/constants" import { getPinShift } from "shared/utils" -// import KonvaVideo from "shared/components/KonvaVideo" -import portraitImg from "shared/assets/portrait.png" +import KonvaVideo from "shared/components/KonvaVideo" type RealmPinAvatarProps = { x: number @@ -23,25 +22,24 @@ function RealmPinAvatar({ x, y }: RealmPinAvatarProps) { const avatarType = useDappSelector(selectWalletAvatarType) const [avatarImage] = useImage(avatar) - const [portrait] = useImage(portraitImg) // TODO: implement video avatar support - // if (avatarType === "video/mp4") { - // return ( - // - // ) - // } + if (avatarType === "video/mp4") { + return ( + + ) + } return ( Date: Fri, 1 Dec 2023 11:59:43 +0100 Subject: [PATCH 2/6] Add `focus` to video element --- src/shared/components/KonvaVideo.tsx | 56 +++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/shared/components/KonvaVideo.tsx b/src/shared/components/KonvaVideo.tsx index a42f7897a..8624cc086 100644 --- a/src/shared/components/KonvaVideo.tsx +++ b/src/shared/components/KonvaVideo.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useRef } from "react" import Konva from "konva" import { Image } from "react-konva" import { ImageConfig } from "konva/lib/shapes/Image" +// import useImage from "use-image" type KonvaVideoProps = { x: number @@ -13,6 +14,26 @@ type KonvaVideoProps = { videoProps?: Partial } +// function extractFirstVideoFrame( +// video: HTMLVideoElement, +// width: number, +// height: number +// ) { +// const canvas = document.createElement("canvas") + +// canvas.width = width +// canvas.height = height + +// const canvasCtx = canvas.getContext("2d") + +// canvasCtx?.drawImage(video, 0, 0, canvas.width, canvas.height) +// const firstFrame = canvas.toDataURL() + +// canvas.remove() + +// return firstFrame +// } + // Source: https://codesandbox.io/p/sandbox/react-konva-video-on-canvas-oygvf?file=%2Fsrc%2Findex.js%3A22%2C31 export default function KonvaVideo({ x, @@ -24,31 +45,62 @@ export default function KonvaVideo({ videoProps, }: KonvaVideoProps) { const imageRef = useRef(null) + // const [videoPaused, setVideoPaused] = useState(true) + // const [firstFrame, setFirstFrame] = useState(null) const videoElement = useMemo(() => { const element = document.createElement("video") element.src = src element.loop = loop + element.focus() + return element }, [src, loop]) - // use Konva.Animation to redraw a layer + // useEffect(() => { + // const onLoad = () => { + // const canvas = document.createElement("canvas") + + // canvas.width = width + // canvas.height = height + + // videoElement.currentTime = 1 + // const canvasCtx = canvas.getContext("2d") + + // canvasCtx?.drawImage(videoElement, 0, 0, canvas.width, canvas.height) + // setFirstFrame(canvas) + // } + // }, [videoElement, height, width]) + useEffect(() => { if (!imageRef.current) return () => {} + // const handleVideoPLay = () => { + // videoElement.play() + // // setVideoPaused(false) + // } + videoElement.play() + + // document.addEventListener("click", handleVideoPLay) + const imageLayer = imageRef.current.getLayer() + // use Konva.Animation to redraw a layer const animation = new Konva.Animation(() => {}, imageLayer) animation.start() - return () => animation.stop() + return () => { + // document.removeEventListener("click", handleVideoPLay) + animation.stop() + } }, [videoElement, imageRef]) return ( Date: Fri, 1 Dec 2023 12:05:24 +0100 Subject: [PATCH 3/6] Extract first video frame --- src/shared/components/KonvaVideo.tsx | 73 +++++++++++----------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/src/shared/components/KonvaVideo.tsx b/src/shared/components/KonvaVideo.tsx index 8624cc086..f515c1b09 100644 --- a/src/shared/components/KonvaVideo.tsx +++ b/src/shared/components/KonvaVideo.tsx @@ -1,8 +1,8 @@ -import React, { useEffect, useMemo, useRef } from "react" +import React, { useEffect, useMemo, useRef, useState } from "react" import Konva from "konva" import { Image } from "react-konva" import { ImageConfig } from "konva/lib/shapes/Image" -// import useImage from "use-image" +import useImage from "use-image" type KonvaVideoProps = { x: number @@ -14,25 +14,25 @@ type KonvaVideoProps = { videoProps?: Partial } -// function extractFirstVideoFrame( -// video: HTMLVideoElement, -// width: number, -// height: number -// ) { -// const canvas = document.createElement("canvas") +function extractFirstVideoFrame( + video: HTMLVideoElement, + width: number, + height: number +) { + const canvas = document.createElement("canvas") -// canvas.width = width -// canvas.height = height + canvas.width = width + canvas.height = height -// const canvasCtx = canvas.getContext("2d") + const canvasCtx = canvas.getContext("2d") -// canvasCtx?.drawImage(video, 0, 0, canvas.width, canvas.height) -// const firstFrame = canvas.toDataURL() + canvasCtx?.drawImage(video, 0, 0, canvas.width, canvas.height) + const firstFrame = canvas.toDataURL() -// canvas.remove() + canvas.remove() -// return firstFrame -// } + return firstFrame +} // Source: https://codesandbox.io/p/sandbox/react-konva-video-on-canvas-oygvf?file=%2Fsrc%2Findex.js%3A22%2C31 export default function KonvaVideo({ @@ -45,45 +45,25 @@ export default function KonvaVideo({ videoProps, }: KonvaVideoProps) { const imageRef = useRef(null) - // const [videoPaused, setVideoPaused] = useState(true) - // const [firstFrame, setFirstFrame] = useState(null) + const [videoPaused, setVideoPaused] = useState(true) const videoElement = useMemo(() => { const element = document.createElement("video") element.src = src element.loop = loop - element.focus() - return element }, [src, loop]) - // useEffect(() => { - // const onLoad = () => { - // const canvas = document.createElement("canvas") - - // canvas.width = width - // canvas.height = height - - // videoElement.currentTime = 1 - // const canvasCtx = canvas.getContext("2d") - - // canvasCtx?.drawImage(videoElement, 0, 0, canvas.width, canvas.height) - // setFirstFrame(canvas) - // } - // }, [videoElement, height, width]) - useEffect(() => { if (!imageRef.current) return () => {} - // const handleVideoPLay = () => { - // videoElement.play() - // // setVideoPaused(false) - // } - - videoElement.play() + const handleVideoPLay = () => { + videoElement.play() + setVideoPaused(false) + } - // document.addEventListener("click", handleVideoPLay) + document.addEventListener("click", handleVideoPLay) const imageLayer = imageRef.current.getLayer() @@ -92,16 +72,19 @@ export default function KonvaVideo({ animation.start() return () => { - // document.removeEventListener("click", handleVideoPLay) + document.removeEventListener("click", handleVideoPLay) animation.stop() } }, [videoElement, imageRef]) + const [firstFrame] = useImage( + extractFirstVideoFrame(videoElement, width, height) + ) + return ( Date: Fri, 1 Dec 2023 12:22:58 +0100 Subject: [PATCH 4/6] Handle `video.play` promise --- src/shared/components/KonvaVideo.tsx | 51 ++++++++-------------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/src/shared/components/KonvaVideo.tsx b/src/shared/components/KonvaVideo.tsx index f515c1b09..ce1a0fffa 100644 --- a/src/shared/components/KonvaVideo.tsx +++ b/src/shared/components/KonvaVideo.tsx @@ -1,8 +1,7 @@ -import React, { useEffect, useMemo, useRef, useState } from "react" +import React, { useEffect, useMemo, useRef } from "react" import Konva from "konva" import { Image } from "react-konva" import { ImageConfig } from "konva/lib/shapes/Image" -import useImage from "use-image" type KonvaVideoProps = { x: number @@ -14,26 +13,6 @@ type KonvaVideoProps = { videoProps?: Partial } -function extractFirstVideoFrame( - video: HTMLVideoElement, - width: number, - height: number -) { - const canvas = document.createElement("canvas") - - canvas.width = width - canvas.height = height - - const canvasCtx = canvas.getContext("2d") - - canvasCtx?.drawImage(video, 0, 0, canvas.width, canvas.height) - const firstFrame = canvas.toDataURL() - - canvas.remove() - - return firstFrame -} - // Source: https://codesandbox.io/p/sandbox/react-konva-video-on-canvas-oygvf?file=%2Fsrc%2Findex.js%3A22%2C31 export default function KonvaVideo({ x, @@ -45,7 +24,6 @@ export default function KonvaVideo({ videoProps, }: KonvaVideoProps) { const imageRef = useRef(null) - const [videoPaused, setVideoPaused] = useState(true) const videoElement = useMemo(() => { const element = document.createElement("video") @@ -58,33 +36,32 @@ export default function KonvaVideo({ useEffect(() => { if (!imageRef.current) return () => {} - const handleVideoPLay = () => { - videoElement.play() - setVideoPaused(false) - } + // Source: https://stackoverflow.com/a/68128950 + const handleVideoPLay = async () => { + const promise = videoElement.play() - document.addEventListener("click", handleVideoPLay) + if (promise !== undefined) { + promise.catch(() => { + videoElement.muted = true + videoElement.play() + }) + } + } + handleVideoPLay() const imageLayer = imageRef.current.getLayer() // use Konva.Animation to redraw a layer const animation = new Konva.Animation(() => {}, imageLayer) animation.start() - return () => { - document.removeEventListener("click", handleVideoPLay) - animation.stop() - } + return () => animation.stop() }, [videoElement, imageRef]) - const [firstFrame] = useImage( - extractFirstVideoFrame(videoElement, width, height) - ) - return ( Date: Fri, 1 Dec 2023 12:39:22 +0100 Subject: [PATCH 5/6] Rename `promise` to `playPromise` --- src/shared/components/KonvaVideo.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/components/KonvaVideo.tsx b/src/shared/components/KonvaVideo.tsx index ce1a0fffa..a3a95eaba 100644 --- a/src/shared/components/KonvaVideo.tsx +++ b/src/shared/components/KonvaVideo.tsx @@ -38,10 +38,10 @@ export default function KonvaVideo({ // Source: https://stackoverflow.com/a/68128950 const handleVideoPLay = async () => { - const promise = videoElement.play() + const playPromise = videoElement.play() - if (promise !== undefined) { - promise.catch(() => { + if (playPromise !== undefined) { + playPromise.catch(() => { videoElement.muted = true videoElement.play() }) From 69798a0df5f8770ac9ce1204091265c6ea2490e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Paczy=C5=84ski?= Date: Fri, 1 Dec 2023 12:52:52 +0100 Subject: [PATCH 6/6] Remove commented code --- src/ui/Island/IslandRealmsDetails/RealmPin.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ui/Island/IslandRealmsDetails/RealmPin.tsx b/src/ui/Island/IslandRealmsDetails/RealmPin.tsx index b1dd60941..71d2008dd 100644 --- a/src/ui/Island/IslandRealmsDetails/RealmPin.tsx +++ b/src/ui/Island/IslandRealmsDetails/RealmPin.tsx @@ -23,7 +23,6 @@ function RealmPinAvatar({ x, y }: RealmPinAvatarProps) { const [avatarImage] = useImage(avatar) - // TODO: implement video avatar support if (avatarType === "video/mp4") { return (