feature(tooltip): implement calculate tooltip position and tooltip arrow position
This commit is contained in:
parent
26bbfaea20
commit
4367870061
|
@ -1,16 +1,63 @@
|
|||
import { computed, SetupContext } from "vue";
|
||||
import { computed, ref, SetupContext } from "vue";
|
||||
import { TooltipPlacement, TooltipProps } from "../tooltip.props";
|
||||
|
||||
export function useTooltipPosition(props: TooltipProps, context: SetupContext) {
|
||||
type RectDirection = 'top' | 'bottom' | 'right' | 'left';
|
||||
type RectSizeProperty = 'height' | 'width';
|
||||
interface RectPosition {
|
||||
top: number;
|
||||
left: number;
|
||||
right: number;
|
||||
}
|
||||
|
||||
export function useTooltipPosition(
|
||||
props: TooltipProps,
|
||||
context: SetupContext,
|
||||
hostBound: DOMRect,
|
||||
tooltipBound: DOMRect,
|
||||
arrowBound: DOMRect) {
|
||||
|
||||
const space = 2;
|
||||
|
||||
const rectifyGutter = 20;
|
||||
|
||||
const revertDirectionMap = new Map<RectDirection, RectDirection>(
|
||||
[['top', 'bottom'], ['bottom', 'top'], ['left', 'right'], ['right', 'left']]
|
||||
);
|
||||
|
||||
const directionBoundMap = new Map<RectDirection, RectSizeProperty>(
|
||||
[['top', 'height'], ['bottom', 'height'], ['left', 'width'], ['right', 'width']]
|
||||
);
|
||||
|
||||
const placement = ref(props.placement);
|
||||
|
||||
const tooltipPlacement = computed(() => {
|
||||
return props.placement;
|
||||
});
|
||||
|
||||
function revertPlacement(placement: string, direction: RectDirection) {
|
||||
const revertDirection: RectDirection = revertDirectionMap.get(direction) || direction;
|
||||
const revertedPlacement = placement.replace(direction, revertDirection);
|
||||
return revertDirection;
|
||||
}
|
||||
|
||||
function autoRectifyDirection(
|
||||
placement: TooltipPlacement,
|
||||
referenceBoundingRect: DOMRect,
|
||||
arrowReferenceBoundingRect: DOMRect,
|
||||
tooltipBound: DOMRect,
|
||||
arrowBound: DOMRect) {
|
||||
let rectifyPlacement = placement;
|
||||
const direction = placement.split('-')[0] as RectDirection;
|
||||
const boundProperty = directionBoundMap.get(direction) as RectSizeProperty;
|
||||
const boundSize = tooltipBound[boundProperty] + arrowBound[boundProperty];
|
||||
const referenceBoundSize = Math.abs(arrowReferenceBoundingRect[direction] - referenceBoundingRect[direction]);
|
||||
|
||||
if (referenceBoundSize < boundSize) {
|
||||
rectifyPlacement = revertPlacement(rectifyPlacement, direction);
|
||||
}
|
||||
return rectifyPlacement;
|
||||
}
|
||||
|
||||
function calculateTooltipTopPositoin(placement: TooltipPlacement, hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
||||
let offsetY = 0;
|
||||
const verticalAlignment = placement.indexOf('bottom') > -1 ? 'bottom' : (placement.indexOf('top') > -1 ? 'top' : 'middle');
|
||||
|
@ -94,9 +141,10 @@ export function useTooltipPosition(props: TooltipProps, context: SetupContext) {
|
|||
|
||||
function tryFixOverBound(
|
||||
placement: TooltipPlacement,
|
||||
originalPosition: RectPosition,
|
||||
referenceBoundingRect: DOMRect,
|
||||
originalBound: DOMRect,
|
||||
tooltipBound: DOMRect): DOMRect {
|
||||
tooltipBound: DOMRect): RectPosition {
|
||||
let fixedLeft = originalBound.left;
|
||||
let fixedTop = originalBound.top;
|
||||
if (['top', 'top-left', 'top-right', 'bottom', 'bottom-left', 'bottom-righ'].includes(placement)) {
|
||||
|
@ -111,7 +159,7 @@ export function useTooltipPosition(props: TooltipProps, context: SetupContext) {
|
|||
fixedTop = overTopBound.overBound ?
|
||||
overTopBound.fixedValue :
|
||||
(overBottomBound.overBound ? overBottomBound.fixedValue - tooltipBound.height : originalBound.top);
|
||||
return Object.assign({}, originalBound, { left: fixedLeft, top: fixedTop });
|
||||
return { left: fixedLeft, top: fixedTop, right: originalPosition.right };
|
||||
}
|
||||
|
||||
function calculateArrowPosition(
|
||||
|
@ -129,9 +177,23 @@ export function useTooltipPosition(props: TooltipProps, context: SetupContext) {
|
|||
const fixedArrowLeft = fixedTooltipBound.left - hostBound.left - hostBound.width * 0.5 + arrowBound.width * 0.5 + offsetX;
|
||||
const fixedArrowTop = fixedTooltipBound.top - hostBound.top - hostBound.height * 0.5 + arrowBound.height * 0.5 + offsetY;
|
||||
|
||||
return Object.assign({}, arrowBound, { left: fixedArrowLeft, top: fixedArrowTop });
|
||||
return Object.assign({}, arrowBound, { left: Math.abs(fixedArrowLeft), top: Math.abs(fixedArrowTop) });
|
||||
}
|
||||
|
||||
const tooltipPosition = computed<RectPosition>(() => {
|
||||
const originalTop = calculateTooltipTopPositoin(placement.value, hostBound, tooltipBound, arrowBound);
|
||||
const originalLeft = calculateTooltipLeftPosition(placement.value, hostBound, tooltipBound, arrowBound);
|
||||
const originalRight = calculateTooltipRightPosition(placement.value, hostBound, tooltipBound, arrowBound);
|
||||
const { top, left, right } = tryFixOverBound(
|
||||
placement.value,
|
||||
{ top: originalTop, left: originalLeft, right: originalRight },
|
||||
hostBound,
|
||||
tooltipBound,
|
||||
tooltipBound
|
||||
);
|
||||
return { top, left, right };
|
||||
});
|
||||
|
||||
/* 计算tooltip最新位置 */
|
||||
function calculatePosition(hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
||||
let top = 0;
|
||||
|
|
Loading…
Reference in New Issue