1 | import { isSafari, isFirefox } from './BrowserDetector';
|
2 | import { MonotonicInterpolant } from './MonotonicInterpolant';
|
3 | const ELEMENT_NODE = 1;
|
4 | export function getNodeClientOffset(node) {
|
5 | const el = node.nodeType === ELEMENT_NODE ? node : node.parentElement;
|
6 | if (!el) {
|
7 | return null;
|
8 | }
|
9 | const { top, left } = el.getBoundingClientRect();
|
10 | return { x: left, y: top };
|
11 | }
|
12 | export function getEventClientOffset(e) {
|
13 | return {
|
14 | x: e.clientX,
|
15 | y: e.clientY,
|
16 | };
|
17 | }
|
18 | function isImageNode(node) {
|
19 | return (node.nodeName === 'IMG' &&
|
20 | (isFirefox() || !document.documentElement?.contains(node)));
|
21 | }
|
22 | function getDragPreviewSize(isImage, dragPreview, sourceWidth, sourceHeight) {
|
23 | let dragPreviewWidth = isImage ? dragPreview.width : sourceWidth;
|
24 | let dragPreviewHeight = isImage ? dragPreview.height : sourceHeight;
|
25 |
|
26 | if (isSafari() && isImage) {
|
27 | dragPreviewHeight /= window.devicePixelRatio;
|
28 | dragPreviewWidth /= window.devicePixelRatio;
|
29 | }
|
30 | return { dragPreviewWidth, dragPreviewHeight };
|
31 | }
|
32 | export function getDragPreviewOffset(sourceNode, dragPreview, clientOffset, anchorPoint, offsetPoint) {
|
33 |
|
34 |
|
35 | const isImage = isImageNode(dragPreview);
|
36 | const dragPreviewNode = isImage ? sourceNode : dragPreview;
|
37 | const dragPreviewNodeOffsetFromClient = getNodeClientOffset(dragPreviewNode);
|
38 | const offsetFromDragPreview = {
|
39 | x: clientOffset.x - dragPreviewNodeOffsetFromClient.x,
|
40 | y: clientOffset.y - dragPreviewNodeOffsetFromClient.y,
|
41 | };
|
42 | const { offsetWidth: sourceWidth, offsetHeight: sourceHeight } = sourceNode;
|
43 | const { anchorX, anchorY } = anchorPoint;
|
44 | const { dragPreviewWidth, dragPreviewHeight } = getDragPreviewSize(isImage, dragPreview, sourceWidth, sourceHeight);
|
45 | const calculateYOffset = () => {
|
46 | const interpolantY = new MonotonicInterpolant([0, 0.5, 1], [
|
47 |
|
48 | offsetFromDragPreview.y,
|
49 |
|
50 | (offsetFromDragPreview.y / sourceHeight) * dragPreviewHeight,
|
51 |
|
52 | offsetFromDragPreview.y + dragPreviewHeight - sourceHeight,
|
53 | ]);
|
54 | let y = interpolantY.interpolate(anchorY);
|
55 |
|
56 | if (isSafari() && isImage) {
|
57 |
|
58 | y += (window.devicePixelRatio - 1) * dragPreviewHeight;
|
59 | }
|
60 | return y;
|
61 | };
|
62 | const calculateXOffset = () => {
|
63 |
|
64 |
|
65 | const interpolantX = new MonotonicInterpolant([0, 0.5, 1], [
|
66 |
|
67 | offsetFromDragPreview.x,
|
68 |
|
69 | (offsetFromDragPreview.x / sourceWidth) * dragPreviewWidth,
|
70 |
|
71 | offsetFromDragPreview.x + dragPreviewWidth - sourceWidth,
|
72 | ]);
|
73 | return interpolantX.interpolate(anchorX);
|
74 | };
|
75 |
|
76 | const { offsetX, offsetY } = offsetPoint;
|
77 | const isManualOffsetX = offsetX === 0 || offsetX;
|
78 | const isManualOffsetY = offsetY === 0 || offsetY;
|
79 | return {
|
80 | x: isManualOffsetX ? offsetX : calculateXOffset(),
|
81 | y: isManualOffsetY ? offsetY : calculateYOffset(),
|
82 | };
|
83 | }
|