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";
|
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 space = 2;
|
||||||
|
|
||||||
const rectifyGutter = 20;
|
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(() => {
|
const tooltipPlacement = computed(() => {
|
||||||
return props.placement;
|
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) {
|
function calculateTooltipTopPositoin(placement: TooltipPlacement, hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
||||||
let offsetY = 0;
|
let offsetY = 0;
|
||||||
const verticalAlignment = placement.indexOf('bottom') > -1 ? 'bottom' : (placement.indexOf('top') > -1 ? 'top' : 'middle');
|
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(
|
function tryFixOverBound(
|
||||||
placement: TooltipPlacement,
|
placement: TooltipPlacement,
|
||||||
|
originalPosition: RectPosition,
|
||||||
referenceBoundingRect: DOMRect,
|
referenceBoundingRect: DOMRect,
|
||||||
originalBound: DOMRect,
|
originalBound: DOMRect,
|
||||||
tooltipBound: DOMRect): DOMRect {
|
tooltipBound: DOMRect): RectPosition {
|
||||||
let fixedLeft = originalBound.left;
|
let fixedLeft = originalBound.left;
|
||||||
let fixedTop = originalBound.top;
|
let fixedTop = originalBound.top;
|
||||||
if (['top', 'top-left', 'top-right', 'bottom', 'bottom-left', 'bottom-righ'].includes(placement)) {
|
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 ?
|
fixedTop = overTopBound.overBound ?
|
||||||
overTopBound.fixedValue :
|
overTopBound.fixedValue :
|
||||||
(overBottomBound.overBound ? overBottomBound.fixedValue - tooltipBound.height : originalBound.top);
|
(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(
|
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 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;
|
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最新位置 */
|
/* 计算tooltip最新位置 */
|
||||||
function calculatePosition(hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
function calculatePosition(hostBound: DOMRect, tooltipBound: DOMRect, arrowBound: DOMRect) {
|
||||||
let top = 0;
|
let top = 0;
|
||||||
|
|
Loading…
Reference in New Issue