@desnoth/vue2-popup
Version:
A simple Vue popup component with self state
129 lines (117 loc) • 3.86 kB
text/typescript
export function calculatePopupPosition(
origin: HTMLElement,
target: HTMLElement
) {
let originWidth: number = origin.offsetWidth;
let originHeight: number = origin.offsetHeight;
let viewportOffset = origin.getBoundingClientRect();
let targetPosition = target.getBoundingClientRect();
let position = {
left: Math.round(viewportOffset.left),
top: Math.round(viewportOffset.top)
};
let popupWidth = target.offsetWidth;
let popupHeight = target.offsetHeight;
let outputLeft: number | string =
position.left + originWidth / 2 - popupWidth / 2;
let outputTop: number | string = position.top + originHeight;
let outputBottom: number | string = "none";
let windowWidth: number = window.innerWidth;
if (outputLeft + popupWidth > windowWidth - 15) {
outputLeft = windowWidth - popupWidth - 15;
} else if (outputLeft < 15) {
outputLeft = 15;
}
if (outputTop + popupHeight + 15 > window.innerHeight) {
outputTop = "none";
outputBottom = window.innerHeight - position.top + 15 + "px";
} else {
outputTop = outputTop + 15 + "px";
}
const triangleLeft = position.left - outputLeft + originWidth / 2 - 13 + "px";
return {
left: outputLeft + "px",
top: outputTop,
bottom: outputBottom,
width: originWidth + "px",
triangleLeft
};
}
// Popup component helper
export function calculatePopupRelativePosition(
origin: HTMLElement,
target: HTMLElement,
container?: HTMLElement
) {
const originWidth: number = origin.offsetWidth;
const originHeight: number = origin.offsetHeight;
const viewportOffset = origin.getBoundingClientRect();
let OriginPosition = {
left: Math.round(viewportOffset.left),
top: Math.round(viewportOffset.top)
};
const popupWidth: number = target.offsetWidth;
const popupHeight: number = target.offsetHeight;
let containerWidth: number;
let containerHeight: number;
let containerPosition;
let outputLeft: any;
let outputTop: any;
if (container) {
containerWidth = container.offsetWidth;
containerHeight = container.offsetHeight;
containerPosition = {
left: Math.round(container.getBoundingClientRect().left),
top: Math.round(container.getBoundingClientRect().top)
};
OriginPosition = {
left: OriginPosition.left - containerPosition.left,
top: OriginPosition.top - containerPosition.top
};
} else {
containerWidth = window.innerWidth;
containerHeight = window.innerHeight;
containerPosition = { left: 0, top: 0 };
OriginPosition = {
left: Math.round(viewportOffset.left),
top: Math.round(viewportOffset.top)
};
}
outputLeft = OriginPosition.left + originWidth / 2 - popupWidth / 2;
outputTop = OriginPosition.top + originHeight + 15;
let XType;
let YType;
// check left and right
if (popupWidth + 15 > containerWidth) {
XType = "fill";
} else if (outputLeft + popupWidth > containerWidth - 15) {
XType = "right";
} else if (outputLeft < 15) {
XType = "left";
} else {
XType = "center";
}
// check top and bottom
const topMargin = outputTop + popupHeight + 15;
const bottomMargin = containerHeight - OriginPosition.top + popupHeight + 15;
let maxHeight = null;
if (topMargin < containerHeight) {
YType = "bottom";
maxHeight = containerHeight - outputTop - 15;
} else if (bottomMargin < containerHeight) {
YType = "top";
maxHeight = containerHeight - (containerHeight - OriginPosition.top) - 15;
} else {
if (
containerHeight - outputTop >
containerHeight - (containerHeight - OriginPosition.top)
) {
YType = "bottom";
maxHeight = containerHeight - outputTop - 15;
} else {
YType = "top";
maxHeight = containerHeight - (containerHeight - OriginPosition.top) - 15;
}
}
return { XType, YType, maxHeight };
}