tiefen_space_h5/components/ImagesMask/index.jsx

509 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, {
useState,
useEffect,
useRef,
forwardRef,
useImperativeHandle,
useMemo,
} from "react";
import { Mask, Toast } from "antd-mobile";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faAngleLeft,
faAngleRight,
faDownload,
} from "@fortawesome/free-solid-svg-icons";
import { useRouter } from "next/navigation";
import baseRequest from "@/utils/baseRequest";
import OwnImage from "../OwnImage";
import { saveImage } from "@/utils/tools/handleFuns";
import requireAPI from "@/utils/requireAPI";
import CheckVip from "@/components/CheckVip";
function ImagesMask({ isEditing = false }, ref) {
const [visible, setVisible] = useState(false);
const [images, setImages] = useState([]);
const [data, setData] = useState(null);
const scrollRef = useRef(null);
const defaultIndex = useRef(null);
const router = useRouter();
const imagesMaskContaintMemo = useMemo(() => {
return (
<ImagesMaskContaint
images={images}
isEditing={isEditing}
visible={visible}
ref={scrollRef}
setVisible={setVisible}
setImages={setImages}
router={router}
data={data}
defaultIndex={defaultIndex.current}
// root={root}
/>
);
}, [images]);
// useEffect(() => {
// let body = document.body;
// if (visible) {
// body.style.touchAction = "none";
// const root = createRoot(document?.getElementById("maskDomBox"));
// root.render(<div>{imagesMaskContaintMemo}</div>);
// } else {
// body.style.touchAction = "auto";
// }
// // root.render(<div>xxxx</div>);
// }, [visible]);
useImperativeHandle(ref, () => ({
show: (arr, index, data) => {
defaultIndex.current = index;
setImages(arr);
setData(data);
setVisible((old) => {
// console.log(arr, index, old);
return !old;
});
// Mask.show
// const maskDomBox = document.getElementById("maskDomBox");
},
close: () => setVisible(false),
}));
return <div>{visible ? imagesMaskContaintMemo : null}</div>;
}
const ImagesMaskContaint = forwardRef(
(
{
isEditing,
visible,
images,
setVisible,
setImages,
router,
data,
defaultIndex = 0,
// root,
},
ref
) => {
const [currentIndex, setCurrentIndex] = useState(0);
const [isNotFirstImg, setIsNotFirstImg] = useState(false);
const [direction, setDirection] = useState("left");
const [initialX, setInitialX] = useState(0);
const [xOffset, setXOffset] = useState(0);
const [initialMoveX, setInitialMoveX] = useState(0);
const [initialMoveY, setInitialMoveY] = useState(0);
const [xOffsetMove, setXOffsetMove] = useState(0);
const [yOffsetMove, setYOffsetMove] = useState(0);
const [active, setActive] = useState(false);
const [zoomed, setZoomed] = useState(false);
const base = baseRequest();
const directionX = useRef(0);
const currentDistance = useRef(0);
useEffect(() => {
if (defaultIndex) {
setIsNotFirstImg(true);
// console.log("defaultIndex.current", defaultIndex);
handleEnd(defaultIndex - 1, "left", true);
}
}, [defaultIndex]);
useEffect(() => {
if (ref.current) {
ref.current.style.transform = `translateX(${
-window.innerWidth * currentIndex
}px)`;
}
}, [currentIndex]);
const handleStart = (e) => {
var touches = e.touches;
setInitialMoveX(touches[0].clientX - ref.current?.offsetLeft);
setInitialMoveY(touches[0].clientY - ref.current?.offsetTop);
// console.log(touches[0].pageX- ref.current.getBoundingClientRect().left);
if (touches.length === 2) {
var touch1 = touches[0];
var touch2 = touches[1];
currentDistance.current = Math.hypot(
touch2.pageX - touch1.pageX,
touch2.pageY - touch1.pageY
);
}
if (touches.length === 1 && !zoomed) {
setInitialX(touches[0].clientX - (!currentIndex ? 0 : xOffset));
// 单点触摸
setActive(true);
}
};
const handleMove = (e) => {
var touches = e.touches;
if (zoomed) {
let currentX = touches[0].clientX - initialMoveX;
let currentY = touches[0].clientY - initialMoveY;
// console.log(currentX + xOffsetMove);
let currentDom =
ref.current.children[currentIndex].getBoundingClientRect();
if (Math.abs(currentX + xOffsetMove) > currentDom.width / 3) return;
ref.current.children[currentIndex].style.left = `${
currentX + xOffsetMove
}px`;
if (Math.abs(currentY + yOffsetMove) > currentDom.height / 3) return;
ref.current.children[currentIndex].style.top = `${
currentY + yOffsetMove - 54
}px`;
} else {
if (active) {
let X = touches[0].clientX - initialX;
setDirection(
directionX.current > touches[0].clientX ? "left" : "right"
);
ref.current.style.transform = "translateX(" + X + "px)";
directionX.current = touches[0].clientX;
}
}
};
const handleEnd = (index, currentDirection, isActive) => {
// const rect = ref.current.getBoundingClientRect();
// console.log(ref.current.children[currentIndex].offsetTop);
if (index != defaultIndex - 1) {
setIsNotFirstImg(false);
}
setXOffsetMove(
ref.current.children[currentIndex].offsetLeft -
window.innerWidth * currentIndex
);
setYOffsetMove(ref.current.children[currentIndex].offsetTop + 54);
if (active || isActive) {
let cxOffset = window.innerWidth;
if (currentDirection == "left") {
if (index < images.length - 1) {
setCurrentIndex(index + 1);
} else {
// setCurrentIndex(0);
ref.current.style.transform = `translateX(${-cxOffset * index}px)`;
}
} else {
if (index > 0) {
setCurrentIndex(index - 1);
} else {
// setCurrentIndex(images.length - 1);
ref.current.style.transform = `translateX(${-cxOffset * index}px)`;
}
}
// setInitialX(currentX);
setInitialX(
-cxOffset * (index + (currentDirection == "left" ? 1 : -1))
);
if (currentDirection == "left" && index > images.length - 2) return;
setXOffset(-cxOffset * (index + (currentDirection == "left" ? 1 : -1)));
}
};
const getOriginImg = async (id) => {
const _data = await requireAPI("POST", `/api/previews/original_image`, {
body: {
image_id: id,
},
});
if (_data.ret === -1) {
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
setImages((old) => {
console.log(old);
const { urls, id, w, h } = _data.data;
const newImages = [...old];
newImages[currentIndex] = {
url: urls[0],
id,
w,
h,
};
return newImages;
});
Toast.show({
content: "已切换至原图",
position: "top",
});
};
return (
<Mask
getContainer={() => document.getElementById("maskDomBox")}
destroyOnClose={false}
visible={visible}
className="z-[1002] h-screen flex justify-center items-center"
onMaskClick={() => {
setVisible(false), setImages([]), setCurrentIndex(null);
// root.unmount();
}}
color="#000000d9"
>
<div className="relative">
{images[currentIndex]?.type != "hid" && (
<div
className="z-50 flex justify-between items-center absolute top-[12px] left-[12px]"
style={{ width: "calc(100% - 24px)" }}
>
<div>
{/* <div
onClick={() => downloadImage(images[currentIndex]?.url)}
className="flex justify-center items-center w-[38px] h-[38px] bg-[#ffffff1a] text-[#fff] rounded-full"
>
<FontAwesomeIcon icon={faDownload} size="xl" />
</div> */}
<div className="leading-[54px] text-center min-w-10">
{currentIndex + 1}/{images.length}
</div>
</div>
<div className="flex gap-2">
{!isEditing && (
<>
<CheckVip
isVipToPassFun={() => {
getOriginImg(images[currentIndex]?.id);
}}
router={router}
>
<div className="flex justify-center items-center w-[38px] h-[38px] bg-[#ffffff1a] text-[#fff] font-medium rounded-full">
原图
</div>
</CheckVip>
<CheckVip
isVipToPassFun={() =>
saveImage(images[currentIndex]?.url)
}
router={router}
>
<div className="flex justify-center items-center w-[38px] h-[38px] bg-[#ffffff1a] text-[#fff] rounded-full">
<FontAwesomeIcon
icon={faDownload}
size="xl"
// className="h-[14px]"
/>
</div>
</CheckVip>
</>
)}
<div
onClick={() => {
setZoomed(!zoomed);
setActive(false);
ref.current.children[currentIndex].style.transform =
"matrix(" +
(zoomed ? 1 : 3) +
", 0, 0, " +
(zoomed ? 1 : 3) +
", 0, 0)";
ref.current.children[currentIndex].style.left = `0px`;
ref.current.children[currentIndex].style.top = `0px`;
}}
className="flex justify-center items-center w-[38px] h-[38px] bg-[#ffffff1a] text-[#fff] rounded-full"
>
{!zoomed ? (
<svg
t="1723822459763"
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="4557"
width="24"
height="24"
>
<path
d="M919.264 905.984l-138.912-138.912C851.808 692.32 896 591.328 896 480c0-229.376-186.624-416-416-416S64 250.624 64 480s186.624 416 416 416c95.008 0 182.432-32.384 252.544-86.208l141.44 141.44a31.904 31.904 0 0 0 45.248 0 32 32 0 0 0 0.032-45.248zM128 480C128 285.92 285.92 128 480 128s352 157.92 352 352-157.92 352-352 352S128 674.08 128 480z"
p-id="4558"
fill="#ffffff"
></path>
<path
d="M625.792 448H512v-112a32 32 0 0 0-64 0V448h-112a32 32 0 0 0 0 64H448v112a32 32 0 1 0 64 0V512h113.792a32 32 0 1 0 0-64z"
p-id="4559"
fill="#ffffff"
></path>
</svg>
) : (
<svg
t="1723822428728"
className="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="4379"
width="24"
height="24"
>
<path
d="M919.264 905.984l-138.912-138.912C851.808 692.32 896 591.328 896 480c0-229.376-186.624-416-416-416S64 250.624 64 480s186.624 416 416 416c95.008 0 182.432-32.384 252.544-86.208l141.44 141.44a31.904 31.904 0 0 0 45.248 0 32 32 0 0 0 0.032-45.248zM128 480C128 285.92 285.92 128 480 128s352 157.92 352 352-157.92 352-352 352S128 674.08 128 480z"
p-id="4380"
fill="#ffffff"
></path>
<path
d="M625.792 448H336a32 32 0 0 0 0 64h289.792a32 32 0 1 0 0-64z"
p-id="4381"
fill="#ffffff"
></path>
</svg>
)}
</div>
</div>
</div>
)}
<div
className="flex justify-start items-center"
style={{ height: "calc(100vh - 24px)" }}
onClick={() => {
setVisible(false), setImages([]), setCurrentIndex(null);
// root.unmount();
}}
>
<div
ref={ref}
id="imagesScrollBox"
className="flex justify-center items-center h-full relative"
draggable={true}
style={{
transitionDuration: !isNotFirstImg ? "300ms" : "0ms",
transitionProperty: "transform",
transitionTimingFunction: "cubic-bezier(0.4, 0, 0.2, 1)",
}}
onTouchStart={handleStart}
onTouchMove={handleMove}
onTouchEnd={() => handleEnd(currentIndex, direction)}
>
{images.map((item, index) => {
return (
<div
draggable={true}
key={index}
className="flex-none w-screen relative h-full"
// onDoubleClick={() => {
// setZoomed(!zoomed);
// ref.current.children[0].style.transform =
// "matrix(" + zoomed
// ? 1
// : 3 + ", 0, 0, " + zoomed
// ? 1
// : 3 + ", 0, 0)";
// ref.current.style.left = `0px`;
// ref.current.style.top = `0px`;
// }}
>
{/* <img
src={item.url}
className="h-full m-auto"
style={{
filter: item.type == "hid" ? "blur(10px)" : "none",
}}
/> */}
<OwnImage
draggable={true}
className="h-full w-full m-auto"
outClassName="h-full w-full"
src={item.url}
style={{
filter: item.type == "hid" ? "blur(10px)" : "none",
}}
// draggable={true}
fit="contain"
/>
<div className="absolute top-1/2 left-1/2 -ml-[100px] -mt-[14px]">
{item.type == "hid" && (
<div className="flex justify-center">
<div
className="rounded-full text-sm h-max w-max px-4 py-1 bg-primary"
onClick={() => {
router.push(
"/webView/" +
encodeURIComponent(
"/zone/pay/" +
data?.zid +
"/h5_zone_moment/" +
data?.id +
"?base=" +
encodeURIComponent(JSON.stringify(base))
)
);
}}
>
此内容暂未解锁立即解锁
</div>
</div>
)}
</div>
</div>
);
})}
</div>
</div>
<div
className="flex justify-between items-center w-screen absolute top-1/2 px-4 pointer-events-none"
style={{
marginTop: "calc(-50vh + 118px)",
height: "calc(100vh - 174px)",
visibility: images.length > 1 ? "visible" : "hidden",
}}
>
<div
className="w-12 h-full flex items-center justify-center rounded-full float-left pointer-events-auto"
onClick={() => {
setActive(true);
setZoomed(false);
setInitialMoveX(0);
setInitialMoveY(0);
setXOffsetMove(0);
setYOffsetMove(0);
ref.current.children[currentIndex].style.transform =
"matrix(1, 0, 0, 1, 0, 0)";
ref.current.children[currentIndex].style.left = `0px`;
ref.current.children[currentIndex].style.top = `0px`;
handleEnd(currentIndex, "right", true);
}}
>
<FontAwesomeIcon
icon={faAngleLeft}
size="xl"
style={{ maxWidth: "12px" }}
/>
</div>
<div
className="w-12 h-full flex items-center justify-center rounded-full float-left pointer-events-auto"
onClick={() => {
setZoomed(false);
setInitialMoveX(0);
setInitialMoveY(0);
setXOffsetMove(0);
setYOffsetMove(0);
ref.current.children[currentIndex].style.transform =
"matrix(1, 0, 0, 1, 0, 0)";
ref.current.children[currentIndex].style.left = `0px`;
ref.current.children[currentIndex].style.top = `0px`;
handleEnd(currentIndex, "left", true);
}}
>
<FontAwesomeIcon
icon={faAngleRight}
size="xl"
style={{ maxWidth: "12px" }}
/>
</div>
</div>
</div>
</Mask>
);
}
);
export default forwardRef(ImagesMask);