enhance(client): improve tooltip position calclation
This commit is contained in:
		| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
| <MkTooltip ref="tooltip" :showing="showing" :x="x" :y="y" :max-width="340" @closed="emit('closed')"> | ||||
| <MkTooltip ref="tooltip" :showing="showing" :x="x" :y="y" :max-width="340" :direction="'left'" :inner-margin="16" @closed="emit('closed')"> | ||||
| 	<div v-if="title" class="qpcyisrl"> | ||||
| 		<div class="title">{{ title }}</div> | ||||
| 		<div v-for="x in series" class="series"> | ||||
|   | ||||
| @@ -17,8 +17,12 @@ const props = withDefaults(defineProps<{ | ||||
| 	y?: number; | ||||
| 	text?: string; | ||||
| 	maxWidth?: number; | ||||
| 	direction?: 'top' | 'bottom' | 'right' | 'left'; | ||||
| 	innerMargin?: number; | ||||
| }>(), { | ||||
| 	maxWidth: 250, | ||||
| 	direction: 'top', | ||||
| 	innerMargin: 0, | ||||
| }); | ||||
|  | ||||
| const emit = defineEmits<{ | ||||
| @@ -34,21 +38,22 @@ const setPosition = () => { | ||||
| 	const contentWidth = el.value.offsetWidth; | ||||
| 	const contentHeight = el.value.offsetHeight; | ||||
|  | ||||
| 	let left: number; | ||||
| 	let top: number; | ||||
|  | ||||
| 	let rect: DOMRect; | ||||
|  | ||||
| 	if (props.targetElement) { | ||||
| 		rect = props.targetElement.getBoundingClientRect(); | ||||
| 	} | ||||
|  | ||||
| 	const calcPosWhenTop = () => { | ||||
| 		let left: number; | ||||
| 		let top: number; | ||||
|  | ||||
| 		if (props.targetElement) { | ||||
| 			left = rect.left + window.pageXOffset + (props.targetElement.offsetWidth / 2); | ||||
| 		top = rect.top + window.pageYOffset - contentHeight; | ||||
|  | ||||
| 		el.value.style.transformOrigin = 'center bottom'; | ||||
| 			top = (rect.top + window.pageYOffset - contentHeight) - props.innerMargin; | ||||
| 		} else { | ||||
| 			left = props.x; | ||||
| 		top = props.y - contentHeight; | ||||
| 			top = (props.y - contentHeight) - props.innerMargin; | ||||
| 		} | ||||
|  | ||||
| 		left -= (el.value.offsetWidth / 2); | ||||
| @@ -57,16 +62,120 @@ const setPosition = () => { | ||||
| 			left = window.innerWidth - contentWidth + window.pageXOffset - 1; | ||||
| 		} | ||||
|  | ||||
| 		return [left, top]; | ||||
| 	} | ||||
|  | ||||
| 	const calcPosWhenBottom = () => { | ||||
| 		let left: number; | ||||
| 		let top: number; | ||||
|  | ||||
| 		if (props.targetElement) { | ||||
| 			left = rect.left + window.pageXOffset + (props.targetElement.offsetWidth / 2); | ||||
| 			top = (rect.top + window.pageYOffset + props.targetElement.offsetHeight) + props.innerMargin; | ||||
| 		} else { | ||||
| 			left = props.x; | ||||
| 			top = (props.y) + props.innerMargin; | ||||
| 		} | ||||
|  | ||||
| 		left -= (el.value.offsetWidth / 2); | ||||
|  | ||||
| 		if (left + contentWidth - window.pageXOffset > window.innerWidth) { | ||||
| 			left = window.innerWidth - contentWidth + window.pageXOffset - 1; | ||||
| 		} | ||||
|  | ||||
| 		return [left, top]; | ||||
| 	} | ||||
|  | ||||
| 	const calcPosWhenLeft = () => { | ||||
| 		let left: number; | ||||
| 		let top: number; | ||||
|  | ||||
| 		if (props.targetElement) { | ||||
| 			left = (rect.left + window.pageXOffset - contentWidth) - props.innerMargin; | ||||
| 			top = rect.top + window.pageYOffset + (props.targetElement.offsetHeight / 2); | ||||
| 		} else { | ||||
| 			left = (props.x - contentWidth) - props.innerMargin; | ||||
| 			top = props.y; | ||||
| 		} | ||||
|  | ||||
| 		top -= (el.value.offsetHeight / 2); | ||||
|  | ||||
| 		if (top + contentHeight - window.pageYOffset > window.innerHeight) { | ||||
| 			top = window.innerHeight - contentHeight + window.pageYOffset - 1; | ||||
| 		} | ||||
|  | ||||
| 		return [left, top]; | ||||
| 	} | ||||
|  | ||||
| 	const calcPosWhenRight = () => { | ||||
| 		let left: number; | ||||
| 		let top: number; | ||||
|  | ||||
| 		if (props.targetElement) { | ||||
| 			left = (rect.left + window.pageXOffset) + props.innerMargin; | ||||
| 			top = rect.top + window.pageYOffset + (props.targetElement.offsetHeight / 2); | ||||
| 		} else { | ||||
| 			left = props.x + props.innerMargin; | ||||
| 			top = props.y; | ||||
| 		} | ||||
|  | ||||
| 		top -= (el.value.offsetHeight / 2); | ||||
|  | ||||
| 		if (top + contentHeight - window.pageYOffset > window.innerHeight) { | ||||
| 			top = window.innerHeight - contentHeight + window.pageYOffset - 1; | ||||
| 		} | ||||
|  | ||||
| 		return [left, top]; | ||||
| 	} | ||||
|  | ||||
| 	const calc = (): { | ||||
| 		left: number; | ||||
| 		top: number; | ||||
| 		transformOrigin: string; | ||||
| 	} => { | ||||
| 		switch (props.direction) { | ||||
| 			case 'top': { | ||||
| 				const [left, top] = calcPosWhenTop(); | ||||
|  | ||||
| 				// ツールチップを上に向かって表示するスペースがなければ下に向かって出す | ||||
| 				if (top - window.pageYOffset < 0) { | ||||
| 		if (props.targetElement) { | ||||
| 			top = rect.top + window.pageYOffset + props.targetElement.offsetHeight; | ||||
| 			el.value.style.transformOrigin = 'center top'; | ||||
| 		} else { | ||||
| 			top = props.y; | ||||
| 					const [left, top] = calcPosWhenBottom(); | ||||
| 					return { left, top, transformOrigin: 'center top' }; | ||||
| 				} | ||||
|  | ||||
| 				return { left, top, transformOrigin: 'center bottom' }; | ||||
| 			} | ||||
|  | ||||
| 			case 'bottom': { | ||||
| 				const [left, top] = calcPosWhenBottom(); | ||||
| 				// TODO: ツールチップを下に向かって表示するスペースがなければ上に向かって出す | ||||
| 				return { left, top, transformOrigin: 'center top' }; | ||||
| 			} | ||||
|  | ||||
| 			case 'left': { | ||||
| 				const [left, top] = calcPosWhenLeft(); | ||||
|  | ||||
| 				// ツールチップを左に向かって表示するスペースがなければ右に向かって出す | ||||
| 				if (left - window.pageXOffset < 0) { | ||||
| 					const [left, top] = calcPosWhenRight(); | ||||
| 					return { left, top, transformOrigin: 'left center' }; | ||||
| 				} | ||||
|  | ||||
| 				return { left, top, transformOrigin: 'right center' }; | ||||
| 			} | ||||
|  | ||||
| 			case 'right': { | ||||
| 				const [left, top] = calcPosWhenRight(); | ||||
| 				// TODO: ツールチップを右に向かって表示するスペースがなければ左に向かって出す | ||||
| 				return { left, top, transformOrigin: 'left center' }; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return null as never; | ||||
| 	} | ||||
|  | ||||
| 	const { left, top, transformOrigin } = calc(); | ||||
| 	el.value.style.transformOrigin = transformOrigin; | ||||
| 	el.value.style.left = left + 'px'; | ||||
| 	el.value.style.top = top + 'px'; | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo