helpers/position.js

88 lines
2.3 KiB
JavaScript

/**
@license
Copyright (c) 2022 trading_peter
This program is available under Apache License Version 2.0
*/
/**
* Helps to position elements relative to each other.
*/
export const Position = function(superClass) {
return class extends superClass {
_posFixed(anchor, el, options) {
options = Object.assign({
valign: 'top',
halign: 'middle',
spacing: 0
}, options);
let top, left, fixLeft = 0, fixTop = 0, compLeft = 0, compTop = 0;
el.style.position = 'fixed';
el.style.zIndex = 1001;
// Test if the target is in a different stacking context.
el.style.left = '0px';
el.style.top = '0px';
const elRect = el.getBoundingClientRect();
if (elRect.left > 0 || elRect.top > 0) {
fixLeft = elRect.left;
fixTop = elRect.top;
}
const anchorRect = anchor.getBoundingClientRect();
if (options.valign === 'top') {
top = anchorRect.top - elRect.height - options.spacing;
// Move popup down a little bit if there issn't enough room over the anchor.
if (top < 0) {
compTop = Math.abs(top);
top = 0;
}
}
if (options.valign === 'bottom') {
top = anchorRect.top + anchorRect.height + options.spacing;
// Move popup up a little bit if there issn't enough room under the anchor.
if (top + elRect.height > window.innerHeight) {
compTop = top + elRect.height - window.innerHeight;
top -= compTop;
}
}
if (options.halign === 'left') {
left = anchorRect.left;
}
if (options.halign === 'middle') {
left = anchorRect.left - elRect.width / 2 + anchorRect.width / 2;
}
if (options.halign === 'right') {
left = anchorRect.left + anchorRect.width - elRect.width;
}
if (left + elRect.width > window.innerWidth) {
compLeft = left + elRect.width - window.innerWidth;
left -= compLeft;
}
if (left < 0) {
compLeft = Math.abs(left);
left = 0;
}
el.style.top = (top - fixTop) + 'px';
el.style.left = (left - fixLeft) + 'px';
// Return info object about how much the position had to compensate to fit on the page.
return {
compLeft: compLeft,
compTop: compTop
};
}
};
}