0
点赞
收藏
分享

微信扫一扫

react.js实现类似3D查看效果


react.js实现类似3D查看效果_reactjs


react.js实现类似3D查看效果_ios_02

其实就是多张图片切换,low~

import {
FC,
ReactElement,
useCallback,
useState,
useEffect,
useMemo,
} from "react";
import axios from "axios";
import DragImages from "./DragImages";

const defaultSource =
"https://media.emeralds.com/stone/E122/video360/E122-video360-001-Medium.jpg?1";

const Emerald2: FC = (): ReactElement => {
const [sources, setSources] = useState<HTMLImageElement[]>([]);

const getSource = useCallback(async () => {
let i = 1;
const source: HTMLImageElement[] = [];

while (i <= 219) {
const url = `https://media.emeralds.com/stone/E122/video360/E122-video360-${i
.toString()
.padStart(3, "0")}-Medium.jpg?1`;
await axios
.get(url, { responseType: "blob" })
.then((response: any) => {
const image = new Image();
const imgSrc = window.URL.createObjectURL(response.data);
image.src = imgSrc;
source.push(image);
})
.catch(() => {});
i++;
}
if (source.length) {
setSources(() => source);
}
}, []);

useEffect(() => {
getSource();
}, [getSource]);

const DragImagesMemo = useMemo(
() => (
<DragImages
width={300}
height={300}
defaultSource={defaultSource}
sources={sources}
onStart={() => {
// eslint-disable-next-line no-console
console.log("start", sources.length);
}}
/>
),
[sources]
);

return <>{DragImagesMemo}</>;
};

export default Emerald2;

需要传入 元素为img的数组,在canvas上不断渲染

import {
FC,
ReactElement,
useRef,
useEffect,
useCallback,
useMemo,
} from "react";

interface IProps {
width?: number;
height?: number;
sources: Array<HTMLImageElement>;
defaultSource: string;
onStart?: () => void;
}

interface ITimer {
timer: NodeJS.Timeout | null;
}

const DragImages: FC<IProps> = ({
width = 365,
height = 365,
sources,
defaultSource,
onStart,
}): ReactElement => {
const timeout = useMemo(() => 50, []);
const sourceProperty = useMemo(() => "sourceProperty", []);
const canvas = useRef<HTMLCanvasElement>(null);
const defaultImage = useRef<HTMLImageElement>(new Image());
const dragOrigin = useRef<{ origin: number }>({ origin: 0 }); // 记录拖拽的点坐标
const Timer = useRef<ITimer>({ timer: null });

const toggleSource = useCallback(
(nextIndex: number) => {
const ctx = canvas.current!.getContext("2d");
const imageSource = sources[nextIndex];
ctx!.drawImage(imageSource, 0, 0, width, height);
// 将当前显示图片的位置放到已经不显示的默认图片上面,为拖动操作指明起始位置
defaultImage.current.setAttribute(sourceProperty, nextIndex.toString());
},
[sources, width, height, defaultImage, sourceProperty, canvas]
);

const autoRotate = useCallback(
(startIndex = 0): void => {
const nextIndex = startIndex < sources.length ? startIndex : 0;
toggleSource(nextIndex);
Timer.current.timer = setTimeout(() => {
autoRotate(nextIndex + 1);
}, timeout);
},
[sources, toggleSource, timeout]
);

const drawDefaultImage = useCallback(() => {
const ctx = canvas.current!.getContext("2d");
const eImage: HTMLImageElement = defaultImage.current;
eImage.onload = () => {
ctx!.drawImage(eImage, 0, 0, width, height);
};
eImage.setAttribute(sourceProperty, "0");
eImage.src = defaultSource;
}, [height, sourceProperty, width, defaultSource]);

const handleClearTimeout = useCallback(() => {
clearTimeout(Timer.current.timer as NodeJS.Timeout);
Timer.current.timer = null;
}, []);

useEffect(() => handleClearTimeout, [handleClearTimeout]);

useEffect(() => {
if (defaultSource) {
drawDefaultImage();
}
}, [defaultSource, drawDefaultImage]);

useEffect(() => {
if (sources.length) {
onStart && onStart();
autoRotate();
}
}, [sources, autoRotate, onStart]);

const onMouseMove = useCallback(
({ clientX }) => {
const currentSourceIndex = defaultImage.current.getAttribute(
sourceProperty
);
const nextSourcesIndex = computedNextSourcesIndex(
clientX,
dragOrigin.current.origin,
Number(currentSourceIndex),
sources.length
);
toggleSource(nextSourcesIndex);
dragOrigin.current.origin = clientX;
},
[sourceProperty, sources, toggleSource]
);

const onMouseDown = useCallback(
({ clientX }) => {
dragOrigin.current.origin = clientX;
handleClearTimeout();
canvas.current!.addEventListener("mousemove", onMouseMove);
},
[onMouseMove, canvas, handleClearTimeout]
);

const cancelDrag = useCallback(() => {
if (!Timer.current.timer) {
canvas.current!.removeEventListener("mousemove", onMouseMove);
const sourceIndex = defaultImage.current.getAttribute(sourceProperty);
autoRotate(Number(sourceIndex) + 1);
}
}, [onMouseMove, canvas, defaultImage, autoRotate, sourceProperty, Timer]);

return (
<canvas
ref={canvas}
width={width}
height={height}
style={{ cursor: "ew-resize" }}
onMouseDown={onMouseDown}
onMouseUp={cancelDrag}
onMouseLeave={cancelDrag}
/>
);
};

