Skip to content

Commit

Permalink
实现在移动端,点击AI回答的图片后,可以通过双指放大缩小移动图片的功能 (#1857)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jiang-Wan authored Jun 26, 2024
1 parent 4b4bea1 commit 9d084b6
Showing 1 changed file with 178 additions and 2 deletions.
180 changes: 178 additions & 2 deletions projects/app/src/components/Markdown/img/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { WheelEventHandler, useState } from 'react';
import React, { WheelEventHandler, useState, MouseEventHandler, TouchEventHandler, useRef } from 'react';
import {
Box,
Image,
Expand All @@ -11,11 +11,32 @@ import {
} from '@chakra-ui/react';

const MdImage = ({ src }: { src?: string }) => {
const imgRef = useRef<HTMLImageElement>(null);
const [isLoading, setIsLoading] = useState(true);
const [succeed, setSucceed] = useState(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const [scale, setScale] = useState(1);

const [positionLeft, setPositionLeft] = useState(0)
const [positionTop, setPositionTop] = useState(0)
const [store] = useState({
scale: 1,
moveable: false,
pageX: 0,
pageY: 0,
pageX2: 0,
pageY2: 0,
originScale: 1
})

// 自定义Modal关闭事件
const customOnClose = (): void => {
setPositionLeft(0)
setPositionTop(0)
setScale(1)
onClose()
}

const handleWheel: WheelEventHandler<HTMLImageElement> = (e) => {
setScale((prevScale) => {
const newScale = prevScale + e.deltaY * 0.5 * -0.01;
Expand All @@ -25,6 +46,153 @@ const MdImage = ({ src }: { src?: string }) => {
});
};

const handleTouchStart: TouchEventHandler<HTMLImageElement> = (event) => {
let touches = event.touches;
let events = touches[0];//单指
let events2 = touches[1];//双指
if (touches.length == 1) {// 单指操作
store.pageX = events.pageX
store.pageY = events.pageY
store.moveable = true;
} else {
// 第一个触摸点的坐标
store.pageX = events.pageX;
store.pageY = events.pageY;
store.moveable = true;
if (events2) {
store.pageX2 = events2.pageX;
store.pageY2 = events2.pageY;
}
store.originScale = store.scale || 1;
}
}

const handleTouchMove: TouchEventHandler<HTMLImageElement> = (event) => {
if (!store.moveable) {
return;
}
let touches = event.touches;
let events = touches[0];
let events2 = touches[1];
//最大移动距离
let moveMaxWith = (Number(imgRef.current?.width) * scale - window.innerWidth) / 2;
let moveMaxHeight = (Number(imgRef.current?.height) * scale - window.innerHeight) / 2;

if (touches.length == 1) {
//未放大,不移动图片
if (scale <= 1)
return;

let pageX = store.pageX;
let pageY = store.pageY
let pageX2 = events.pageX;
let pageY2 = events.pageY;

let newLeft = positionLeft + pageX2 / 20 - pageX / 20;
let newTop = positionTop + pageY2 / 20 - pageY / 20;
if (Math.abs(newLeft) > moveMaxWith) {
if (newLeft > 0) {
newLeft = moveMaxWith;
}
else {
newLeft = 0 - moveMaxWith;
}
}
// 放大倍数没超过屏高
if (moveMaxHeight < 0) {
newTop = 0;
}
else if (Math.abs(newTop) > moveMaxHeight) {
if (newTop > 0) {
newTop = moveMaxHeight;
}
else {
newTop = 0 - moveMaxHeight;
}
}

//控制图片移动
setPositionLeft(newLeft)
setPositionTop(newTop)
} else {
// 双指移动
if (events2) {
// 第2个指头坐标在touchmove时候获取
store.pageX2 = events2.pageX;
store.pageY2 = events2.pageY;

// 获取坐标之间的距离
let getDistance = function (start: any, stop: any) {
//用到三角函数
return Math.hypot(stop.x - start.x,
stop.y - start.y);
};
// 双指缩放比例计算
let zoom = getDistance({
x: events.pageX,
y: events.pageY
}, {
x: events2.pageX,
y: events2.pageY
}) / getDistance({
x: store.pageX,
y: store.pageY
}, {
x: store.pageX2,
y: store.pageY2
});
// 应用在元素上的缩放比例
let newScale = store.originScale * zoom;

// 缩放比例限制
if (newScale > 10) {
newScale = 10;
}
if (newScale <= 1) {
newScale = 1;
}

store.scale = newScale;
// 图像应用缩放效果
setScale(newScale);
// 如果是缩小图片,则限制移动的距离
if (Math.abs(positionLeft) > moveMaxWith) {
if (positionLeft > 0) {
setPositionLeft(moveMaxWith);
}
else {
setPositionLeft(0 - moveMaxWith);
}
}

if (moveMaxHeight < 0) {
setPositionTop(0);
}
else if (Math.abs(positionTop) > moveMaxHeight) {
if (positionTop > 0) {
setPositionTop(moveMaxHeight);
}
else {
setPositionTop(0 - moveMaxHeight);
}
}
}
}

}

const handleTouchEnd: TouchEventHandler<HTMLImageElement> = (e) => {
store.moveable = false;
store.pageX2 = 0;
store.pageY2 = 0;
}

const handleTouchCancel: TouchEventHandler<HTMLImageElement> = (e) => {
store.moveable = false;
store.pageX2 = 0;
store.pageY2 = 0;
}

return (
<>
<Image
Expand All @@ -50,10 +218,11 @@ const MdImage = ({ src }: { src?: string }) => {
onOpen();
}}
/>
<Modal isOpen={isOpen} onClose={onClose} isCentered>
<Modal isOpen={isOpen} onClose={customOnClose} isCentered>
<ModalOverlay />
<ModalContent boxShadow={'none'} maxW={'auto'} w="auto" bg={'transparent'}>
<Image
ref={imgRef}
transform={`scale(${scale})`}
borderRadius={'md'}
src={src}
Expand All @@ -64,7 +233,14 @@ const MdImage = ({ src }: { src?: string }) => {
fallbackSrc={'/imgs/errImg.png'}
fallbackStrategy={'onError'}
objectFit={'contain'}
position={'relative'}
top={positionTop + 'px'}
left={positionLeft + "px"}
onWheel={handleWheel}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
onTouchCancel={handleTouchCancel}
/>
</ModalContent>
<ModalCloseButton bg={'myWhite.500'} zIndex={999999} />
Expand Down

0 comments on commit 9d084b6

Please sign in to comment.