@gx-design-vue/image 0.1.2 → 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +71 -7
- package/dist/GImage.d.ts +162 -0
- package/dist/GImage.js +221 -0
- package/dist/ImagePreview/Operations.d.ts +83 -0
- package/dist/ImagePreview/Operations.js +71 -0
- package/dist/ImagePreview/hooks/getFixScaleEleTransPosition.d.ts +19 -0
- package/dist/ImagePreview/hooks/getFixScaleEleTransPosition.js +40 -0
- package/dist/ImagePreview/hooks/useImageTransform.d.ts +39 -0
- package/dist/ImagePreview/hooks/useImageTransform.js +105 -0
- package/dist/ImagePreview/hooks/useMouseEvent.d.ts +14 -0
- package/dist/ImagePreview/hooks/useMouseEvent.js +100 -0
- package/dist/ImagePreview/hooks/useTouchEvent.d.ts +12 -0
- package/dist/ImagePreview/hooks/useTouchEvent.js +123 -0
- package/dist/ImagePreview/index.d.ts +162 -0
- package/dist/ImagePreview/index.js +303 -0
- package/dist/ImagePreview/props.d.ts +88 -0
- package/dist/ImagePreview/props.js +53 -0
- package/dist/ImagePreview/style.d.ts +30 -0
- package/dist/ImagePreview/style.js +286 -0
- package/dist/ImagePreview/typings.d.ts +19 -0
- package/dist/ImagePreview/typings.js +1 -0
- package/dist/ImagePreview/utils/KeyCode.d.ts +438 -0
- package/dist/ImagePreview/utils/KeyCode.js +173 -0
- package/dist/ImagePreview/utils/addEventListener.d.ts +6 -0
- package/dist/ImagePreview/utils/addEventListener.js +22 -0
- package/dist/ImagePreview/utils/util.d.ts +7 -0
- package/dist/ImagePreview/utils/util.js +8 -0
- package/dist/hooks/useFrameSetState.d.ts +5 -0
- package/dist/hooks/useFrameSetState.js +33 -0
- package/dist/image.esm.js +2374 -0
- package/dist/image.js +1 -0
- package/dist/index.d.ts +5 -7
- package/dist/index.js +6 -0
- package/dist/props.d.ts +82 -77
- package/dist/props.js +66 -0
- package/dist/slots.d.ts +6 -0
- package/dist/slots.js +21 -0
- package/dist/style.d.ts +9 -0
- package/dist/style.js +78 -0
- package/dist/typings.d.ts +6 -0
- package/dist/typings.js +1 -0
- package/dist/utils/aria.d.ts +14 -11
- package/dist/utils/aria.js +16 -0
- package/dist/utils/util.d.ts +4 -0
- package/dist/utils/util.js +8 -0
- package/global.d.ts +8 -0
- package/package.json +57 -60
- package/dist/Image.d.ts +0 -130
- package/dist/components/ImageViewer.d.ts +0 -59
- package/dist/components/ImageViewerGroup.d.ts +0 -14
- package/dist/design/config.less +0 -2
- package/dist/image.es.js +0 -801
- package/dist/image.umd.js +0 -1
- package/dist/style.css +0 -1
- package/dist/style.less +0 -177
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useWindowSize } from "@vueuse/core";
|
|
2
|
+
|
|
3
|
+
//#region src/ImagePreview/hooks/getFixScaleEleTransPosition.ts
|
|
4
|
+
function fixPoint(key, start, width, clientWidth) {
|
|
5
|
+
const startAddWidth = start + width;
|
|
6
|
+
const offsetStart = (width - clientWidth) / 2;
|
|
7
|
+
if (width > clientWidth) {
|
|
8
|
+
if (start > 0) return { [key]: offsetStart };
|
|
9
|
+
if (start < 0 && startAddWidth < clientWidth) return { [key]: -offsetStart };
|
|
10
|
+
} else if (start < 0 || startAddWidth > clientWidth) return { [key]: start < 0 ? offsetStart : -offsetStart };
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Fix positon x,y point when
|
|
15
|
+
*
|
|
16
|
+
* Ele width && height < client
|
|
17
|
+
* - Back origin
|
|
18
|
+
*
|
|
19
|
+
* - Ele width | height > clientWidth | clientHeight
|
|
20
|
+
* - left | top > 0 -> Back 0
|
|
21
|
+
* - left | top + width | height < clientWidth | clientHeight -> Back left | top + width | height === clientWidth | clientHeight
|
|
22
|
+
*
|
|
23
|
+
* Regardless of other
|
|
24
|
+
*/
|
|
25
|
+
function getFixScaleEleTransPosition(width, height, left, top) {
|
|
26
|
+
const { width: clientWidth, height: clientHeight } = useWindowSize();
|
|
27
|
+
let fixPos = null;
|
|
28
|
+
if (width <= clientWidth.value && height <= clientHeight.value) fixPos = {
|
|
29
|
+
x: 0,
|
|
30
|
+
y: 0
|
|
31
|
+
};
|
|
32
|
+
else if (width > clientWidth.value || height > clientHeight.value) fixPos = {
|
|
33
|
+
...fixPoint("x", left, width, clientWidth.value),
|
|
34
|
+
...fixPoint("y", top, height, clientHeight.value)
|
|
35
|
+
};
|
|
36
|
+
return fixPos;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { getFixScaleEleTransPosition as default };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Ref } from "vue";
|
|
2
|
+
|
|
3
|
+
//#region src/ImagePreview/hooks/useImageTransform.d.ts
|
|
4
|
+
interface TransformType {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
rotate: number;
|
|
8
|
+
scale: number;
|
|
9
|
+
flipX: boolean;
|
|
10
|
+
flipY: boolean;
|
|
11
|
+
}
|
|
12
|
+
type TransformAction = 'flipY' | 'flipX' | 'rotateLeft' | 'rotateRight' | 'zoomIn' | 'zoomOut' | 'close' | 'prev' | 'next' | 'wheel' | 'doubleClick' | 'move' | 'dragRebound' | 'touchZoom' | 'reset';
|
|
13
|
+
type UpdateTransformFunc = (newTransform: Partial<TransformType>, action: TransformAction) => void;
|
|
14
|
+
type DispatchZoomChangeFunc = (ratio: number, action: TransformAction, centerX?: number, centerY?: number, isTouch?: boolean) => void;
|
|
15
|
+
declare function useImageTransform(imgRef: Ref<HTMLImageElement>, minScale: Ref<number>, maxScale: Ref<number>, onTransform?: (info: {
|
|
16
|
+
transform: TransformType;
|
|
17
|
+
action: TransformAction;
|
|
18
|
+
}) => void): {
|
|
19
|
+
transform: Ref<{
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
rotate: number;
|
|
23
|
+
scale: number;
|
|
24
|
+
flipX: boolean;
|
|
25
|
+
flipY: boolean;
|
|
26
|
+
}, {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
rotate: number;
|
|
30
|
+
scale: number;
|
|
31
|
+
flipX: boolean;
|
|
32
|
+
flipY: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
resetTransform: (action: TransformAction) => void;
|
|
35
|
+
updateTransform: UpdateTransformFunc;
|
|
36
|
+
dispatchZoomChange: DispatchZoomChangeFunc;
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { DispatchZoomChangeFunc, TransformAction, TransformType, UpdateTransformFunc, useImageTransform as default };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { ref } from "vue";
|
|
2
|
+
import { raf } from "@gx-design-vue/pro-utils";
|
|
3
|
+
import { useWindowSize } from "@vueuse/core";
|
|
4
|
+
import { cloneDeep, isEqual } from "es-toolkit";
|
|
5
|
+
import { useState } from "@gx-design-vue/pro-hooks";
|
|
6
|
+
|
|
7
|
+
//#region src/ImagePreview/hooks/useImageTransform.ts
|
|
8
|
+
const initialTransform = {
|
|
9
|
+
x: 0,
|
|
10
|
+
y: 0,
|
|
11
|
+
rotate: 0,
|
|
12
|
+
scale: 1,
|
|
13
|
+
flipX: false,
|
|
14
|
+
flipY: false
|
|
15
|
+
};
|
|
16
|
+
function useImageTransform(imgRef, minScale, maxScale, onTransform) {
|
|
17
|
+
const frame = ref(null);
|
|
18
|
+
const queue = ref([]);
|
|
19
|
+
const [transform, setTransform] = useState(initialTransform);
|
|
20
|
+
const resetTransform = (action) => {
|
|
21
|
+
setTransform(initialTransform);
|
|
22
|
+
if (!isEqual(initialTransform, transform.value)) onTransform?.({
|
|
23
|
+
transform: initialTransform,
|
|
24
|
+
action
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
/** Direct update transform */
|
|
28
|
+
const updateTransform = (newTransform, action) => {
|
|
29
|
+
if (frame.value === null) {
|
|
30
|
+
queue.value = [];
|
|
31
|
+
frame.value = raf(() => {
|
|
32
|
+
let memoState = cloneDeep(transform.value);
|
|
33
|
+
queue.value.forEach((queueState) => {
|
|
34
|
+
memoState = {
|
|
35
|
+
...memoState,
|
|
36
|
+
...queueState
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
frame.value = null;
|
|
40
|
+
onTransform?.({
|
|
41
|
+
transform: memoState,
|
|
42
|
+
action
|
|
43
|
+
});
|
|
44
|
+
setTransform(memoState);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
queue.value.push({
|
|
48
|
+
...transform.value,
|
|
49
|
+
...newTransform
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
/** Scale according to the position of centerX and centerY */
|
|
53
|
+
const dispatchZoomChange = (ratio, action, centerX, centerY, isTouch) => {
|
|
54
|
+
const { width, height, offsetWidth, offsetHeight, offsetLeft, offsetTop } = imgRef.value;
|
|
55
|
+
let newRatio = ratio;
|
|
56
|
+
let newScale = transform.value.scale * ratio;
|
|
57
|
+
if (newScale > maxScale.value) {
|
|
58
|
+
newScale = maxScale.value;
|
|
59
|
+
newRatio = maxScale.value / transform.value.scale;
|
|
60
|
+
} else if (newScale < minScale.value) {
|
|
61
|
+
newScale = isTouch ? newScale : minScale.value;
|
|
62
|
+
newRatio = newScale / transform.value.scale;
|
|
63
|
+
}
|
|
64
|
+
/** Default center point scaling */
|
|
65
|
+
const mergedCenterX = centerX ?? innerWidth / 2;
|
|
66
|
+
const mergedCenterY = centerY ?? innerHeight / 2;
|
|
67
|
+
const diffRatio = newRatio - 1;
|
|
68
|
+
/** Deviation calculated from image size */
|
|
69
|
+
const diffImgX = diffRatio * width * .5;
|
|
70
|
+
const diffImgY = diffRatio * height * .5;
|
|
71
|
+
/** The difference between the click position and the edge of the document */
|
|
72
|
+
const diffOffsetLeft = diffRatio * (mergedCenterX - transform.value.x - offsetLeft);
|
|
73
|
+
const diffOffsetTop = diffRatio * (mergedCenterY - transform.value.y - offsetTop);
|
|
74
|
+
/** Final positioning */
|
|
75
|
+
let newX = transform.value.x - (diffOffsetLeft - diffImgX);
|
|
76
|
+
let newY = transform.value.y - (diffOffsetTop - diffImgY);
|
|
77
|
+
/**
|
|
78
|
+
* When zooming the image
|
|
79
|
+
* When the image size is smaller than the width and height of the window, the position is initialized
|
|
80
|
+
*/
|
|
81
|
+
if (ratio < 1 && newScale === 1) {
|
|
82
|
+
const mergedWidth = offsetWidth * newScale;
|
|
83
|
+
const mergedHeight = offsetHeight * newScale;
|
|
84
|
+
const { width: clientWidth, height: clientHeight } = useWindowSize();
|
|
85
|
+
if (mergedWidth <= clientWidth.value && mergedHeight <= clientHeight.value) {
|
|
86
|
+
newX = 0;
|
|
87
|
+
newY = 0;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
updateTransform({
|
|
91
|
+
x: newX,
|
|
92
|
+
y: newY,
|
|
93
|
+
scale: newScale
|
|
94
|
+
}, action);
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
transform,
|
|
98
|
+
resetTransform,
|
|
99
|
+
updateTransform,
|
|
100
|
+
dispatchZoomChange
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//#endregion
|
|
105
|
+
export { useImageTransform as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { DispatchZoomChangeFunc, TransformType, UpdateTransformFunc } from "./useImageTransform.js";
|
|
2
|
+
import { MouseEventHandler } from "../typings.js";
|
|
3
|
+
import { Ref } from "vue";
|
|
4
|
+
|
|
5
|
+
//#region src/ImagePreview/hooks/useMouseEvent.d.ts
|
|
6
|
+
declare function useMouseEvent(imgRef: Ref<HTMLImageElement>, movable: Ref<boolean>, visible: Ref<boolean>, scaleStep: Ref<number>, transform: Ref<TransformType>, updateTransform: UpdateTransformFunc, dispatchZoomChange: DispatchZoomChangeFunc): {
|
|
7
|
+
isMoving: Ref<boolean, boolean>;
|
|
8
|
+
onMouseDown: MouseEventHandler;
|
|
9
|
+
onMouseMove: MouseEventHandler;
|
|
10
|
+
onMouseUp: MouseEventHandler;
|
|
11
|
+
onWheel: (event: WheelEvent) => void;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { useMouseEvent as default };
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import addEventListenerWrap from "../utils/addEventListener.js";
|
|
2
|
+
import { BASE_SCALE_RATIO, WHEEL_MAX_SCALE_RATIO } from "../utils/util.js";
|
|
3
|
+
import getFixScaleEleTransPosition from "./getFixScaleEleTransPosition.js";
|
|
4
|
+
import { ref } from "vue";
|
|
5
|
+
import { useEffect, useState } from "@gx-design-vue/pro-hooks";
|
|
6
|
+
|
|
7
|
+
//#region src/ImagePreview/hooks/useMouseEvent.ts
|
|
8
|
+
function useMouseEvent(imgRef, movable, visible, scaleStep, transform, updateTransform, dispatchZoomChange) {
|
|
9
|
+
const [isMoving, setMoving] = useState(false);
|
|
10
|
+
const startPositionInfo = ref({
|
|
11
|
+
diffX: 0,
|
|
12
|
+
diffY: 0,
|
|
13
|
+
transformX: 0,
|
|
14
|
+
transformY: 0
|
|
15
|
+
});
|
|
16
|
+
const onMouseDown = (event) => {
|
|
17
|
+
if (!movable || event.button !== 0) return;
|
|
18
|
+
event.preventDefault();
|
|
19
|
+
event.stopPropagation();
|
|
20
|
+
startPositionInfo.value = {
|
|
21
|
+
diffX: event.pageX - transform.value.x,
|
|
22
|
+
diffY: event.pageY - transform.value.y,
|
|
23
|
+
transformX: transform.value.x,
|
|
24
|
+
transformY: transform.value.y
|
|
25
|
+
};
|
|
26
|
+
setMoving(true);
|
|
27
|
+
};
|
|
28
|
+
const onMouseMove = (event) => {
|
|
29
|
+
if (visible && isMoving.value) updateTransform({
|
|
30
|
+
x: event.pageX - startPositionInfo.value.diffX,
|
|
31
|
+
y: event.pageY - startPositionInfo.value.diffY
|
|
32
|
+
}, "move");
|
|
33
|
+
};
|
|
34
|
+
const onMouseUp = () => {
|
|
35
|
+
if (visible && isMoving.value) {
|
|
36
|
+
setMoving(false);
|
|
37
|
+
/** No need to restore the position when the picture is not moved, So as not to interfere with the click */
|
|
38
|
+
const { transformX, transformY } = startPositionInfo.value;
|
|
39
|
+
if (!(transform.value.x !== transformX && transform.value.y !== transformY)) return;
|
|
40
|
+
const width = imgRef.value.offsetWidth * transform.value.scale;
|
|
41
|
+
const height = imgRef.value.offsetHeight * transform.value.scale;
|
|
42
|
+
const { left, top } = imgRef.value.getBoundingClientRect();
|
|
43
|
+
const isRotate = transform.value.rotate % 180 !== 0;
|
|
44
|
+
const fixState = getFixScaleEleTransPosition(isRotate ? height : width, isRotate ? width : height, left, top);
|
|
45
|
+
if (fixState) updateTransform({ ...fixState }, "dragRebound");
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const onWheel = (event) => {
|
|
49
|
+
if (!visible || event.deltaY === 0) return;
|
|
50
|
+
const scaleRatio = Math.abs(event.deltaY / 100);
|
|
51
|
+
let ratio = BASE_SCALE_RATIO + Math.min(scaleRatio, WHEEL_MAX_SCALE_RATIO) * scaleStep.value;
|
|
52
|
+
if (event.deltaY > 0) ratio = BASE_SCALE_RATIO / ratio;
|
|
53
|
+
dispatchZoomChange(ratio, "wheel", event.clientX, event.clientY);
|
|
54
|
+
};
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
let onTopMouseUpListener;
|
|
57
|
+
let onTopMouseMoveListener;
|
|
58
|
+
let onMouseUpListener;
|
|
59
|
+
let onMouseMoveListener;
|
|
60
|
+
if (movable) {
|
|
61
|
+
onMouseUpListener = addEventListenerWrap(window, "mouseup", onMouseUp, false);
|
|
62
|
+
onMouseMoveListener = addEventListenerWrap(window, "mousemove", onMouseMove, false);
|
|
63
|
+
try {
|
|
64
|
+
/* istanbul ignore next */
|
|
65
|
+
if (window.top !== window.self) {
|
|
66
|
+
onTopMouseUpListener = addEventListenerWrap(window.top, "mouseup", onMouseUp, false);
|
|
67
|
+
onTopMouseMoveListener = addEventListenerWrap(window.top, "mousemove", onMouseMove, false);
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
/* istanbul ignore next */
|
|
71
|
+
console.warn(`[rc-image] ${error}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return () => {
|
|
75
|
+
onMouseUpListener?.remove();
|
|
76
|
+
onMouseMoveListener?.remove();
|
|
77
|
+
/* istanbul ignore next */
|
|
78
|
+
onTopMouseUpListener?.remove();
|
|
79
|
+
/* istanbul ignore next */
|
|
80
|
+
onTopMouseMoveListener?.remove();
|
|
81
|
+
};
|
|
82
|
+
}, [
|
|
83
|
+
visible,
|
|
84
|
+
isMoving,
|
|
85
|
+
() => transform.value.x,
|
|
86
|
+
() => transform.value.y,
|
|
87
|
+
() => transform.value.rotate,
|
|
88
|
+
movable
|
|
89
|
+
]);
|
|
90
|
+
return {
|
|
91
|
+
isMoving,
|
|
92
|
+
onMouseDown,
|
|
93
|
+
onMouseMove,
|
|
94
|
+
onMouseUp,
|
|
95
|
+
onWheel
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
export { useMouseEvent as default };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DispatchZoomChangeFunc, TransformType, UpdateTransformFunc } from "./useImageTransform.js";
|
|
2
|
+
import { Ref } from "vue";
|
|
3
|
+
|
|
4
|
+
//#region src/ImagePreview/hooks/useTouchEvent.d.ts
|
|
5
|
+
declare function useTouchEvent(imgRef: Ref<HTMLImageElement>, movable: Ref<boolean>, visible: Ref<boolean>, minScale: Ref<number>, transform: Ref<TransformType>, updateTransform: UpdateTransformFunc, dispatchZoomChange: DispatchZoomChangeFunc): {
|
|
6
|
+
isTouching: Ref<boolean, boolean>;
|
|
7
|
+
onTouchStart: (event: TouchEvent) => void;
|
|
8
|
+
onTouchMove: (event: TouchEvent) => void;
|
|
9
|
+
onTouchEnd: () => void;
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { useTouchEvent as default };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import addEventListenerWrap from "../utils/addEventListener.js";
|
|
2
|
+
import getFixScaleEleTransPosition from "./getFixScaleEleTransPosition.js";
|
|
3
|
+
import { ref } from "vue";
|
|
4
|
+
import { useEffect, useState } from "@gx-design-vue/pro-hooks";
|
|
5
|
+
|
|
6
|
+
//#region src/ImagePreview/hooks/useTouchEvent.ts
|
|
7
|
+
function getDistance(a, b) {
|
|
8
|
+
const x = a.x - b.x;
|
|
9
|
+
const y = a.y - b.y;
|
|
10
|
+
return Math.hypot(x, y);
|
|
11
|
+
}
|
|
12
|
+
function getCenter(oldPoint1, oldPoint2, newPoint1, newPoint2) {
|
|
13
|
+
const distance1 = getDistance(oldPoint1, newPoint1);
|
|
14
|
+
const distance2 = getDistance(oldPoint2, newPoint2);
|
|
15
|
+
if (distance1 === 0 && distance2 === 0) return [oldPoint1.x, oldPoint1.y];
|
|
16
|
+
const ratio = distance1 / (distance1 + distance2);
|
|
17
|
+
return [oldPoint1.x + ratio * (oldPoint2.x - oldPoint1.x), oldPoint1.y + ratio * (oldPoint2.y - oldPoint1.y)];
|
|
18
|
+
}
|
|
19
|
+
function useTouchEvent(imgRef, movable, visible, minScale, transform, updateTransform, dispatchZoomChange) {
|
|
20
|
+
const [isTouching, setIsTouching] = useState(false);
|
|
21
|
+
const touchPointInfo = ref({
|
|
22
|
+
point1: {
|
|
23
|
+
x: 0,
|
|
24
|
+
y: 0
|
|
25
|
+
},
|
|
26
|
+
point2: {
|
|
27
|
+
x: 0,
|
|
28
|
+
y: 0
|
|
29
|
+
},
|
|
30
|
+
eventType: "none"
|
|
31
|
+
});
|
|
32
|
+
const updateTouchPointInfo = (values) => {
|
|
33
|
+
touchPointInfo.value = {
|
|
34
|
+
...touchPointInfo.value,
|
|
35
|
+
...values
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
const onTouchStart = (event) => {
|
|
39
|
+
if (!movable.value) return;
|
|
40
|
+
event.stopPropagation();
|
|
41
|
+
setIsTouching(true);
|
|
42
|
+
const { touches = [] } = event;
|
|
43
|
+
if (touches.length > 1) updateTouchPointInfo({
|
|
44
|
+
point1: {
|
|
45
|
+
x: touches[0].clientX,
|
|
46
|
+
y: touches[0].clientY
|
|
47
|
+
},
|
|
48
|
+
point2: {
|
|
49
|
+
x: touches[1].clientX,
|
|
50
|
+
y: touches[1].clientY
|
|
51
|
+
},
|
|
52
|
+
eventType: "touchZoom"
|
|
53
|
+
});
|
|
54
|
+
else updateTouchPointInfo({
|
|
55
|
+
point1: {
|
|
56
|
+
x: touches[0].clientX - transform.value.x,
|
|
57
|
+
y: touches[0].clientY - transform.value.y
|
|
58
|
+
},
|
|
59
|
+
eventType: "move"
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
const onTouchMove = (event) => {
|
|
63
|
+
const { touches = [] } = event;
|
|
64
|
+
const { point1, point2, eventType } = touchPointInfo.value;
|
|
65
|
+
if (touches.length > 1 && eventType === "touchZoom") {
|
|
66
|
+
const newPoint1 = {
|
|
67
|
+
x: touches[0].clientX,
|
|
68
|
+
y: touches[0].clientY
|
|
69
|
+
};
|
|
70
|
+
const newPoint2 = {
|
|
71
|
+
x: touches[1].clientX,
|
|
72
|
+
y: touches[1].clientY
|
|
73
|
+
};
|
|
74
|
+
const [centerX, centerY] = getCenter(point1, point2, newPoint1, newPoint2);
|
|
75
|
+
dispatchZoomChange(getDistance(newPoint1, newPoint2) / getDistance(point1, point2), "touchZoom", centerX, centerY, true);
|
|
76
|
+
updateTouchPointInfo({
|
|
77
|
+
point1: newPoint1,
|
|
78
|
+
point2: newPoint2,
|
|
79
|
+
eventType: "touchZoom"
|
|
80
|
+
});
|
|
81
|
+
} else if (eventType === "move") {
|
|
82
|
+
updateTransform({
|
|
83
|
+
x: touches[0].clientX - point1.x,
|
|
84
|
+
y: touches[0].clientY - point1.y
|
|
85
|
+
}, "move");
|
|
86
|
+
updateTouchPointInfo({ eventType: "move" });
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const onTouchEnd = () => {
|
|
90
|
+
if (!visible.value) return;
|
|
91
|
+
if (isTouching) setIsTouching(false);
|
|
92
|
+
updateTouchPointInfo({ eventType: "none" });
|
|
93
|
+
if (minScale.value > transform.value.scale)
|
|
94
|
+
/** When the scaling ratio is less than the minimum scaling ratio, reset the scaling ratio */
|
|
95
|
+
return updateTransform({
|
|
96
|
+
x: 0,
|
|
97
|
+
y: 0,
|
|
98
|
+
scale: minScale.value
|
|
99
|
+
}, "touchZoom");
|
|
100
|
+
const width = imgRef.value.offsetWidth * transform.value.scale;
|
|
101
|
+
const height = imgRef.value.offsetHeight * transform.value.scale;
|
|
102
|
+
const { left, top } = imgRef.value.getBoundingClientRect();
|
|
103
|
+
const isRotate = transform.value.rotate % 180 !== 0;
|
|
104
|
+
const fixState = getFixScaleEleTransPosition(isRotate ? height : width, isRotate ? width : height, left, top);
|
|
105
|
+
if (fixState) updateTransform({ ...fixState }, "dragRebound");
|
|
106
|
+
};
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
let onTouchMoveListener;
|
|
109
|
+
if (visible.value && movable.value) onTouchMoveListener = addEventListenerWrap(window, "touchmove", (e) => e.preventDefault(), { passive: false });
|
|
110
|
+
return () => {
|
|
111
|
+
onTouchMoveListener?.remove();
|
|
112
|
+
};
|
|
113
|
+
}, [visible, movable]);
|
|
114
|
+
return {
|
|
115
|
+
isTouching,
|
|
116
|
+
onTouchStart,
|
|
117
|
+
onTouchMove,
|
|
118
|
+
onTouchEnd
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
export { useTouchEvent as default };
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { TransformAction, TransformType } from "./hooks/useImageTransform.js";
|
|
2
|
+
import _default, { PreviewPropsIcons } from "./props.js";
|
|
3
|
+
import * as vue6 from "vue";
|
|
4
|
+
import { ExtractPropTypes, SlotsType } from "vue";
|
|
5
|
+
import * as _gx_design_vue_pro_utils3 from "@gx-design-vue/pro-utils";
|
|
6
|
+
import * as ant_design_vue_es__util_type0 from "ant-design-vue/es/_util/type";
|
|
7
|
+
|
|
8
|
+
//#region src/ImagePreview/index.d.ts
|
|
9
|
+
type ImagePreviewProps = Partial<ExtractPropTypes<typeof _default>>;
|
|
10
|
+
declare const GImagePreview: vue6.DefineComponent<ExtractPropTypes<{
|
|
11
|
+
urls: {
|
|
12
|
+
type: vue6.PropType<string[]>;
|
|
13
|
+
default: () => any[];
|
|
14
|
+
};
|
|
15
|
+
open: {
|
|
16
|
+
type: vue6.PropType<boolean>;
|
|
17
|
+
default: boolean;
|
|
18
|
+
};
|
|
19
|
+
scaleStep: {
|
|
20
|
+
type: vue6.PropType<number>;
|
|
21
|
+
default: number;
|
|
22
|
+
};
|
|
23
|
+
minScale: {
|
|
24
|
+
type: vue6.PropType<number>;
|
|
25
|
+
default: number;
|
|
26
|
+
};
|
|
27
|
+
maxScale: {
|
|
28
|
+
type: vue6.PropType<number>;
|
|
29
|
+
default: number;
|
|
30
|
+
};
|
|
31
|
+
movable: {
|
|
32
|
+
type: vue6.PropType<boolean>;
|
|
33
|
+
default: boolean;
|
|
34
|
+
};
|
|
35
|
+
disabled: vue6.PropType<boolean>;
|
|
36
|
+
zIndex: {
|
|
37
|
+
type: vue6.PropType<number>;
|
|
38
|
+
default: number;
|
|
39
|
+
};
|
|
40
|
+
current: {
|
|
41
|
+
type: vue6.PropType<number>;
|
|
42
|
+
default: number;
|
|
43
|
+
};
|
|
44
|
+
infinite: {
|
|
45
|
+
type: vue6.PropType<boolean>;
|
|
46
|
+
default: boolean;
|
|
47
|
+
};
|
|
48
|
+
getContainer: {
|
|
49
|
+
type: vue6.PropType<string>;
|
|
50
|
+
};
|
|
51
|
+
onHideOnClickModal: {
|
|
52
|
+
type: vue6.PropType<boolean>;
|
|
53
|
+
default: boolean;
|
|
54
|
+
};
|
|
55
|
+
countRender: vue6.PropType<_gx_design_vue_pro_utils3.WithFalse<(current: number, total: number) => _gx_design_vue_pro_utils3.CustomRender>>;
|
|
56
|
+
icons: {
|
|
57
|
+
type: vue6.PropType<PreviewPropsIcons>;
|
|
58
|
+
default: () => PreviewPropsIcons;
|
|
59
|
+
};
|
|
60
|
+
onTransform: vue6.PropType<(info: {
|
|
61
|
+
transform: TransformType;
|
|
62
|
+
action: TransformAction;
|
|
63
|
+
}) => void>;
|
|
64
|
+
onOpenChange: vue6.PropType<(val: boolean) => void>;
|
|
65
|
+
'onUpdate:open': vue6.PropType<(val: boolean) => void>;
|
|
66
|
+
}>, () => ant_design_vue_es__util_type0.VueNode, {}, {}, {}, vue6.ComponentOptionsMixin, vue6.ComponentOptionsMixin, {
|
|
67
|
+
close: () => true;
|
|
68
|
+
transform: (_info: {
|
|
69
|
+
transform: TransformType;
|
|
70
|
+
action: TransformAction;
|
|
71
|
+
}) => true;
|
|
72
|
+
'update:open': (_val: boolean) => true;
|
|
73
|
+
}, string, vue6.PublicProps, Readonly<ExtractPropTypes<{
|
|
74
|
+
urls: {
|
|
75
|
+
type: vue6.PropType<string[]>;
|
|
76
|
+
default: () => any[];
|
|
77
|
+
};
|
|
78
|
+
open: {
|
|
79
|
+
type: vue6.PropType<boolean>;
|
|
80
|
+
default: boolean;
|
|
81
|
+
};
|
|
82
|
+
scaleStep: {
|
|
83
|
+
type: vue6.PropType<number>;
|
|
84
|
+
default: number;
|
|
85
|
+
};
|
|
86
|
+
minScale: {
|
|
87
|
+
type: vue6.PropType<number>;
|
|
88
|
+
default: number;
|
|
89
|
+
};
|
|
90
|
+
maxScale: {
|
|
91
|
+
type: vue6.PropType<number>;
|
|
92
|
+
default: number;
|
|
93
|
+
};
|
|
94
|
+
movable: {
|
|
95
|
+
type: vue6.PropType<boolean>;
|
|
96
|
+
default: boolean;
|
|
97
|
+
};
|
|
98
|
+
disabled: vue6.PropType<boolean>;
|
|
99
|
+
zIndex: {
|
|
100
|
+
type: vue6.PropType<number>;
|
|
101
|
+
default: number;
|
|
102
|
+
};
|
|
103
|
+
current: {
|
|
104
|
+
type: vue6.PropType<number>;
|
|
105
|
+
default: number;
|
|
106
|
+
};
|
|
107
|
+
infinite: {
|
|
108
|
+
type: vue6.PropType<boolean>;
|
|
109
|
+
default: boolean;
|
|
110
|
+
};
|
|
111
|
+
getContainer: {
|
|
112
|
+
type: vue6.PropType<string>;
|
|
113
|
+
};
|
|
114
|
+
onHideOnClickModal: {
|
|
115
|
+
type: vue6.PropType<boolean>;
|
|
116
|
+
default: boolean;
|
|
117
|
+
};
|
|
118
|
+
countRender: vue6.PropType<_gx_design_vue_pro_utils3.WithFalse<(current: number, total: number) => _gx_design_vue_pro_utils3.CustomRender>>;
|
|
119
|
+
icons: {
|
|
120
|
+
type: vue6.PropType<PreviewPropsIcons>;
|
|
121
|
+
default: () => PreviewPropsIcons;
|
|
122
|
+
};
|
|
123
|
+
onTransform: vue6.PropType<(info: {
|
|
124
|
+
transform: TransformType;
|
|
125
|
+
action: TransformAction;
|
|
126
|
+
}) => void>;
|
|
127
|
+
onOpenChange: vue6.PropType<(val: boolean) => void>;
|
|
128
|
+
'onUpdate:open': vue6.PropType<(val: boolean) => void>;
|
|
129
|
+
}>> & Readonly<{
|
|
130
|
+
onClose?: () => any;
|
|
131
|
+
onTransform?: (_info: {
|
|
132
|
+
transform: TransformType;
|
|
133
|
+
action: TransformAction;
|
|
134
|
+
}) => any;
|
|
135
|
+
"onUpdate:open"?: (_val: boolean) => any;
|
|
136
|
+
}>, {
|
|
137
|
+
zIndex: number;
|
|
138
|
+
icons: PreviewPropsIcons;
|
|
139
|
+
infinite: boolean;
|
|
140
|
+
current: number;
|
|
141
|
+
open: boolean;
|
|
142
|
+
urls: string[];
|
|
143
|
+
scaleStep: number;
|
|
144
|
+
minScale: number;
|
|
145
|
+
maxScale: number;
|
|
146
|
+
movable: boolean;
|
|
147
|
+
onHideOnClickModal: boolean;
|
|
148
|
+
}, SlotsType<{
|
|
149
|
+
close: () => void;
|
|
150
|
+
left: () => void;
|
|
151
|
+
right: () => void;
|
|
152
|
+
countRender: () => void;
|
|
153
|
+
rotateRight: () => void;
|
|
154
|
+
zoomIn: () => void;
|
|
155
|
+
zoomOut: () => void;
|
|
156
|
+
flipX: () => void;
|
|
157
|
+
flipY: () => void;
|
|
158
|
+
rotateLeft: () => void;
|
|
159
|
+
placeholder: () => void;
|
|
160
|
+
}>, {}, {}, string, vue6.ComponentProvideOptions, true, {}, any>;
|
|
161
|
+
//#endregion
|
|
162
|
+
export { ImagePreviewProps, GImagePreview as default };
|