export default DragImages;

function computedNextSourcesIndex(
clientX: number,
prevClientX: number,
currentSourceIndex: number,
sourcesLength: number
) {
const nextIndex =
clientX > prevClientX ? currentSourceIndex - 1 : currentSourceIndex + 1;
const allowValue = nextIndex < sourcesLength && nextIndex >= 0;

return allowValue ? nextIndex : nextIndex < 0 ? sourcesLength - 1 : 0;

// if (allowValue) {
// return nextIndex;
// }
// if (nextIndex < 0) {
// return sourcesLength - 1;
// }
// return 0;
}



old version

import {
FC,
ReactElement,
useRef,
useEffect,
useCallback,
useMemo,
} from "react";
import { log } from "../../../utils/logger";

interface IProps {
width?: number;
height?: number;
sources: Array<string>;
defaultSource: string;
}

interface ITimer {
timer: NodeJS.Timeout | null;
}

const DragImages: FC<IProps> = ({
width = 365,
height = 365,
sources,
defaultSource,
}): ReactElement => {
const timeout = useMemo(() => 50, []);
const imageProperty = useMemo(() => "sourceIndex", []);
const canvas = useRef<HTMLCanvasElement>(null);
const provideSources = useMemo(() => sources, [sources]);
const image = useRef<HTMLImageElement>(new Image());
const dragOrigin = useRef<{ origin: number }>({ origin: 0 });
const Timer = useRef<ITimer>({ timer: null });

const toggleSource = useCallback(
(nextIndex: number) => {
const eImage = image.current;
eImage.setAttribute(imageProperty, nextIndex.toString());
eImage.src = provideSources[nextIndex];
},
[provideSources, imageProperty]
);

const autoRotate = useCallback(
(startIndex = 1): void => {
const nextIndex = startIndex <= provideSources.length ? startIndex : 0;
toggleSource(nextIndex);
Timer.current.timer = setTimeout(() => {
autoRotate(nextIndex + 1);
}, timeout);
},
[provideSources, toggleSource, timeout]
);

const drawDefaultImage = useCallback(() => {
const ctx = canvas.current!.getContext("2d");
const eImage = image.current;
eImage.onload = () => {
ctx!.drawImage(eImage, 0, 0, width, height);
};
eImage.setAttribute(imageProperty, "0");
eImage.src = defaultSource;
}, [height, imageProperty, width, defaultSource]);

const handleClearTimeout = useCallback(() => {
clearTimeout(Timer.current.timer as NodeJS.Timeout);
Timer.current.timer = null;
}, []);

useEffect(() => handleClearTimeout, [handleClearTimeout]);

useEffect(() => {
if (defaultSource) {
drawDefaultImage();
}
}, [defaultSource, drawDefaultImage]);

useEffect(() => {
if (provideSources.length) {
log("start");
autoRotate();
}
}, [provideSources, autoRotate]);

const onMouseMove = useCallback(
({ clientX }) => {
const currentSourceIndex = image.current.getAttribute(imageProperty);
const nextSourcesIndex = computedNextSourcesIndex(
clientX,
dragOrigin.current.origin,
Number(currentSourceIndex),
provideSources.length
);
toggleSource(nextSourcesIndex);
dragOrigin.current.origin = clientX;
},
[imageProperty, provideSources, toggleSource]
);

const onMouseDown = useCallback(
({ clientX }) => {
dragOrigin.current.origin = clientX;
handleClearTimeout();
canvas.current!.addEventListener("mousemove", onMouseMove);
},
[onMouseMove, canvas, handleClearTimeout]
);

const cancelDrag = useCallback(() => {
if (!Timer.current.timer) {
canvas.current!.removeEventListener("mousemove", onMouseMove);
const sourceIndex = image.current.getAttribute(imageProperty);
autoRotate(Number(sourceIndex) + 1);
}
}, [onMouseMove, canvas, image, autoRotate, imageProperty, Timer]);

return (
<canvas
ref={canvas}
width={width}
height={height}
style={{ cursor: "ew-resize" }}
onMouseDown={onMouseDown}
onMouseUp={cancelDrag}
onMouseLeave={cancelDrag}
/>
);
};

export default DragImages;

function computedNextSourcesIndex(
clientX: number,
prevClientX: number,
currentSourceIndex: number,
sourcesLength: number
) {
const nextIndex =
clientX > prevClientX ? currentSourceIndex - 1 : currentSourceIndex + 1;
const allowValue = nextIndex <= sourcesLength && nextIndex >= 0;

return allowValue ? nextIndex : nextIndex < 0 ? sourcesLength : 0;

// if (allowValue) {
// return nextIndex;
// }
// if (nextIndex < 0) {
// return sourcesLength;
// }
// return 0;
}


举报

相关推荐

0 条评论