1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/open-hand-choerodon-ui

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
domAlign.tsx 12 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
HughHzWu Отправлено 3 лет назад c6a3497
import { getDocument, getMousePosition } from 'choerodon-ui/pro/lib/_util/DocumentUtils';
import isString from 'lodash/isString';
import { pxToRem } from '../_util/UnitConvertor';
import { AlignPoint } from './Align';
type overflowType = { adjustX?: boolean; adjustY?: boolean };
type regionType = { left: number; top: number; width: number; height: number };
type positionType = { left: number; top: number };
function isFailX(elFuturePos, elRegion, visibleRect) {
return (
elFuturePos.left < visibleRect.left || elFuturePos.left + elRegion.width > visibleRect.right
);
}
function isFailY(elFuturePos, elRegion, visibleRect) {
return (
elFuturePos.top < visibleRect.top || elFuturePos.top + elRegion.height > visibleRect.bottom
);
}
function isCompleteFailX(elFuturePos, elRegion, visibleRect) {
return (
elFuturePos.left > visibleRect.right || elFuturePos.left + elRegion.width < visibleRect.left
);
}
function isCompleteFailY(elFuturePos, elRegion, visibleRect) {
return (
elFuturePos.top > visibleRect.bottom || elFuturePos.top + elRegion.height < visibleRect.top
);
}
function getParent(element: HTMLElement): HTMLElement | null {
let parent: HTMLElement | null = element;
do {
parent = parent.parentElement;
} while (parent && parent.nodeType !== 1 && parent.nodeType !== 9);
return parent;
}
function getOffsetParentAndStyle(el: HTMLElement, defaultView: Window): { parent: HTMLElement, style: CSSStyleDeclaration | null } | null {
const { position } = defaultView.getComputedStyle(el);
if (position !== 'absolute' && position !== 'fixed') {
if (!isString(el.nodeName) || el.nodeName.toLowerCase() !== 'html') {
const parent = getParent(el);
if (parent) {
return {
parent,
style: null,
};
}
}
} else {
const { body } = defaultView.document;
for (
let parent = getParent(el);
parent && parent !== body && parent.nodeType !== 9;
parent = getParent(parent)
) {
const style = defaultView.getComputedStyle(parent);
if (style.position !== 'static') {
return { parent, style };
}
}
}
return null;
}
function getVisibleRectForElement(element: HTMLElement) {
const { ownerDocument } = element;
if (ownerDocument) {
const { defaultView } = ownerDocument;
if (defaultView) {
const { body, documentElement } = ownerDocument;
let offsetParentAndStyle = getOffsetParentAndStyle(element, defaultView);
while (offsetParentAndStyle) {
const { parent, style } = offsetParentAndStyle;
if (!parent || parent === body || parent === documentElement) {
break;
}
if ((style || defaultView.getComputedStyle(parent)).overflow !== 'visible') {
const rect = parent.getBoundingClientRect();
const { x, y } = getMousePosition(rect.left, rect.top, defaultView, true);
return {
top: y,
right: rect.right + x - rect.left,
bottom: rect.bottom + y - rect.top,
left: x,
};
}
offsetParentAndStyle = getOffsetParentAndStyle(parent, defaultView);
}
}
}
const { body } = getDocument(window);
return {
top: 0,
right: body.clientWidth,
bottom: body.clientHeight,
left: 0,
};
}
function getRegion(node: HTMLElement): regionType {
const rect = node.getBoundingClientRect();
const { ownerDocument } = node;
const defaultView = ownerDocument ? ownerDocument.defaultView : null;
const position = defaultView ? getMousePosition(rect.left, rect.top, defaultView, true) : { x: rect.left, y: rect.top };
return {
top: position.y,
left: position.x,
width: rect.width || node.offsetWidth,
height: rect.height || node.offsetHeight,
};
}
function isOutOfVisibleRect(target: HTMLElement) {
const visibleRect = getVisibleRectForElement(target);
const targetRegion = getRegion(target);
return (
!visibleRect ||
targetRegion.left + targetRegion.width <= visibleRect.left ||
targetRegion.top + targetRegion.height <= visibleRect.top ||
targetRegion.left >= visibleRect.right ||
targetRegion.top >= visibleRect.bottom
);
}
function flip(points, reg, map) {
return points.map(p => p.replace(reg, m => map[m]));
}
function flipOffset(offset, index) {
offset[index] = -offset[index];
return offset;
}
function getAlignOffset(region, align) {
const V = align.charAt(0);
const H = align.charAt(1);
const w = region.width;
const h = region.height;
let x = region.left;
let y = region.top;
if (V === 'c') {
y += h / 2;
} else if (V === 'b') {
y += h;
}
if (H === 'c') {
x += w / 2;
} else if (H === 'r') {
x += w;
}
return {
left: x,
top: y,
};
}
function getElFuturePos(elRegion, refNodeRegion, points, offset, targetOffset): positionType {
const p1 = getAlignOffset(refNodeRegion, points[1]);
const p2 = getAlignOffset(elRegion, points[0]);
const diff = [p2.left - p1.left, p2.top - p1.top];
return {
left: elRegion.left - diff[0] + offset[0] - targetOffset[0],
top: elRegion.top - diff[1] + offset[1] - targetOffset[1],
};
}
function adjustForViewport(
elFuturePos: positionType,
elRegion: regionType,
visibleRect,
overflow,
): regionType {
const pos = { ...elFuturePos };
const size = {
width: elRegion.width,
height: elRegion.height,
};
if (overflow.adjustX && pos.left < visibleRect.left) {
pos.left = visibleRect.left;
}
// Left edge inside and right edge outside viewport, try to resize it.
if (
overflow.resizeWidth &&
pos.left >= visibleRect.left &&
pos.left + size.width > visibleRect.right
) {
size.width -= pos.left + size.width - visibleRect.right;
}
// Right edge outside viewport, try to move it.
if (overflow.adjustX && pos.left + size.width > visibleRect.right) {
// 保证左边界和可视区域左边界对齐
pos.left = Math.max(visibleRect.right - size.width, visibleRect.left);
}
// Top edge outside viewport, try to move it.
if (overflow.adjustY && pos.top < visibleRect.top) {
pos.top = visibleRect.top;
}
// Top edge inside and bottom edge outside viewport, try to resize it.
if (
overflow.resizeHeight &&
pos.top >= visibleRect.top &&
pos.top + size.height > visibleRect.bottom
) {
size.height -= pos.top + size.height - visibleRect.bottom;
}
// Bottom edge outside viewport, try to move it.
if (overflow.adjustY && pos.top + size.height > visibleRect.bottom) {
// 保证上边界和可视区域上边界对齐
pos.top = Math.max(visibleRect.bottom - size.height, visibleRect.top);
}
return Object.assign(pos, size);
}
// function isFixedPosition(node: HTMLElement): boolean {
// const { offsetParent, ownerDocument } = node;
// if (
// ownerDocument &&
// offsetParent === ownerDocument.body &&
// ownerDocument.defaultView &&
// ownerDocument.defaultView.getComputedStyle(node).position !== 'fixed'
// ) {
// return false;
// }
// if (offsetParent) {
// return isFixedPosition(offsetParent as HTMLElement);
// }
// return true;
// }
function doAlign(el: HTMLElement, refNodeRegion: regionType, align, isTargetNotOutOfVisible: boolean) {
let points = align.points;
let offset = (align.offset || [0, 0]).slice();
let targetOffset = (align.targetOffset || [0, 0]).slice();
const overflow: overflowType = align.overflow || {};
const source: HTMLElement = align.source || el;
const newOverflowCfg: overflowType = {};
let fail = 0;
const visibleRect = getVisibleRectForElement(el);
const elRegion = getRegion(source);
let elFuturePos = getElFuturePos(elRegion, refNodeRegion, points, offset, targetOffset);
let newElRegion = Object.assign(elRegion, elFuturePos);
if (visibleRect && (overflow.adjustX || overflow.adjustY) && isTargetNotOutOfVisible) {
if (overflow.adjustX) {
if (isFailX(elFuturePos, elRegion, visibleRect)) {
const newPoints = flip(points, /[lr]/gi, {
l: 'r',
r: 'l',
});
const newOffset = flipOffset(offset, 0);
const newTargetOffset = flipOffset(targetOffset, 0);
const newElFuturePos = getElFuturePos(
elRegion,
refNodeRegion,
newPoints,
newOffset,
newTargetOffset,
);
if (!isCompleteFailX(newElFuturePos, elRegion, visibleRect)) {
fail = 1;
points = newPoints;
offset = newOffset;
targetOffset = newTargetOffset;
}
}
}
if (overflow.adjustY) {
if (isFailY(elFuturePos, elRegion, visibleRect)) {
const _newPoints = flip(points, /[tb]/gi, {
t: 'b',
b: 't',
});
const _newOffset = flipOffset(offset, 1);
const _newTargetOffset = flipOffset(targetOffset, 1);
const _newElFuturePos = getElFuturePos(
elRegion,
refNodeRegion,
_newPoints,
_newOffset,
_newTargetOffset,
);
if (!isCompleteFailY(_newElFuturePos, elRegion, visibleRect)) {
fail = 1;
points = _newPoints;
offset = _newOffset;
targetOffset = _newTargetOffset;
}
}
}
if (fail) {
elFuturePos = getElFuturePos(elRegion, refNodeRegion, points, offset, targetOffset);
Object.assign(newElRegion, elFuturePos);
}
newOverflowCfg.adjustX = overflow.adjustX && isFailX(elFuturePos, elRegion, visibleRect);
newOverflowCfg.adjustY = overflow.adjustY && isFailY(elFuturePos, elRegion, visibleRect);
if (newOverflowCfg.adjustX || newOverflowCfg.adjustY) {
newElRegion = adjustForViewport(elFuturePos, elRegion, visibleRect, newOverflowCfg);
}
}
const { width, height } = newElRegion;
if (width !== elRegion.width) {
source.style.width = width ? pxToRem(width, true)! : '0';
}
if (height !== elRegion.height) {
source.style.height = height ? pxToRem(height, true)! : '0';
}
// const isTargetFixed = isFixedPosition(target);
const { offsetParent, ownerDocument } = source;
if (offsetParent) {
const { left, top } = offsetParent.getBoundingClientRect();
newElRegion.left -= left;
newElRegion.top -= top;
}
if (ownerDocument) {
const { x, y } = getMousePosition(0, 0, ownerDocument.defaultView || window, true);
newElRegion.left -= x;
newElRegion.top -= y;
}
Object.assign(source.style, {
left: pxToRem(newElRegion.left, true),
top: pxToRem(newElRegion.top, true),
});
// if (isTargetFixed) {
// source.style.position = 'fixed';
// } else {
// source.style.position = '';
// }
return {
points,
offset,
targetOffset,
overflow: newOverflowCfg,
};
}
export default function alignElement(el: HTMLElement, refNode: HTMLElement, align) {
const target = align.target || refNode;
const refNodeRegion = getRegion(target);
const isTargetNotOutOfVisible = !isOutOfVisibleRect(target);
return doAlign(el, refNodeRegion, align, isTargetNotOutOfVisible);
}
export function alignPoint(el: HTMLElement, tgtPoint: AlignPoint, align) {
let left = 0;
let top = 0;
const { ownerDocument } = el;
const defaultView = ownerDocument ? ownerDocument.defaultView : null;
const documentElement = ownerDocument ? ownerDocument.documentElement : null;
const scrollX = documentElement ? documentElement.scrollLeft : 0;
const scrollY = documentElement ? documentElement.scrollTop : 0;
if (tgtPoint.pageX !== undefined) {
left = tgtPoint.pageX - scrollX;
} else if (tgtPoint.clientX !== undefined) {
left = scrollX + tgtPoint.clientX;
}
if (tgtPoint.pageY !== undefined) {
top = tgtPoint.pageY - scrollY;
} else if (tgtPoint.clientY !== undefined) {
top = tgtPoint.clientY;
}
const position = defaultView ? getMousePosition(left, top, defaultView, true) : {
x: left,
y: top,
vw: documentElement ? documentElement.clientWidth : 0,
vh: documentElement ? documentElement.clientHeight : 0,
};
left = position.x;
top = position.y;
const tgtRegion: regionType = {
left,
top,
width: 0,
height: 0,
};
const pointInView = left >= 0 && left <= position.vw && top >= 0 && top <= position.vh; // Provide default target point
const points = [align.points[0], 'cc'];
return doAlign(el, tgtRegion, {
...align,
points,
}, pointInView);
}

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/open-hand-choerodon-ui.git
git@gitlife.ru:oschina-mirror/open-hand-choerodon-ui.git
oschina-mirror
open-hand-choerodon-ui
open-hand-choerodon-ui
master