UNPKG

dhtmlx-gantt

Version:

An open source JavaScript Gantt chart that helps you illustrate a project schedule in a nice-looking chart.

1,390 lines (1,384 loc) 1.15 MB
(function(global2, factory) { typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global2 = typeof globalThis !== "undefined" ? globalThis : global2 || self, factory(global2.dhtmlxgantt = {})); })(this, function(exports2) { "use strict";/** @license dhtmlxGantt v.9.1.1 Standard This version of dhtmlxGantt is distributed under GPL 2.0 license and can be legally used in GPL projects. To use dhtmlxGantt in non-GPL projects (and get Pro version of the product), please obtain Individual, Commercial, Enterprise or Ultimate license on our site https://dhtmlx.com/docs/products/dhtmlxGantt/#licensing or contact us at info@dhtmlx.com (c) XB Software */ function getNodePosition(elem) { var top = 0, left = 0, right = 0, bottom = 0; if (elem.getBoundingClientRect) { var box = elem.getBoundingClientRect(); var body = document.body; var docElem = document.documentElement || document.body.parentNode || document.body; var scrollTop = window.pageYOffset || docElem.scrollTop || body.scrollTop; var scrollLeft = window.pageXOffset || docElem.scrollLeft || body.scrollLeft; var clientTop = docElem.clientTop || body.clientTop || 0; var clientLeft = docElem.clientLeft || body.clientLeft || 0; top = box.top + scrollTop - clientTop; left = box.left + scrollLeft - clientLeft; right = document.body.offsetWidth - box.right; bottom = document.body.offsetHeight - box.bottom; } else { while (elem) { top = top + parseInt(elem.offsetTop, 10); left = left + parseInt(elem.offsetLeft, 10); elem = elem.offsetParent; } right = document.body.offsetWidth - elem.offsetWidth - left; bottom = document.body.offsetHeight - elem.offsetHeight - top; } return { y: Math.round(top), x: Math.round(left), width: elem.offsetWidth, height: elem.offsetHeight, right: Math.round(right), bottom: Math.round(bottom) }; } function isVisible(node) { var display = false, visibility = false; if (window.getComputedStyle) { var style = window.getComputedStyle(node, null); display = style["display"]; visibility = style["visibility"]; } else if (node.currentStyle) { display = node.currentStyle["display"]; visibility = node.currentStyle["visibility"]; } return display != "none" && visibility != "hidden"; } function hasNonNegativeTabIndex(node) { return !isNaN(node.getAttribute("tabindex")) && node.getAttribute("tabindex") * 1 >= 0; } function hasHref(node) { var canHaveHref = { a: true, area: true }; if (canHaveHref[node.nodeName.loLowerCase()]) { return !!node.getAttribute("href"); } return true; } function isEnabled(node) { var canDisable = { input: true, select: true, textarea: true, button: true, object: true }; if (canDisable[node.nodeName.toLowerCase()]) { return !node.hasAttribute("disabled"); } return true; } function getFocusableNodes(root) { var nodes = root.querySelectorAll(["a[href]", "area[href]", "input", "select", "textarea", "button", "iframe", "object", "embed", "[tabindex]", "[contenteditable]"].join(", ")); var nodesArray = Array.prototype.slice.call(nodes, 0); for (var i = 0; i < nodesArray.length; i++) { nodesArray[i].$position = i; } nodesArray.sort(function(a, b) { if (a.tabIndex === 0 && b.tabIndex !== 0) { return 1; } if (a.tabIndex !== 0 && b.tabIndex === 0) { return -1; } if (a.tabIndex === b.tabIndex) { return a.$position - b.$position; } if (a.tabIndex < b.tabIndex) { return -1; } return 1; }); for (var i = 0; i < nodesArray.length; i++) { var node = nodesArray[i]; var isValid = (hasNonNegativeTabIndex(node) || isEnabled(node) || hasHref(node)) && isVisible(node); if (!isValid) { nodesArray.splice(i, 1); i--; } } return nodesArray; } function getScrollSize() { var div = document.createElement("div"); div.style.cssText = "visibility:hidden;position:absolute;left:-1000px;width:100px;padding:0px;margin:0px;height:110px;min-height:100px;overflow-y:scroll;"; document.body.appendChild(div); var width = div.offsetWidth - div.clientWidth; document.body.removeChild(div); return Math.max(width, 15); } function getClassName(node) { if (!node) return ""; var className = node.className || ""; if (className.baseVal) className = className.baseVal; if (!className.indexOf) className = ""; return _trimString(className); } function addClassName(node, className) { if (className && node.className.indexOf(className) === -1) { node.className += " " + className; } } function removeClassName(node, name) { name = name.split(" "); for (var i = 0; i < name.length; i++) { var regEx = new RegExp("\\s?\\b" + name[i] + "\\b(?![-_.])", ""); node.className = node.className.replace(regEx, ""); } } function hasClass(element, className) { if ("classList" in element) { return element.classList.contains(className); } else { return new RegExp("\\b" + className + "\\b").test(element.className); } } function toNode(node) { if (typeof node === "string") { return document.getElementById(node) || document.querySelector(node) || document.body; } return node || document.body; } var _slave; function insertNode(node, newone) { if (!_slave) { _slave = document.createElement("div"); } _slave.innerHTML = newone; var child = _slave.firstChild; node.appendChild(child); return child; } function removeNode(node) { if (node && node.parentNode) { node.parentNode.removeChild(node); } } function getChildNodes(node, css) { var ch = node.childNodes; var len = ch.length; var out = []; for (var i = 0; i < len; i++) { var obj = ch[i]; if (obj.className && obj.className.indexOf(css) !== -1) { out.push(obj); } } return out; } function getTargetNode(e) { var trg; if (e.tagName) trg = e; else { e = e || window.event; trg = e.target || e.srcElement; if (trg.shadowRoot && e.composedPath) { trg = e.composedPath()[0]; } } return trg; } function locateAttribute(e, attribute) { if (!attribute) return; var trg = getTargetNode(e); while (trg) { if (trg.getAttribute) { var test = trg.getAttribute(attribute); if (test) return trg; } trg = trg.parentNode || trg.host; } return null; } function _trimString(str) { var func = String.prototype.trim || function() { return this.replace(/^\s+|\s+$/g, ""); }; return func.apply(str); } function locateClassName(e, classname, strict) { var trg = getTargetNode(e); var css = ""; if (strict === void 0) strict = true; while (trg) { css = getClassName(trg); if (css) { var ind = css.indexOf(classname); if (ind >= 0) { if (!strict) return trg; var left = ind === 0 || !_trimString(css.charAt(ind - 1)); var right = ind + classname.length >= css.length || !_trimString(css.charAt(ind + classname.length)); if (left && right) return trg; } } trg = trg.parentNode; } return null; } function getRelativeEventPosition(ev, node) { var _a; const d = document.documentElement; const box = getNodePosition(node); const { clientX, clientY } = ((_a = ev.touches) == null ? void 0 : _a[0]) ?? ev; return { x: clientX + d.scrollLeft - d.clientLeft - box.x + node.scrollLeft, y: clientY + d.scrollTop - d.clientTop - box.y + node.scrollTop }; } function getRelativeNodePosition(child, parent) { const childPos = getNodePosition(child); const parentPos = getNodePosition(parent); return { x: childPos.x - parentPos.x, y: childPos.y - parentPos.y }; } function isChildOf(child, parent) { if (!child || !parent) { return false; } while (child && child != parent) { child = child.parentNode; } return child === parent; } function closest(element, selector) { if (element.closest) { return element.closest(selector); } else if (element.matches || element.msMatchesSelector || element.webkitMatchesSelector) { var el = element; if (!document.documentElement.contains(el)) return null; do { var method = el.matches || el.msMatchesSelector || el.webkitMatchesSelector; if (method.call(el, selector)) return el; el = el.parentElement || el.parentNode; } while (el !== null && el.nodeType === 1); return null; } else { console.error("Your browser is not supported"); return null; } } function getClosestSizedElement(element) { while (element) { if (element.offsetWidth > 0 && element.offsetHeight > 0) { return element; } element = element.parentElement; } return null; } function isShadowDomSupported() { return document.head.createShadowRoot || document.head.attachShadow; } function getActiveElement() { var activeElement = document.activeElement; if (activeElement.shadowRoot) { activeElement = activeElement.shadowRoot.activeElement; } if (activeElement === document.body && document.getSelection) { activeElement = document.getSelection().focusNode || document.body; } return activeElement; } function getRootNode(element) { if (!element) { return document.body; } if (!isShadowDomSupported()) { return document.body; } while (element.parentNode && (element = element.parentNode)) { if (element instanceof ShadowRoot) { return element.host; } } return document.body; } function hasShadowParent(element) { return !!getRootNode(element); } const domHelpers = Object.freeze(Object.defineProperty({ __proto__: null, addClassName, closest, getActiveElement, getChildNodes, getClassName, getClosestSizedElement, getFocusableNodes, getNodePosition, getRelativeEventPosition, getRelativeNodePosition, getRootNode, getScrollSize, getTargetNode, hasClass, hasShadowParent, insertNode, isChildOf, isShadowDomSupported, locateAttribute, locateClassName, removeClassName, removeNode, toNode }, Symbol.toStringTag, { value: "Module" })); var globalScope; if (typeof window !== "undefined") { globalScope = window; } else { globalScope = global; } const scope = globalScope; let EventsManager$1 = class EventsManager { constructor(gantt2) { this._mouseDown = false; this._touchStarts = false; this._touchActive = false; this._longTapTimer = false; this._gantt = gantt2; this._domEvents = gantt2._createDomEventScope(); } attach(selectedRegion, useKey, ignore) { const gantt2 = this._gantt; const _target = selectedRegion.getViewPort(); this._originPosition = scope.getComputedStyle(_target).display; this._restoreOriginPosition = () => { _target.style.position = this._originPosition; }; if (this._originPosition === "static") { _target.style.position = "relative"; } const state = gantt2.$services.getService("state"); state.registerProvider("clickDrag", () => { const result = { autoscroll: false }; return result; }); let scheduledDndCoordinates = null; const startDragAndDrop = () => { if (!scheduledDndCoordinates) { return; } this._mouseDown = true; selectedRegion.setStart(gantt2.copy(scheduledDndCoordinates)); selectedRegion.setPosition(gantt2.copy(scheduledDndCoordinates)); selectedRegion.setEnd(gantt2.copy(scheduledDndCoordinates)); scheduledDndCoordinates = null; }; this._domEvents.attach(_target, "mousedown", (event2) => { startDrag(event2); }); const eventElement = getRootNode(gantt2.$root) || document.body; this._domEvents.attach(eventElement, "mouseup", (event2) => { stopDrag(event2); }); this._domEvents.attach(_target, "mousemove", (event2) => { dragMove(event2); }); this._domEvents.attach(_target, "touchstart", (event2) => { this._touchStarts = true; this._longTapTimer = setTimeout(() => { if (this._touchStarts) { startDrag(getTouchEvent(event2)); this._touchStarts = false; this._touchActive = true; } }, this._gantt.config.touch_drag); }); this._domEvents.attach(eventElement, "touchend", (event2) => { this._touchStarts = false; this._touchActive = false; clearTimeout(this._longTapTimer); stopDrag(getTouchEvent(event2)); }); this._domEvents.attach(_target, "touchmove", (event2) => { if (this._touchActive) { let filterTargets = getFilterTargets(); if (filterTargets && gantt2.utils.dom.closest(event2.target, filterTargets)) { return; } dragMove(getTouchEvent(event2)); event2.preventDefault(); } else { this._touchStarts = false; clearTimeout(this._longTapTimer); } }); function getTouchEvent(event2) { const touchEvent = event2.changedTouches && event2.changedTouches[0] || event2; return touchEvent; } const getFilterTargets = () => { let filterTargets = ".gantt_task_line, .gantt_task_link"; if (ignore !== void 0) { if (ignore instanceof Array) { filterTargets = ignore.join(", "); } else { filterTargets = ignore; } } return filterTargets; }; const startDrag = (event2) => { scheduledDndCoordinates = null; let filterTargets = getFilterTargets(); if (filterTargets) { if (gantt2.utils.dom.closest(event2.target, filterTargets)) { return; } } state.registerProvider("clickDrag", () => { const result = { autoscroll: this._mouseDown }; return result; }); if (useKey && event2[useKey] !== true) { return; } scheduledDndCoordinates = this._getCoordinates(event2, selectedRegion); }; const stopDrag = (event2) => { scheduledDndCoordinates = null; if (useKey && event2[useKey] !== true) { return; } if (this._mouseDown === true) { this._mouseDown = false; const coordinates = this._getCoordinates(event2, selectedRegion); selectedRegion.dragEnd(coordinates); } }; const dragMove = (event2) => { if (useKey && event2[useKey] !== true) { return; } const dragTimeline = this._gantt.ext.clickDrag; const dragTimelineUseKey = (this._gantt.config.drag_timeline || {}).useKey; if (dragTimeline && dragTimelineUseKey) { if (!useKey && event2[dragTimelineUseKey]) { return; } } let coordinates = null; if (!this._mouseDown && scheduledDndCoordinates) { coordinates = this._getCoordinates(event2, selectedRegion); if (Math.abs(scheduledDndCoordinates.relative.left - coordinates.relative.left) > 5) { startDragAndDrop(); } return; } if (this._mouseDown === true) { coordinates = this._getCoordinates(event2, selectedRegion); selectedRegion.setEnd(coordinates); selectedRegion.render(); } }; } detach() { const gantt2 = this._gantt; this._domEvents.detachAll(); if (this._restoreOriginPosition) { this._restoreOriginPosition(); } const state = gantt2.$services.getService("state"); state.unregisterProvider("clickDrag"); } destructor() { this.detach(); } _getCoordinates(event2, selectedRegion) { const viewPort = selectedRegion.getViewPort(); const viewPortBounds = viewPort.getBoundingClientRect(); const { clientX, clientY } = event2; const result = { absolute: { left: clientX, top: clientY }, relative: { left: clientX - viewPortBounds.left + viewPort.scrollLeft, top: clientY - viewPortBounds.top + viewPort.scrollTop } }; return result; } }; var EventHost = function() { this._silent_mode = false; this.listeners = {}; }; EventHost.prototype = { _silentStart: function() { this._silent_mode = true; }, _silentEnd: function() { this._silent_mode = false; } }; var createEventStorage = function(obj) { var handlers = {}; var index = 0; var eventStorage = function() { var combinedResult = true; for (var i in handlers) { var handlerResult = handlers[i].apply(obj, arguments); combinedResult = combinedResult && handlerResult; } return combinedResult; }; eventStorage.addEvent = function(handler, settings) { if (typeof handler == "function") { var handlerId; if (settings && settings.id) { handlerId = settings.id; } else { handlerId = index; index++; } if (settings && settings.once) { var originalHandler = handler; handler = function() { originalHandler(); eventStorage.removeEvent(handlerId); }; } handlers[handlerId] = handler; return handlerId; } return false; }; eventStorage.removeEvent = function(id) { delete handlers[id]; }; eventStorage.clear = function() { handlers = {}; }; return eventStorage; }; function makeEventable(obj) { var eventHost = new EventHost(); obj.attachEvent = function(eventName, handler, settings) { eventName = "ev_" + eventName.toLowerCase(); if (!eventHost.listeners[eventName]) { eventHost.listeners[eventName] = createEventStorage(this); } if (settings && settings.thisObject) { handler = handler.bind(settings.thisObject); } var innerId = eventHost.listeners[eventName].addEvent(handler, settings); var handlerId = eventName + ":" + innerId; if (settings && settings.id) { handlerId = settings.id; } return handlerId; }; obj.attachAll = function(callback) { this.attachEvent("listen_all", callback); }; obj.callEvent = function(name, eventArguments) { if (eventHost._silent_mode) return true; var handlerName = "ev_" + name.toLowerCase(); var listeners = eventHost.listeners; if (listeners["ev_listen_all"]) { listeners["ev_listen_all"].apply(this, [name].concat(eventArguments)); } if (listeners[handlerName]) return listeners[handlerName].apply(this, eventArguments); return true; }; obj.checkEvent = function(name) { var listeners = eventHost.listeners; return !!listeners["ev_" + name.toLowerCase()]; }; obj.detachEvent = function(id) { if (id) { var listeners = eventHost.listeners; for (var i in listeners) { listeners[i].removeEvent(id); } var list = id.split(":"); var listeners = eventHost.listeners; if (list.length === 2) { var eventName = list[0]; var eventId = list[1]; if (listeners[eventName]) { listeners[eventName].removeEvent(eventId); } } } }; obj.detachAllEvents = function() { for (var name in eventHost.listeners) { eventHost.listeners[name].clear(); } }; } var units = { second: 1, minute: 60, hour: 60 * 60, day: 60 * 60 * 24, week: 60 * 60 * 24 * 7, month: 60 * 60 * 24 * 30, quarter: 60 * 60 * 24 * 30 * 3, year: 60 * 60 * 24 * 365 }; function getSecondsInUnit(unit) { return units[unit] || units.hour; } function forEach(arr, callback) { if (arr.forEach) { arr.forEach(callback); } else { var workArray = arr.slice(); for (var i = 0; i < workArray.length; i++) { callback(workArray[i], i); } } } function arrayMap(arr, callback) { if (arr.map) { return arr.map(callback); } else { var workArray = arr.slice(); var resArray = []; for (var i = 0; i < workArray.length; i++) { resArray.push(callback(workArray[i], i)); } return resArray; } } function arrayFind(arr, callback) { if (arr.find) { return arr.find(callback); } else { for (var i = 0; i < arr.length; i++) { if (callback(arr[i], i)) { return arr[i]; } } } } function arrayIncludes(arr, item) { if (arr.includes) { return arr.includes(item); } else { for (var i = 0; i < arr.length; i++) { if (arr[i] === item) { return true; } } return false; } } function isArray(obj) { if (Array.isArray) { return Array.isArray(obj); } else { return obj && obj.length !== void 0 && obj.pop && obj.push; } } function isDate(obj) { if (obj && typeof obj === "object") { return !!(obj.getFullYear && obj.getMonth && obj.getDate); } else { return false; } } function isValidDate(obj) { return isDate(obj) && !isNaN(obj.getTime()); } function arrayFilter(arr, callback) { var result = []; if (arr.filter) { return arr.filter(callback); } else { for (var i = 0; i < arr.length; i++) { if (callback(arr[i], i)) { result[result.length] = arr[i]; } } return result; } } function throttle(callback, timeout) { var wait = false; return function() { if (!wait) { callback.apply(null, arguments); wait = true; setTimeout(function() { wait = false; }, timeout); } }; } function delay(callback, timeout) { var timer; var result = function() { result.$cancelTimeout(); result.$pending = true; var args = Array.prototype.slice.call(arguments); timer = setTimeout(function() { callback.apply(this, args); result.$pending = false; }, timeout); }; result.$pending = false; result.$cancelTimeout = function() { clearTimeout(timer); result.$pending = false; }; result.$execute = function() { var args = Array.prototype.slice.call(arguments); callback.apply(this, args); result.$cancelTimeout(); }; return result; } function isEventable(obj) { return obj.attachEvent && obj.detachEvent; } function replaceValidZeroId(id, rootId) { if (checkZeroId(id) && !checkZeroId(rootId)) { id = "0"; } return id; } function checkZeroId(id) { if (id === 0) { return true; } return false; } function findBinary(array, target) { var low = 0, high = array.length - 1, i, item, prev; while (low <= high) { i = Math.floor((low + high) / 2); item = +array[i]; prev = +array[i - 1]; if (item < target) { low = i + 1; continue; } if (item > target) { if (!(!isNaN(prev) && prev < target)) { high = i - 1; continue; } else { return i - 1; } } while (+array[i] == +array[i + 1]) i++; return i; } return array.length - 1; } class SelectedRegion { constructor(config2, gantt2, view) { this._el = document.createElement("div"); this.defaultRender = (start, end) => { if (!this._el) { this._el = document.createElement("div"); } const node = this._el; const top = Math.min(start.relative.top, end.relative.top); const bottom = Math.max(start.relative.top, end.relative.top); const left = Math.min(start.relative.left, end.relative.left); const right = Math.max(start.relative.left, end.relative.left); if (this._singleRow) { const pos = this._getTaskPositionByTop(this._startPoint.relative.top); node.style.height = pos.height + "px"; node.style.top = pos.top + "px"; } else { node.style.height = Math.abs(bottom - top) + "px"; node.style.top = top + "px"; } node.style.width = Math.abs(right - left) + "px"; node.style.left = left + "px"; return node; }; this._gantt = gantt2; this._view = view; this._viewPort = config2.viewPort; this._el.classList.add(config2.className); if (typeof config2.callback === "function") { this._callback = config2.callback; } this.render = () => { let node; if (config2.render) { node = config2.render(this._startPoint, this._endPoint); } else { node = this.defaultRender(this._startPoint, this._endPoint); } if (node !== this._el) { if (this._el && this._el.parentNode) { this._el.parentNode.removeChild(this._el); } this._el = node; } if (config2.className !== "") { this._el.classList.add(config2.className); } this.draw(); }; if (!isEventable(this._viewPort)) { makeEventable(this._viewPort); } this._singleRow = config2.singleRow; this._useRequestAnimationFrame = config2.useRequestAnimationFrame; } draw() { if (this._useRequestAnimationFrame) { return requestAnimationFrame(() => { this._viewPort.appendChild(this.getElement()); }); } else { this._viewPort.appendChild(this.getElement()); } } clear() { if (this._useRequestAnimationFrame) { return requestAnimationFrame(() => { if (!this._el.parentNode) { return; } this._viewPort.removeChild(this._el); }); } else { if (!this._el.parentNode) { return; } this._viewPort.removeChild(this._el); } } getElement() { return this._el; } getViewPort() { return this._viewPort; } setStart(startPoint) { const gantt2 = this._gantt; this._startPoint = startPoint; this._startDate = gantt2.dateFromPos(this._startPoint.relative.left); this._viewPort.callEvent("onBeforeDrag", [this._startPoint]); } setEnd(endPoint) { const gantt2 = this._gantt; this._endPoint = endPoint; if (this._singleRow) { const pos = this._getTaskPositionByTop(this._startPoint.relative.top); this._endPoint.relative.top = pos.top; } this._endDate = gantt2.dateFromPos(this._endPoint.relative.left); if (this._startPoint.relative.left > this._endPoint.relative.left) { this._positionPoint = { relative: { left: this._endPoint.relative.left, top: this._positionPoint.relative.top }, absolute: { left: this._endPoint.absolute.left, top: this._positionPoint.absolute.top } }; } if (this._startPoint.relative.top > this._endPoint.relative.top) { this._positionPoint = { relative: { left: this._positionPoint.relative.left, top: this._endPoint.relative.top }, absolute: { left: this._positionPoint.absolute.left, top: this._endPoint.absolute.top } }; } this._viewPort.callEvent("onDrag", [this._startPoint, this._endPoint]); } setPosition(positionPoint) { this._positionPoint = positionPoint; } dragEnd(endPoint) { const gantt2 = this._gantt; if (endPoint.relative.left < 0) { endPoint.relative.left = 0; } this._viewPort.callEvent("onBeforeDragEnd", [this._startPoint, endPoint]); this.setEnd(endPoint); this._endDate = this._endDate || gantt2.getState().max_date; if (this._startDate.valueOf() > this._endDate.valueOf()) { [this._startDate, this._endDate] = [this._endDate, this._startDate]; } this.clear(); const tasksByTime = gantt2.getTaskByTime(this._startDate, this._endDate); const tasksByIndex = this._getTasksByTop(this._startPoint.relative.top, this._endPoint.relative.top); this._viewPort.callEvent("onDragEnd", [this._startPoint, this._endPoint]); if (this._callback) { this._callback(this._startPoint, this._endPoint, this._startDate, this._endDate, tasksByTime, tasksByIndex); } } getInBounds() { return this._singleRow; } _getTasksByTop(start, end) { const gantt2 = this._gantt; let startValue = start; let endValue = end; if (start > end) { startValue = end; endValue = start; } const startIndex = this._getTaskPositionByTop(startValue).index; const endIndex = this._getTaskPositionByTop(endValue).index; const result = []; for (let i = startIndex; i <= endIndex; i++) { const task = gantt2.getTaskByIndex(i); if (task) { result.push(gantt2.getTaskByIndex(i)); } } return result; } _getTaskPositionByTop(top) { const gantt2 = this._gantt; const view = this._view; const index = view.getItemIndexByTopPosition(top); const task = gantt2.getTaskByIndex(index); if (task) { const height = view.getItemHeight(task.id); const itemTop = view.getItemTop(task.id); return { top: itemTop || 0, height: height || 0, index }; } else { const dataHeight = view.getTotalHeight(); return { top: top > dataHeight ? dataHeight : 0, height: gantt2.config.row_height, index: top > dataHeight ? gantt2.getTaskCount() : 0 }; } } } function click_drag(gantt2) { if (!gantt2.ext) { gantt2.ext = {}; } const defaultConfig = { className: "gantt_click_drag_rect", useRequestAnimationFrame: true, callback: void 0, singleRow: false }; function setClickDrag() { const config2 = { viewPort: gantt2.$task_data, ...defaultConfig }; if (gantt2.ext.clickDrag) { gantt2.ext.clickDrag.destructor(); } gantt2.ext.clickDrag = new EventsManager$1(gantt2); const clickDrag = gantt2.config.click_drag; config2.render = clickDrag.render || defaultConfig.render; config2.className = clickDrag.className || defaultConfig.className; config2.callback = clickDrag.callback || defaultConfig.callback; config2.viewPort = clickDrag.viewPort || gantt2.$task_data; config2.useRequestAnimationFrame = clickDrag.useRequestAnimationFrame === void 0 ? defaultConfig.useRequestAnimationFrame : clickDrag.useRequestAnimationFrame; config2.singleRow = clickDrag.singleRow === void 0 ? defaultConfig.singleRow : clickDrag.singleRow; const timeline = gantt2.$ui.getView("timeline"); const selectedRegion = new SelectedRegion(config2, gantt2, timeline); gantt2.ext.clickDrag.attach(selectedRegion, clickDrag.useKey, clickDrag.ignore); } gantt2.attachEvent("onGanttReady", () => { if (gantt2.config.click_drag) { setClickDrag(); } }); gantt2.attachEvent("onGanttLayoutReady", function() { if (gantt2.$container && gantt2.config.click_drag) { gantt2.attachEvent("onGanttRender", function() { setClickDrag(); }, { once: true }); } }); gantt2.attachEvent("onDestroy", () => { if (gantt2.ext.clickDrag) { gantt2.ext.clickDrag.destructor(); } }); } let _dragInProgress = false; class EventsManager { constructor(gantt2) { this._mouseDown = false; this._calculateDirectionVector = () => { const traceSteps = 10; if (this._trace.length >= traceSteps) { const dots = this._trace.slice(this._trace.length - traceSteps); const vectors = []; for (let i = 1; i < dots.length; i++) { vectors.push({ x: dots[i].x - dots[i - 1].x, y: dots[i].y - dots[i - 1].y }); } const resultVector = { x: 0, y: 0 }; vectors.forEach((vector) => { resultVector.x += vector.x; resultVector.y += vector.y; }); const magnitude = Math.sqrt(resultVector.x * resultVector.x + resultVector.y * resultVector.y); const angleDegrees = Math.atan2(Math.abs(resultVector.y), Math.abs(resultVector.x)) * 180 / Math.PI; return { magnitude, angleDegrees }; } return null; }; this._applyDndReadyStyles = () => { this._timeline.$task.classList.add("gantt_timeline_move_available"); }; this._clearDndReadyStyles = () => { this._timeline.$task.classList.remove("gantt_timeline_move_available"); }; this._getScrollPosition = (timeline) => { const gantt3 = this._gantt; return { x: gantt3.$ui.getView(timeline.$config.scrollX).getScrollState().position, y: gantt3.$ui.getView(timeline.$config.scrollY).getScrollState().position }; }; this._countNewScrollPosition = (coords) => { const vector = this._calculateDirectionVector(); let shiftX = this._startPoint.x - coords.x; let shiftY = this._startPoint.y - coords.y; if (vector) { if (vector.angleDegrees < 15) { shiftY = 0; } else if (vector.angleDegrees > 75) { shiftX = 0; } } const result = { x: this._scrollState.x + shiftX, y: this._scrollState.y + shiftY }; return result; }; this._setScrollPosition = (timeline, coords) => { const gantt3 = this._gantt; requestAnimationFrame(() => { gantt3.scrollLayoutCell(timeline.$id, coords.x, coords.y); }); }; this._stopDrag = (event2) => { const gantt3 = this._gantt; this._trace = []; gantt3.$root.classList.remove("gantt_noselect"); if (this._originalReadonly !== void 0 && this._mouseDown) { gantt3.config.readonly = this._originalReadonly; if (gantt3.config.drag_timeline && gantt3.config.drag_timeline.render) { gantt3.render(); } } if (this._originAutoscroll !== void 0) { gantt3.config.autoscroll = this._originAutoscroll; } if (gantt3.config.drag_timeline) { const { useKey } = gantt3.config.drag_timeline; if (useKey && event2[useKey] !== true) { return; } } this._mouseDown = false; _dragInProgress = false; }; this._startDrag = (event2) => { const gantt3 = this._gantt; this._originAutoscroll = gantt3.config.autoscroll; gantt3.config.autoscroll = false; _dragInProgress = true; gantt3.$root.classList.add("gantt_noselect"); this._originalReadonly = gantt3.config.readonly; gantt3.config.readonly = true; if (gantt3.config.drag_timeline && gantt3.config.drag_timeline.render) { gantt3.render(); } this._trace = []; this._mouseDown = true; const { x, y } = this._getScrollPosition(this._timeline); this._scrollState = { x, y }; this._startPoint = { x: event2.clientX, y: event2.clientY }; this._trace.push(this._startPoint); }; this._gantt = gantt2; this._domEvents = gantt2._createDomEventScope(); this._trace = []; } static create(gantt2) { return new EventsManager(gantt2); } static _isDragInProgress() { return _dragInProgress; } destructor() { this._domEvents.detachAll(); } attach(timeline) { this._timeline = timeline; const gantt2 = this._gantt; this._domEvents.attach(timeline.$task, "mousedown", (event2) => { if (!gantt2.config.drag_timeline) { return; } const { useKey, ignore, enabled } = gantt2.config.drag_timeline; if (enabled === false) { return; } let filterTargets = ".gantt_task_line, .gantt_task_link"; if (ignore !== void 0) { if (ignore instanceof Array) { filterTargets = ignore.join(", "); } else { filterTargets = ignore; } } if (filterTargets) { if (gantt2.utils.dom.closest(event2.target, filterTargets)) { return; } } if (useKey && event2[useKey] !== true) { return; } this._startDrag(event2); }); this._domEvents.attach(document, "keydown", (event2) => { if (!gantt2.config.drag_timeline) { return; } const { useKey } = gantt2.config.drag_timeline; if (useKey && event2[useKey] === true) { this._applyDndReadyStyles(); } }); this._domEvents.attach(document, "keyup", (event2) => { if (!gantt2.config.drag_timeline) { return; } const { useKey } = gantt2.config.drag_timeline; if (useKey && event2[useKey] === false) { this._clearDndReadyStyles(); this._stopDrag(event2); } }); this._domEvents.attach(document, "mouseup", (event2) => { this._stopDrag(event2); }); this._domEvents.attach(gantt2.$root, "mouseup", (event2) => { this._stopDrag(event2); }); this._domEvents.attach(document, "mouseleave", (event2) => { this._stopDrag(event2); }); this._domEvents.attach(gantt2.$root, "mouseleave", (event2) => { this._stopDrag(event2); }); this._domEvents.attach(gantt2.$root, "mousemove", (event2) => { if (!gantt2.config.drag_timeline) { return; } const { useKey } = gantt2.config.drag_timeline; if (useKey && event2[useKey] !== true) { return; } const clickDrag = this._gantt.ext.clickDrag; const clickDragUseKey = (this._gantt.config.click_drag || {}).useKey; if (clickDrag && clickDragUseKey) { if (!useKey && event2[clickDragUseKey]) { return; } } if (this._mouseDown === true) { this._trace.push({ x: event2.clientX, y: event2.clientY }); const scrollPosition = this._countNewScrollPosition({ x: event2.clientX, y: event2.clientY }); this._setScrollPosition(timeline, scrollPosition); this._scrollState = scrollPosition; this._startPoint = { x: event2.clientX, y: event2.clientY }; } }); } } function drag_timeline(gantt2) { if (!gantt2.ext) { gantt2.ext = {}; } gantt2.ext.dragTimeline = { create: () => EventsManager.create(gantt2), _isDragInProgress: () => EventsManager._isDragInProgress }; gantt2.config.drag_timeline = { enabled: true, render: false }; } var plainObjectConstructor = {}.constructor.toString(); function isCustomType(object) { var constructorString = object.constructor.toString(); return constructorString !== plainObjectConstructor; } function isExternalType(object) { return object.$$typeof && object.$$typeof.toString().includes("react."); } function copy(object) { var i, result; if (object && typeof object == "object") { switch (true) { case isDate(object): result = new Date(object); break; case isArray(object): result = new Array(object.length); for (i = 0; i < object.length; i++) { result[i] = copy(object[i]); } break; default: if (isCustomType(object)) { result = Object.create(object); } else if (isExternalType(object)) { result = object; return result; } else { result = {}; } for (i in object) { if (Object.prototype.hasOwnProperty.apply(object, [i])) result[i] = copy(object[i]); } break; } } return result || object; } function mixin(target, source, force) { for (var f in source) if (target[f] === void 0 || force) target[f] = source[f]; return target; } function defined(obj) { return typeof obj != "undefined"; } var seed; function uid() { if (!seed) seed = (/* @__PURE__ */ new Date()).valueOf(); seed++; return seed; } function bind(functor, object) { if (functor.bind) return functor.bind(object); else return function() { return functor.apply(object, arguments); }; } function event(el, event2, handler, capture) { if (el.addEventListener) el.addEventListener(event2, handler, capture === void 0 ? false : capture); else if (el.attachEvent) el.attachEvent("on" + event2, handler); } function eventRemove(el, event2, handler, capture) { if (el.removeEventListener) el.removeEventListener(event2, handler, capture === void 0 ? false : capture); else if (el.detachEvent) el.detachEvent("on" + event2, handler); } const utils = Object.freeze(Object.defineProperty({ __proto__: null, bind, copy, defined, event, eventRemove, mixin, uid }, Symbol.toStringTag, { value: "Module" })); function ScaleHelper(gantt2) { var dateHelper = gantt2.date; gantt2.$services; return { getSum: function(sizes, from, to) { if (to === void 0) to = sizes.length - 1; if (from === void 0) from = 0; var summ = 0; for (var i = from; i <= to; i++) summ += sizes[i]; return summ; }, setSumWidth: function(sum_width, scale, from, to) { var parts = scale.width; if (to === void 0) to = parts.length - 1; if (from === void 0) from = 0; var length = to - from + 1; if (from > parts.length - 1 || length <= 0 || to > parts.length - 1) return; var oldWidth = this.getSum(parts, from, to); var diff = sum_width - oldWidth; this.adjustSize(diff, parts, from, to); this.adjustSize(-diff, parts, to + 1); scale.full_width = this.getSum(parts); }, splitSize: function(width, count) { var arr = []; for (var i = 0; i < count; i++) arr[i] = 0; this.adjustSize(width, arr); return arr; }, adjustSize: function(width, parts, from, to) { if (!from) from = 0; if (to === void 0) to = parts.length - 1; var length = to - from + 1; var full = this.getSum(parts, from, to); for (var i = from; i <= to; i++) { var share = Math.floor(width * (full ? parts[i] / full : 1 / length)); full -= parts[i]; width -= share; length--; parts[i] += share; } parts[parts.length - 1] += width; }, sortScales: function(scales) { function cellSize(unit, step) { var d = new Date(1970, 0, 1); return dateHelper.add(d, step, unit) - d; } scales.sort(function(a, b) { if (cellSize(a.unit, a.step) < cellSize(b.unit, b.step)) { return 1; } else if (cellSize(a.unit, a.step) > cellSize(b.unit, b.step)) { return -1; } else { return 0; } }); for (var i = 0; i < scales.length; i++) { scales[i].index = i; } }, _prepareScaleObject: function(scale) { var format = scale.format; if (!format) { format = scale.template || scale.date || "%d %M"; } if (typeof format === "string") { format = gantt2.date.date_to_str(format); } return { unit: scale.unit || "day", step: scale.step || 1, format, css: scale.css, projection: scale.projection || null, column_width: scale.column_width || null }; }, primaryScale: function(config2) { const scaleConfig = config2 || gantt2.config; const primaryScale = scaleConfig.scales[0]; const result = { unit: primaryScale.unit, step: primaryScale.step, template: primaryScale.template, format: primaryScale.format, date: primaryScale.date, css: primaryScale.css || gantt2.templates.scale_cell_class, projection: primaryScale.projection || null, column_width: primaryScale.column_width || null }; return this._prepareScaleObject(result); }, getAdditionalScales: function(config2) { const scaleConfig = config2 || gantt2.config; const scales = scaleConfig.scales.slice(1); return scales.map((function(scale) { return this._prepareScaleObject(scale); }).bind(this)); }, prepareConfigs: function(scales, min_coll_width, container_width, scale_height, minDate, maxDate, rtl) { var heights = this.splitSize(scale_height, scales.length); var full_width = container_width; var configs = []; for (var i = scales.length - 1; i >= 0; i--) { var main_scale = i == scales.length - 1; var cfg = this.initScaleConfig(scales[i], minDate, maxDate); if (main_scale) { this.processIgnores(cfg); } if (main_scale && cfg.column_width) { full_width = cfg.column_width * (cfg.display_count || cfg.count); } this.initColSizes(cfg, min_coll_width, full_width, heights[i]); this.limitVisibleRange(cfg); if (main_scale) { full_width = cfg.full_width; } configs.unshift(cfg); } for (var i = 0; i < configs.length - 1; i++) { this.alineScaleColumns(configs[configs.length - 1], configs[i]); } for (var i = 0; i < configs.length; i++) { if (rtl) { this.reverseScale(configs[i]); } this.setPosSettings(configs[i]); } return configs; }, reverseScale: function(scale) { scale.width = scale.width.reverse(); scale.trace_x = scale.trace_x.reverse(); var indexes = scale.trace_indexes; scale.trace_indexes = {}; scale.trace_index_transition = {}; scale.rtl = true; for (var i = 0; i < scale.trace_x.length; i++) { scale.trace_indexes[scale.trace_x[i].valueOf()] = i; scale.trace_index_transition[indexes[scale.trace_x[i].valueOf()]] = i; } return scale; }, setPosSettings: function(config2) { for (var i = 0, len = config2.trace_x.length; i < len; i++) { config2.left.push((config2.width[i - 1] || 0) + (config2.left[i - 1] || 0)); } }, _ignore_time_config: function(date2, scale) { if (gantt2.config.skip_off_time) { var skip = true; var probe = date2; for (var i = 0; i < scale.step; i++) { if (i) { probe = dateHelper.add(date2, i, scale.unit); } skip = skip && !this.isWorkTime(probe, scale.unit); } return skip; } return false; }, processIgnores: function(config2) { config2.ignore_x = {}; config2.display_count = config2.count; }, initColSizes: function(config2, min_col_width, full_width, line_height) { var cont_width = full_width; config2.height = line_height; var column_count = config2.display_count === void 0 ? config2.count : config2.display_count; if (!column_count) column_count = 1; const fixedMode = !isNaN(config2.column_width * 1) && config2.column_width * 1 > 0; if (fixedMode) { const baseCellWidth = config2.column_width * 1; config2.col_width = baseCellWidth; cont_width = baseCellWidth * column_count; } else { config2.col_width = Math.floor(cont_width / column_count); if (min_col_width) { if (config2.col_width < min_col_width) { config2.col_width = min_col_width; cont_width = config2.col_width * column_count; } } } config2.width = []; var ignores = config2.ignore_x || {}; for (var i = 0; i < config2.trace_x.length; i++) { if (ignores[config2.trace_x[i].valueOf()] || config2.display_count == config2.count) { if (fixedMode) { config2.width[i] = config2.col_width; } else { config2.width[i] = 0; } } else { var width = 1; if (config2.unit == "month") { var days = Math.round((dateHelper.add(config2.trace_x[i], config2.step, config2.unit) - config2.trace_x[i]) / (1e3 * 60 * 60 * 24)); width = days; } config2.width[i] = width; } } if (!fixedMode) { this.adjustSize(cont_width - this.getSum(config2.width), config2.width); } config2.full_width = this.getSum(config2.width); }, initScaleConfig: function(config2, min_date, max_date) { var cfg = mixin({ count: 0, col_width: 0, full_width: 0, height: 0, width: [], left: [], trace_x: [], trace_indexes: {}, min_date: new Date(min_date), max_date: new Date(max_date) }, config2); this.eachColumn(config2.unit, config2.step, min_date, max_date, function(date2) { cfg.count++; cfg.trace_x.push(new Date(date2)); cfg.trace_indexes[date2.valueOf()] = cfg.trace_x.length - 1; }); cfg.trace_x_ascending = cfg.trace_x.slice(); return cfg; }, iterateScales: function(lower_scale, upper_scale, from, to, callback) { var upper_dates = upper_scale.trace_x; var lower_dates = lower_scale.trace_x; var prev = from || 0; var end = to || lower_dates.length - 1; var prevUpper = 0; for (var up = 1; up < upper_dates.length; up++) { var target_index = lower_scale.trace_indexes[+upper_dates[up]]; if (target_index !== void 0 && target_index <= end) { if (callback) { callback.apply(this, [prevUpper, up,