Blame view

天文台pc/tianwentai-ui/node_modules/react-dnd-html5-backend/src/OffsetUtils.ts 3.52 KB
bc518174   王天杨   提交两个项目文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  import type { XYCoord } from 'dnd-core'
  
  import { isFirefox, isSafari } from './BrowserDetector.js'
  import { MonotonicInterpolant } from './MonotonicInterpolant.js'
  
  const ELEMENT_NODE = 1
  
  export function getNodeClientOffset(node: Node): XYCoord | null {
  	const el = node.nodeType === ELEMENT_NODE ? node : node.parentElement
  
  	if (!el) {
  		return null
  	}
  
  	const { top, left } = (el as HTMLElement).getBoundingClientRect()
  	return { x: left, y: top }
  }
  
  export function getEventClientOffset(e: MouseEvent): XYCoord {
  	return {
  		x: e.clientX,
  		y: e.clientY,
  	}
  }
  
  function isImageNode(node: any) {
  	return (
  		node.nodeName === 'IMG' &&
  		(isFirefox() || !document.documentElement?.contains(node))
  	)
  }
  
  function getDragPreviewSize(
  	isImage: boolean,
  	dragPreview: any,
  	sourceWidth: number,
  	sourceHeight: number,
  ) {
  	let dragPreviewWidth = isImage ? dragPreview.width : sourceWidth
  	let dragPreviewHeight = isImage ? dragPreview.height : sourceHeight
  
  	// Work around @2x coordinate discrepancies in browsers
  	if (isSafari() && isImage) {
  		dragPreviewHeight /= window.devicePixelRatio
  		dragPreviewWidth /= window.devicePixelRatio
  	}
  	return { dragPreviewWidth, dragPreviewHeight }
  }
  
  export function getDragPreviewOffset(
  	sourceNode: HTMLElement,
  	dragPreview: HTMLElement,
  	clientOffset: XYCoord,
  	anchorPoint: { anchorX: number; anchorY: number },
  	offsetPoint: { offsetX: number; offsetY: number },
  ): XYCoord {
  	// The browsers will use the image intrinsic size under different conditions.
  	// Firefox only cares if it's an image, but WebKit also wants it to be detached.
  	const isImage = isImageNode(dragPreview)
  	const dragPreviewNode = isImage ? sourceNode : dragPreview
  	const dragPreviewNodeOffsetFromClient = getNodeClientOffset(
  		dragPreviewNode,
  	) as XYCoord
  	const offsetFromDragPreview = {
  		x: clientOffset.x - dragPreviewNodeOffsetFromClient.x,
  		y: clientOffset.y - dragPreviewNodeOffsetFromClient.y,
  	}
  	const { offsetWidth: sourceWidth, offsetHeight: sourceHeight } = sourceNode
  	const { anchorX, anchorY } = anchorPoint
  	const { dragPreviewWidth, dragPreviewHeight } = getDragPreviewSize(
  		isImage,
  		dragPreview,
  		sourceWidth,
  		sourceHeight,
  	)
  
  	const calculateYOffset = () => {
  		const interpolantY = new MonotonicInterpolant(
  			[0, 0.5, 1],
  			[
  				// Dock to the top
  				offsetFromDragPreview.y,
  				// Align at the center
  				(offsetFromDragPreview.y / sourceHeight) * dragPreviewHeight,
  				// Dock to the bottom
  				offsetFromDragPreview.y + dragPreviewHeight - sourceHeight,
  			],
  		)
  		let y = interpolantY.interpolate(anchorY)
  		// Work around Safari 8 positioning bug
  		if (isSafari() && isImage) {
  			// We'll have to wait for @3x to see if this is entirely correct
  			y += (window.devicePixelRatio - 1) * dragPreviewHeight
  		}
  		return y
  	}
  
  	const calculateXOffset = () => {
  		// Interpolate coordinates depending on anchor point
  		// If you know a simpler way to do this, let me know
  		const interpolantX = new MonotonicInterpolant(
  			[0, 0.5, 1],
  			[
  				// Dock to the left
  				offsetFromDragPreview.x,
  				// Align at the center
  				(offsetFromDragPreview.x / sourceWidth) * dragPreviewWidth,
  				// Dock to the right
  				offsetFromDragPreview.x + dragPreviewWidth - sourceWidth,
  			],
  		)
  		return interpolantX.interpolate(anchorX)
  	}
  
  	// Force offsets if specified in the options.
  	const { offsetX, offsetY } = offsetPoint
  	const isManualOffsetX = offsetX === 0 || offsetX
  	const isManualOffsetY = offsetY === 0 || offsetY
  	return {
  		x: isManualOffsetX ? offsetX : calculateXOffset(),
  		y: isManualOffsetY ? offsetY : calculateYOffset(),
  	}
  }