重构client,拆分组件
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { useEffect } from "react";
|
||||
import type { RefObject } from "react";
|
||||
|
||||
interface UseBackgroundCanvasProps {
|
||||
isVideo: boolean;
|
||||
idx: number;
|
||||
videoRef: RefObject<HTMLVideoElement | null>;
|
||||
scrollerRef: RefObject<HTMLDivElement | null>;
|
||||
backgroundCanvasRef: RefObject<HTMLCanvasElement | null>;
|
||||
}
|
||||
|
||||
export function useBackgroundCanvas({
|
||||
isVideo,
|
||||
idx,
|
||||
videoRef,
|
||||
scrollerRef,
|
||||
backgroundCanvasRef,
|
||||
}: UseBackgroundCanvasProps) {
|
||||
useEffect(() => {
|
||||
const canvas = backgroundCanvasRef.current;
|
||||
if (!canvas) return;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
const updateCanvasSize = () => {
|
||||
canvas.width = Math.floor(window.innerWidth / 10);
|
||||
canvas.height = Math.floor(window.innerHeight / 10);
|
||||
};
|
||||
updateCanvasSize();
|
||||
|
||||
let resizeTimeout: NodeJS.Timeout;
|
||||
const debouncedResize = () => {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(updateCanvasSize, 300);
|
||||
};
|
||||
window.addEventListener("resize", debouncedResize);
|
||||
|
||||
const drawMediaToCanvas = () => {
|
||||
if (!ctx) return;
|
||||
|
||||
let sourceElement: HTMLVideoElement | HTMLImageElement | null = null;
|
||||
|
||||
if (isVideo) {
|
||||
sourceElement = videoRef.current;
|
||||
} else {
|
||||
const scroller = scrollerRef.current;
|
||||
if (scroller) {
|
||||
const currentImgContainer = scroller.children[idx] as HTMLElement;
|
||||
if (currentImgContainer) {
|
||||
sourceElement = currentImgContainer.querySelector("img");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sourceElement || (sourceElement instanceof HTMLVideoElement && sourceElement.readyState < 2)) return;
|
||||
|
||||
const canvasWidth = canvas.width;
|
||||
const canvasHeight = canvas.height;
|
||||
const sourceWidth =
|
||||
sourceElement instanceof HTMLVideoElement ? sourceElement.videoWidth : sourceElement.naturalWidth;
|
||||
const sourceHeight =
|
||||
sourceElement instanceof HTMLVideoElement ? sourceElement.videoHeight : sourceElement.naturalHeight;
|
||||
|
||||
if (!sourceWidth || !sourceHeight) return;
|
||||
|
||||
const canvasRatio = canvasWidth / canvasHeight;
|
||||
const sourceRatio = sourceWidth / sourceHeight;
|
||||
|
||||
let drawWidth: number, drawHeight: number, offsetX: number, offsetY: number;
|
||||
|
||||
if (canvasRatio > sourceRatio) {
|
||||
drawWidth = canvasWidth;
|
||||
drawHeight = canvasWidth / sourceRatio;
|
||||
offsetX = 0;
|
||||
offsetY = (canvasHeight - drawHeight) / 2;
|
||||
} else {
|
||||
drawHeight = canvasHeight;
|
||||
drawWidth = canvasHeight * sourceRatio;
|
||||
offsetX = (canvasWidth - drawWidth) / 2;
|
||||
offsetY = 0;
|
||||
}
|
||||
|
||||
ctx.drawImage(sourceElement, offsetX, offsetY, drawWidth, drawHeight);
|
||||
};
|
||||
|
||||
const intervalId = setInterval(drawMediaToCanvas, 20);
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
window.removeEventListener("resize", debouncedResize);
|
||||
clearTimeout(resizeTimeout);
|
||||
};
|
||||
}, [isVideo, idx, videoRef, scrollerRef, backgroundCanvasRef]);
|
||||
}
|
||||
Reference in New Issue
Block a user