@progress/kendo-angular-gantt
Version:
Kendo UI Angular Gantt
196 lines (195 loc) • 6.93 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { DependencyType } from '../models/dependency-type.enum';
/**
* @hidden
*
* Gets the offset (top and left values) relative to a target element.
*/
export const getOffsetRelativeToParent = (element, targetParent) => {
const offset = {
top: 0,
left: 0
};
if (!targetParent.contains(element)) {
return offset;
}
let offsetParent = element;
while (offsetParent && offsetParent !== targetParent) {
offset.top += offsetParent.offsetTop;
offset.left += offsetParent.offsetLeft;
offsetParent = offsetParent.offsetParent;
}
return offset;
};
/**
* @hidden
*/
export const getElementRect = (element, relativeContainer) => {
const { top, left } = getOffsetRelativeToParent(element, relativeContainer);
return {
top: top + element.offsetHeight / 2,
left: left,
right: left + element.offsetWidth
};
};
/**
* @hidden
*/
export const dependencyCoordinates = (from, to, rowHeight, type, minDistanceBeforeTurn, arrowSize) => {
const points = [];
const minTurnHeight = Math.floor(rowHeight / 2);
const drawingDown = from.top < to.top;
let top, left;
// FF and SS are composed of 4 connected polyline points (not counting the arrow)
/*
[[[]]]- -[[[]]]
| |
[[[]]]- -[[[]]]
*/
if (type === DependencyType.FF || type === DependencyType.SS) {
// polyline start from first task
const dir = type === DependencyType.SS ? 'left' : 'right';
top = from.top;
left = from[dir];
points.push({ top, left });
// first turn point
left = Math[dir === 'left' ? 'min' : 'max'](from[dir], to[dir]);
left = dir === 'left' ? left - minDistanceBeforeTurn : left + minDistanceBeforeTurn;
points.push({ top, left });
// second turn point
top = to.top;
points.push({ top, left });
// second task reached
left = dir === 'left' ? to[dir] - arrowSize : to[dir] + arrowSize;
points.push({ top, left });
// arrow pointing to the second task
points.push(...getArrow(top, left, dir !== 'left', arrowSize));
}
else {
// FS and SF are composed of 4 or 6 connected polyline points (not counting the arrow), depending on the position of the tasks
/*
[[[]]]- [[[]]]-
| |
-[[[]]] -----
|
-[[[]]]
*/
const startDir = type === DependencyType.SF ? 'left' : 'right';
const endDir = type === DependencyType.SF ? 'right' : 'left';
const additionalTurn = type === DependencyType.SF
? from[startDir] - minDistanceBeforeTurn * 2 < to[endDir]
: from[startDir] + minDistanceBeforeTurn * 2 > to[endDir];
// polyline start from first task
top = from.top;
left = from[startDir];
points.push({ top, left });
// first turn point
left = startDir === 'left'
? left - minDistanceBeforeTurn
: left + minDistanceBeforeTurn;
points.push({ top, left });
// if second task start is before the first task end in FS
// if second task end is after the first task start in SF
if (additionalTurn) {
// additional turn start
top = drawingDown
? top + minTurnHeight
: top - minTurnHeight;
points.push({ top, left });
// additional turn end
left = startDir === 'left'
? to[endDir] + minDistanceBeforeTurn
: to[endDir] - minDistanceBeforeTurn;
points.push({ top, left });
}
// second task level reached
top = to.top;
points.push({ top, left });
// second task element reached
left = endDir === 'left' ? to[endDir] - arrowSize : to[endDir] + arrowSize;
points.push({ top, left });
// arrow pointing to the second task
points.push(...getArrow(top, left, endDir !== 'left', arrowSize));
}
return points;
};
const getArrow = (top, left, isArrowWest, arrowSize) => {
const points = isArrowWest
? getArrowWest(top, left, arrowSize)
: getArrowEast(top, left, arrowSize);
return points;
};
const getArrowWest = (top, left, arrowSize) => {
const points = [];
points.push({
top: top - arrowSize / 2,
left
});
points.push({
top,
left: left - arrowSize + 1
});
points.push({
top: top + arrowSize / 2,
left
});
points.push({
top,
left
});
return points;
};
const getArrowEast = (top, left, arrowSize) => {
const points = [];
points.push({
top: top + arrowSize / 2,
left
});
points.push({
top,
left: left + arrowSize - 1
});
points.push({
top: top - arrowSize / 2,
left
});
points.push({
top,
left
});
return points;
};
/**
* @hidden
*
* Translates the provided client `left` and `top` coords to coords relative to the provided container.
* https://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_View/Coordinate_systems#standard_cssom_coordinate_systems
*/
export const clientToOffsetCoords = (clientLeft, clientTop, offsetContainer) => {
// client (viewport) coordinates of the target container
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#value
const offsetContainerClientRect = offsetContainer.getBoundingClientRect();
return {
left: clientLeft - offsetContainerClientRect.left + offsetContainer.scrollLeft,
top: clientTop - offsetContainerClientRect.top + offsetContainer.scrollTop
};
};
/**
* @hidden
*
* Retrieves the `left` and `top` values of the center of the provided element.
* The retrieved values are relative to the current viewport (client values).
* https://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_View/Coordinate_systems#standard_cssom_coordinate_systems
*/
export const getElementClientCenterCoords = (element) => {
// client (viewport) coordinates of the targeted element
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect#value
const { left, top, width, height } = element.getBoundingClientRect();
return {
left: left + (width / 2),
top: top + (height / 2)
};
};