UNPKG

vue-ganttastic

Version:

A simple and customizable Gantt chart component for Vue.js

1,472 lines (1,322 loc) 59.6 kB
/*! * vue-ganttastic v0.9.33 * (c) Marko Zunic * Released under the MIT License. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var moment = _interopDefault(require('moment')); function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var GanttasticThemeColors = { "default": { primary: "#eeeeee", secondary: "#E0E0E0", ternary: "#F5F5F5", hoverHighlight: "rgba(204, 216, 219, 0.5)", text: "#404040", background: "white" }, "creamy": { primary: "#ffe8d9", secondary: "#fcdcc5", ternary: "#fff6f0", hoverHighlight: "rgba(230, 221, 202, 0.5)", text: "#542d05", background: "white" }, "crimson": { primary: "#a82039", secondary: "#c41238", ternary: "#db4f56", hoverHighlight: "rgba(196, 141, 141, 0.5)", text: "white", background: "white" }, "dark": { primary: "#404040", secondary: "#303030", ternary: "#353535", hoverHighlight: "rgba(159, 160, 161, 0.5)", text: "white", background: "#525252", toast: "#1f1f1f" }, "flare": { primary: "#e08a38", secondary: "#e67912", ternary: "#5e5145", hoverHighlight: "rgba(196, 141, 141, 0.5)", text: "white", background: "white" }, "fuchsia": { primary: "#de1d5a", secondary: "#b50b41", ternary: "#ff7da6", hoverHighlight: "rgba(196, 141, 141, 0.5)", text: "white", background: "white" }, "grove": { primary: "#3d9960", secondary: "#288542", ternary: "#72b585", hoverHighlight: "rgba(160, 219, 171, 0.5)", text: "white", background: "white" }, "material-blue": { primary: "#0D47A1", secondary: "#1565C0", ternary: "#42a5f5", hoverHighlight: "rgba(110, 165, 196, 0.5)", text: "white", background: "white" }, "sky": { primary: "#b5e3ff", secondary: "#a1d6f7", ternary: "#d6f7ff", hoverHighlight: "rgba(193, 202, 214, 0.5)", text: "#022c47", background: "white" }, "slumber": { primary: "#2c2e36", secondary: "#2f3447", ternary: "#35394d", hoverHighlight: "rgba(179, 162, 127, 0.5)", text: "#ffe0b3", background: "#38383b", toast: "#1f1f1f" }, "vue": { primary: "#258a5d", secondary: "#41B883", ternary: "#35495E", hoverHighlight: "rgba(160, 219, 171, 0.5)", text: "white", background: "white" } }; // var script = { name: "GGanttTimeaxis", props: { chartStart: String, chartEnd: String, rowLabelWidth: String, timemarkerOffset: { type: Number, "default": 0 }, locale: String, themeColors: Object }, data: function data() { return { axisDays: [], hourCount: null, timemarker: null, hourFontSize: "11px", dayFormat: "dddd, DD. MMMM" }; }, mounted: function mounted() { var _this = this; this.timemarker = document.querySelector("#g-timeaxis-marker"); this.initAxisDaysAndHours(); this.onWindowResize(); window.addEventListener('resize', this.onWindowResize); window.addEventListener("mousemove", function (event) { return _this.moveTimemarker(event); }); window.addEventListener("dragover", function (event) { return _this.moveTimemarker(event); }); }, methods: { initAxisDaysAndHours: function initAxisDaysAndHours() { this.axisDays = []; var start = moment(this.chartStart); var end = moment(this.chartEnd); this.hourCount = Math.floor(end.diff(start, "hour", true)); while (start.isBefore(end)) { var hourCountOfDay = start.format("DD.MM.YYYY") == end.format("DD.MM.YYYY") ? end.hour() : 24 - start.hour(); var widthPercentage = hourCountOfDay / this.hourCount * 100; var endHour = start.day() === end.day() ? end.hour() - 1 : 23; // -1 because the last hour is not included e.g if chartEnd=04:00 the last interval we display is between 03 and 04 this.axisDays.push(this.getAxisDayObject(start, widthPercentage, endHour)); start.add(1, "day").hour(0); } }, getAxisDayObject: function getAxisDayObject(datetime, widthPercentage, endHour) { var datetimeMoment = moment(datetime); var axisDayObject = { widthPercentage: widthPercentage, value: datetime.format("YYYY-MM-DD"), ganttHours: [] }; var startHour = datetimeMoment.hour(); for (var i = 0; i <= endHour - startHour; i++) { var hour = { text: datetimeMoment.format("HH"), fullDatetime: datetimeMoment.format("DD.MM.YYYY HH:mm") }; axisDayObject.ganttHours.push(hour); datetimeMoment.add(1, "hour"); } return axisDayObject; }, moveTimemarker: function moveTimemarker(event) { this.timemarker.style.left = event.clientX - this.timemarkerOffset - this.horizontalAxisContainer.left + "px"; }, onWindowResize: function onWindowResize() { this.horizontalAxisContainer = document.querySelector("#g-timeaxis").getBoundingClientRect(); this.hourFontSize = Math.min(9.5, 0.75 * (this.horizontalAxisContainer.width / this.hourCount)) + "px"; }, dayFormatted: function dayFormatted(day) { // do not display day text if the day is smaller than 12% return day.widthPercentage >= 12 ? moment(day.value).locale(this.locale).format(this.dayFormat) : ""; } }, watch: { chartStart: function chartStart() { this.initAxisDaysAndHours(); }, chartEnd: function chartEnd() { this.initAxisDaysAndHours(); } } }; function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { if (typeof shadowMode !== 'boolean') { createInjectorSSR = createInjector; createInjector = shadowMode; shadowMode = false; } // Vue.extend constructor export interop. const options = typeof script === 'function' ? script.options : script; // render functions if (template && template.render) { options.render = template.render; options.staticRenderFns = template.staticRenderFns; options._compiled = true; // functional template if (isFunctionalTemplate) { options.functional = true; } } // scopedId if (scopeId) { options._scopeId = scopeId; } let hook; if (moduleIdentifier) { // server build hook = function (context) { // 2.3 injection context = context || // cached call (this.$vnode && this.$vnode.ssrContext) || // stateful (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional // 2.2 with runInNewContext: true if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { context = __VUE_SSR_CONTEXT__; } // inject component styles if (style) { style.call(this, createInjectorSSR(context)); } // register component module identifier for async chunk inference if (context && context._registeredComponents) { context._registeredComponents.add(moduleIdentifier); } }; // used by ssr in case component is cached and beforeCreate // never gets called options._ssrRegister = hook; } else if (style) { hook = shadowMode ? function (context) { style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); } : function (context) { style.call(this, createInjector(context)); }; } if (hook) { if (options.functional) { // register for functional component in vue file const originalRender = options.render; options.render = function renderWithStyleInjection(h, context) { hook.call(context); return originalRender(h, context); }; } else { // inject component registration as beforeCreate hook const existing = options.beforeCreate; options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; } } return script; } const isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase()); function createInjector(context) { return (id, style) => addStyle(id, style); } let HEAD; const styles = {}; function addStyle(id, css) { const group = isOldIE ? css.media || 'default' : id; const style = styles[group] || (styles[group] = { ids: new Set(), styles: [] }); if (!style.ids.has(id)) { style.ids.add(id); let code = css.source; if (css.map) { // https://developer.chrome.com/devtools/docs/javascript-debugging // this makes source maps inside style tags work properly in Chrome code += '\n/*# sourceURL=' + css.map.sources[0] + ' */'; // http://stackoverflow.com/a/26603875 code += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) + ' */'; } if (!style.element) { style.element = document.createElement('style'); style.element.type = 'text/css'; if (css.media) style.element.setAttribute('media', css.media); if (HEAD === undefined) { HEAD = document.head || document.getElementsByTagName('head')[0]; } HEAD.appendChild(style.element); } if ('styleSheet' in style.element) { style.styles.push(code); style.element.styleSheet.cssText = style.styles .filter(Boolean) .join('\n'); } else { const index = style.ids.size - 1; const textNode = document.createTextNode(code); const nodes = style.element.childNodes; if (nodes[index]) style.element.removeChild(nodes[index]); if (nodes.length) style.element.insertBefore(textNode, nodes[index]); else style.element.appendChild(textNode); } } } /* script */ var __vue_script__ = script; /* template */ var __vue_render__ = function __vue_render__() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c('div', { attrs: { "id": "g-timeaxis" } }, [_c('div', { staticClass: "g-timeaxis-empty-space", style: { width: _vm.rowLabelWidth, background: _vm.themeColors.secondary } }), _vm._v(" "), _c('div', { staticClass: "g-timeaxis-days", style: { width: 100 - _vm.rowLabelWidth.replace('%', '') + "%" } }, _vm._l(_vm.axisDays, function (day, index) { return _c('div', { key: day.text, staticClass: "g-timeaxis-day", style: { width: day.widthPercentage + '%', background: index % 2 === 0 ? _vm.themeColors.primary : _vm.themeColors.secondary, color: _vm.themeColors.text } }, [_c('div', [_vm._v(" " + _vm._s(_vm.dayFormatted(day)) + " ")]), _vm._v(" "), _c('div', { style: { background: _vm.themeColors.ternary, color: _vm.themeColors.text } }, _vm._l(day.ganttHours, function (hour) { return _c('div', { key: hour.fullDatetime, staticClass: "g-timeaxis-hour" }, [_c('span', { style: { fontSize: _vm.hourFontSize } }, [_vm._v(_vm._s(hour.text))]), _vm._v(" "), _c('div', { staticClass: "g-timeaxis-hour-pin", style: { background: _vm.themeColors.text } })]); }), 0)]); }), 0), _vm._v(" "), _c('div', { attrs: { "id": "g-timeaxis-marker" } })]); }; var __vue_staticRenderFns__ = []; /* style */ var __vue_inject_styles__ = function __vue_inject_styles__(inject) { if (!inject) return; inject("data-v-4cda9c60_0", { source: "#g-timeaxis[data-v-4cda9c60],.g-timeaxis-day[data-v-4cda9c60],.g-timeaxis-day>div[data-v-4cda9c60],.g-timeaxis-days[data-v-4cda9c60]{display:flex;overflow:hidden}#g-timeaxis[data-v-4cda9c60]{position:sticky;top:0;width:100%;height:8%;min-height:75px;background:#fff;z-index:4;box-shadow:0 1px 3px 2px rgba(50,50,50,.5)}#g-timeaxis>.g-timeaxis-empty-space[data-v-4cda9c60]{width:20%;height:100%;background:#f5f5f5}#g-timeaxis>.g-timeaxis-days[data-v-4cda9c60]{position:relative;width:80%;height:100%,}.g-timeaxis-day[data-v-4cda9c60]{height:100%;flex-direction:column;background:#e0e0e0}.g-timeaxis-day[data-v-4cda9c60]:nth-child(odd){background:#e8e8e8}.g-timeaxis-day>div[data-v-4cda9c60]:nth-child(1){height:50%;justify-content:space-around;font-weight:700;align-items:center}.g-timeaxis-day>div[data-v-4cda9c60]:nth-child(2){align-items:flex-end;height:50%;justify-content:space-between;background:#f5f5f5;padding-top:2px;color:#212121}.g-timeaxis-hour[data-v-4cda9c60]{display:flex;justify-content:space-between;align-items:flex-start;flex-direction:column;opacity:.5;width:100%}.g-timeaxis-hour-pin[data-v-4cda9c60]{width:1px;height:8px}#g-timeaxis-marker[data-v-4cda9c60]{position:absolute;top:0;left:0;height:100%;width:3px;background:#000}", map: undefined, media: undefined }); }; /* scoped */ var __vue_scope_id__ = "data-v-4cda9c60"; /* module identifier */ var __vue_module_identifier__ = undefined; /* functional template */ var __vue_is_functional_template__ = false; /* style inject SSR */ /* style inject shadow dom */ var __vue_component__ = /*#__PURE__*/normalizeComponent({ render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ }, __vue_inject_styles__, __vue_script__, __vue_scope_id__, __vue_is_functional_template__, __vue_module_identifier__, false, createInjector, undefined, undefined); // var script$1 = { name: "GGanttGrid", props: { chartStart: { type: String }, chartEnd: { type: String }, rowLabelWidth: String, highlightedHours: { type: Array, "default": function _default() { return []; } } }, computed: { allHours: function allHours() { var momentChartStart = moment(this.chartStart); var momentChartEnd = moment(this.chartEnd); var res = []; while (momentChartStart.isSameOrBefore(momentChartEnd)) { res.push(momentChartStart.hour()); momentChartStart.add(1, "hour"); } return res; } } }; /* script */ var __vue_script__$1 = script$1; /* template */ var __vue_render__$1 = function __vue_render__() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c('div', { staticClass: "g-grid-container", style: { left: _vm.rowLabelWidth, width: 100 - this.rowLabelWidth.replace('%', '') + "%" } }, _vm._l(_vm.allHours, function (hour, index) { return _c('div', { key: index, "class": { 'g-grid-line': true, 'g-grid-line-highlighted': _vm.highlightedHours.includes(hour) } }); }), 0); }; var __vue_staticRenderFns__$1 = []; /* style */ var __vue_inject_styles__$1 = function __vue_inject_styles__(inject) { if (!inject) return; inject("data-v-c44fb5a6_0", { source: ".g-grid-container[data-v-c44fb5a6]{position:absolute;top:0;left:30%;width:70%;height:calc(100% - 23px);display:flex;justify-content:space-between}.g-grid-line[data-v-c44fb5a6]{width:1px;height:100%;background:#eaeaea}.g-grid-line-highlighted[data-v-c44fb5a6]{background:#90caf9;box-shadow:0 0 0 1px #90caf9}", map: undefined, media: undefined }); }; /* scoped */ var __vue_scope_id__$1 = "data-v-c44fb5a6"; /* module identifier */ var __vue_module_identifier__$1 = undefined; /* functional template */ var __vue_is_functional_template__$1 = false; /* style inject SSR */ /* style inject shadow dom */ var __vue_component__$1 = /*#__PURE__*/normalizeComponent({ render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 }, __vue_inject_styles__$1, __vue_script__$1, __vue_scope_id__$1, __vue_is_functional_template__$1, __vue_module_identifier__$1, false, createInjector, undefined, undefined); // var script$2 = { name: "GGanttBar", props: { bar: { type: Object }, barStart: { type: String }, // property name of the bar objects that represents the start datetime barEnd: { type: String }, // property name of the bar objects that represents the end datetime, barContainer: [Object, DOMRect], allBarsInRow: { type: Array } }, inject: ["getHourCount", "ganttChartProps", "initDragOfBarsFromBundle", "moveBarsFromBundleOfPushedBar", "setDragLimitsOfGanttBar", "onBarEvent", "onDragendBar", "getMinGapBetweenBars"], data: function data() { return { showTooltip: false, tooltipTimeout: null, dragLimitLeft: null, dragLimitRight: null, isDragging: false, isMainBarOfDrag: false, // is this the bar that was clicked on when starting to drag // or is it dragged along some other bar from the same bundle cursorOffsetX: 0, mousemoveCallback: null, // gets initialized when starting to drag // possible values: drag, dragByHandleLeft, dragByHandleRight, barStartBeforeDrag: null, barEndBeforeDrag: null }; }, computed: { // use these computed moment objects to work with the bar's start/end dates: // instead of directly mutating them: barStartMoment: { get: function get() { return moment(this.bar[this.barStart]); }, set: function set(value) { this.bar[this.barStart] = moment(value).format("YYYY-MM-DD HH:mm:ss"); } }, barEndMoment: { get: function get() { return moment(this.bar[this.barEnd]); }, set: function set(value) { this.bar[this.barEnd] = moment(value).format("YYYY-MM-DD HH:mm:ss"); } }, barConfig: function barConfig() { if (this.bar.ganttBarConfig) { return Object.assign(Object.assign({}, this.bar.ganttBarConfig), {}, { background: this.bar.ganttBarConfig.isShadow ? "grey" : this.bar.ganttBarConfig.background || this.bar.ganttBarConfig.backgroundColor, opacity: this.bar.ganttBarConfig.isShadow ? "0.3" : this.bar.ganttBarConfig.opacity }); } return {}; }, barStyle: function barStyle() { var xStart = this.mapTimeToPosition(this.barStartMoment); var xEnd = this.mapTimeToPosition(this.barEndMoment); return Object.assign(Object.assign({}, this.barConfig || {}), {}, { left: "".concat(xStart, "px"), width: "".concat(xEnd - xStart, "px"), height: "".concat(this.ganttChartProps.rowHeight - 6, "px"), zIndex: this.barConfig.zIndex || (this.isDragging ? 2 : 1) }); }, tooltipStyle: function tooltipStyle() { return { left: this.barStyle.left, top: "".concat(this.ganttChartProps.rowHeight, "px") }; }, chartStartMoment: function chartStartMoment() { return moment(this.ganttChartProps.chartStart); }, chartEndMoment: function chartEndMoment() { return moment(this.ganttChartProps.chartEnd); } }, methods: { onMouseenter: function onMouseenter(e) { var _this = this; if (this.tooltipTimeout) { clearTimeout(this.tooltipTimeout); } this.tooltipTimeout = setTimeout(function () { return _this.showTooltip = true; }, 800); this.onBarEvent({ event: e, type: e.type }, this); }, onMouseleave: function onMouseleave(e) { clearTimeout(this.tooltipTimeout); this.showTooltip = false; this.onBarEvent({ event: e, type: e.type }, this); }, onContextmenu: function onContextmenu(e) { var time = this.mapPositionToTime(e.clientX - this.barContainer.left).format("YYYY-MM-DD HH:mm:ss"); this.onBarEvent({ event: e, type: e.type, time: time }, this); }, onClick: function onClick(e) { var time = this.mapPositionToTime(e.clientX - this.barContainer.left).format("YYYY-MM-DD HH:mm:ss"); this.onBarEvent({ event: e, type: e.type, time: time }, this); }, onDblclick: function onDblclick(e) { var time = this.mapPositionToTime(e.clientX - this.barContainer.left).format("YYYY-MM-DD HH:mm:ss"); this.onBarEvent({ event: e, type: e.type, time: time }, this); }, onMousedown: function onMousedown(e) { var _this2 = this; e.preventDefault(); if (e.button === 2) { return; } if (!this.barConfig.immobile && !this.barConfig.isShadow) { this.setDragLimitsOfGanttBar(this); // initialize the dragging on next mousemove event: window.addEventListener("mousemove", this.onFirstMousemove, { once: true }); // if next mousemove happens after mouse up (if user just presses mouse button down, then up, without moving): window.addEventListener("mouseup", function () { return window.removeEventListener("mousemove", _this2.onFirstMousemove); }, { once: true }); } var time = this.mapPositionToTime(e.clientX - this.barContainer.left).format("YYYY-MM-DD HH:mm:ss"); this.onBarEvent({ event: e, type: e.type, time: time }, this); }, onFirstMousemove: function onFirstMousemove(e) { this.isMainBarOfDrag = true; // this method is injected here by GGanttChart.vue, and calls initDrag() // for all GGanttBars that belong to the same bundle as this bar: this.initDragOfBarsFromBundle(this, e); }, /* --------------------------------------------------------- */ /* ------------- METHODS FOR DRAGGING THE BAR -------------- */ /* --------------------------------------------------------- */ initDrag: function initDrag(e) { // "e" must be the mousedown event this.isDragging = true; this.barStartBeforeDrag = this.bar[this.barStart]; this.barEndBeforeDrag = this.bar[this.barEnd]; var barX = this.$refs["g-gantt-bar"].getBoundingClientRect().left; this.cursorOffsetX = e.clientX - barX; var mousedownType = e.target.className; switch (mousedownType) { case "g-gantt-bar-handle-left": document.body.style.cursor = "w-resize"; this.mousemoveCallback = this.dragByHandleLeft; break; case "g-gantt-bar-handle-right": document.body.style.cursor = "w-resize"; this.mousemoveCallback = this.dragByHandleRight; break; default: this.mousemoveCallback = this.drag; } window.addEventListener("mousemove", this.mousemoveCallback); window.addEventListener("mouseup", this.endDrag); }, drag: function drag(e) { var barWidth = this.$refs["g-gantt-bar"].getBoundingClientRect().width; var newXStart = e.clientX - this.barContainer.left - this.cursorOffsetX; var newXEnd = newXStart + barWidth; if (this.isPosOutOfDragRange(newXStart, newXEnd)) { return; } this.barStartMoment = this.mapPositionToTime(newXStart); this.barEndMoment = this.mapPositionToTime(newXEnd); this.manageOverlapping(); this.onBarEvent({ event: e, type: "drag" }, this); }, dragByHandleLeft: function dragByHandleLeft(e) { var newXStart = e.clientX - this.barContainer.left; var newStartMoment = this.mapPositionToTime(newXStart); if (newStartMoment.isSameOrAfter(this.barEndMoment) || this.isPosOutOfDragRange(newXStart, null)) { return; } this.barStartMoment = newStartMoment; this.manageOverlapping(); }, dragByHandleRight: function dragByHandleRight(e) { var newXEnd = e.clientX - this.barContainer.left; var newEndMoment = this.mapPositionToTime(newXEnd); if (newEndMoment.isSameOrBefore(this.barStartMoment) || this.isPosOutOfDragRange(null, newXEnd)) { return; } this.barEndMoment = newEndMoment; this.manageOverlapping(); }, isPosOutOfDragRange: function isPosOutOfDragRange(xStart, xEnd) { if (!this.ganttChartProps.pushOnOverlap) { return false; } if (xStart && this.dragLimitLeft !== null && xStart < this.dragLimitLeft + this.getMinGapBetweenBars()) { return true; } if (xEnd && this.dragLimitRight !== null && xEnd > this.dragLimitRight - this.getMinGapBetweenBars()) { return true; } return false; }, endDrag: function endDrag(e) { this.isDragging = false; this.dragLimitLeft = null; this.dragLimitRight = null; document.body.style.cursor = "auto"; window.removeEventListener("mousemove", this.mousemoveCallback); window.removeEventListener("mouseup", this.endDrag); if (this.isMainBarOfDrag) { this.onDragendBar(e, this); this.isMainBarOfDrag = false; } }, snapBack: function snapBack() { this.barStartMoment = this.barStartBeforeDrag; this.barEndMoment = this.barEndBeforeDrag; }, manageOverlapping: function manageOverlapping() { if (!this.ganttChartProps.pushOnOverlap || this.barConfig.pushOnOverlap === false) { return; } var currentBar = this.bar; var _this$getOverlapBarAn = this.getOverlapBarAndType(currentBar), overlapBar = _this$getOverlapBarAn.overlapBar, overlapType = _this$getOverlapBarAn.overlapType; while (overlapBar) { var minuteDiff = void 0; var currentStartMoment = moment(currentBar[this.barStart]); var currentEndMoment = moment(currentBar[this.barEnd]); var overlapStartMoment = moment(overlapBar[this.barStart]); var overlapEndMoment = moment(overlapBar[this.barEnd]); switch (overlapType) { case "left": minuteDiff = overlapEndMoment.diff(currentStartMoment, "minutes", true) + this.getMinGapBetweenBars(); overlapBar[this.barEnd] = currentStartMoment.subtract(this.getMinGapBetweenBars(), "minutes", true).format("YYYY-MM-DD HH:mm:ss"); overlapBar[this.barStart] = overlapStartMoment.subtract(minuteDiff, "minutes", true).format("YYYY-MM-DD HH:mm:ss"); break; case "right": minuteDiff = currentEndMoment.diff(overlapStartMoment, "minutes", true) + this.getMinGapBetweenBars(); overlapBar[this.barStart] = currentEndMoment.add(this.getMinGapBetweenBars(), "minutes", true).format("YYYY-MM-DD HH:mm:ss"); overlapBar[this.barEnd] = overlapEndMoment.add(minuteDiff, "minutes", true).format("YYYY-MM-DD HH:mm:ss"); break; default: // eslint-disable-next-line console.warn("One bar is inside of the other one! This should never occur while push-on-overlap is active!"); return; } this.moveBarsFromBundleOfPushedBar(overlapBar, minuteDiff, overlapType); currentBar = overlapBar; var _this$getOverlapBarAn2 = this.getOverlapBarAndType(overlapBar); overlapBar = _this$getOverlapBarAn2.overlapBar; overlapType = _this$getOverlapBarAn2.overlapType; } }, getOverlapBarAndType: function getOverlapBarAndType(bar) { var _this3 = this; var barStartMoment = moment(bar[this.barStart]); var barEndMoment = moment(bar[this.barEnd]); var overlapLeft, overlapRight, overlapInBetween; var overlapBar = this.allBarsInRow.find(function (otherBar) { if (otherBar === bar || otherBar.ganttBarConfig.pushOnOverlap === false) { return false; } var otherBarStart = moment(otherBar[_this3.barStart]); var otherBarEnd = moment(otherBar[_this3.barEnd]); overlapLeft = barStartMoment.isBetween(otherBarStart, otherBarEnd); overlapRight = barEndMoment.isBetween(otherBarStart, otherBarEnd); overlapInBetween = otherBarStart.isBetween(barStartMoment, barEndMoment) || otherBarEnd.isBetween(barStartMoment, barEndMoment); return overlapLeft || overlapRight || overlapInBetween; }); var overlapType = overlapLeft ? "left" : overlapRight ? "right" : overlapInBetween ? "between" : null; return { overlapBar: overlapBar, overlapType: overlapType }; }, // this is used in GGanttChart, when a bar from a bundle is pushed // so that bars from its bundle also get pushed moveBarByMinutesAndPush: function moveBarByMinutesAndPush(minuteCount, direction) { switch (direction) { case "left": this.barStartMoment = moment(this.barStartMoment).subtract(minuteCount, "minutes", true); this.barEndMoment = moment(this.barEndMoment).subtract(minuteCount, "minutes", true); break; case "right": this.barStartMoment = moment(this.barStartMoment).add(minuteCount, "minutes", true); this.barEndMoment = moment(this.barEndMoment).add(minuteCount, "minutes", true); break; default: // eslint-disable-next-line console.warn("wrong direction in moveBarByMinutesAndPush"); return; } this.manageOverlapping(); }, /* --------------------------------------------------------- */ /* ------- MAPPING POSITION TO TIME (AND VICE VERSA) ------- */ /* --------------------------------------------------------- */ mapTimeToPosition: function mapTimeToPosition(time) { var hourDiffFromStart = moment(time).diff(this.chartStartMoment, "hour", true); return hourDiffFromStart / this.getHourCount() * this.barContainer.width; }, mapPositionToTime: function mapPositionToTime(xPos) { var hourDiffFromStart = xPos / this.barContainer.width * this.getHourCount(); return this.chartStartMoment.clone().add(hourDiffFromStart, "hours"); } }, filters: { TimeFilter: function TimeFilter(value) { return moment(value).format("HH:mm"); } } }; /* script */ var __vue_script__$2 = script$2; /* template */ var __vue_render__$2 = function __vue_render__() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c('div', [_c('div', { ref: "g-gantt-bar", staticClass: "g-gantt-bar", style: _vm.barStyle, on: { "mouseenter": function mouseenter($event) { $event.stopPropagation(); return _vm.onMouseenter($event); }, "mouseleave": function mouseleave($event) { $event.stopPropagation(); return _vm.onMouseleave($event); }, "mousedown": function mousedown($event) { $event.stopPropagation(); return _vm.onMousedown($event); }, "click": function click($event) { $event.stopPropagation(); return _vm.onClick($event); }, "dblclick": function dblclick($event) { return _vm.onDblclick($event); }, "contextmenu": function contextmenu($event) { return _vm.onContextmenu($event); } } }, [_c('div', { staticClass: "g-gantt-bar-label" }, [_vm._t("bar-label", [_vm._v("\n " + _vm._s(_vm.barConfig.label || "") + "\n ")], { "bar": _vm.bar })], 2), _vm._v(" "), _vm.barConfig.handles ? [_c('div', { staticClass: "g-gantt-bar-handle-left" }), _vm._v(" "), _c('div', { staticClass: "g-gantt-bar-handle-right" })] : _vm._e()], 2), _vm._v(" "), _c('transition', { attrs: { "name": "fade", "mode": "out-in" } }, [!_vm.barConfig.noTooltip && (_vm.showTooltip || _vm.isDragging) ? _c('div', { staticClass: "g-gantt-tooltip", style: _vm.tooltipStyle }, [_c('div', { staticClass: "color-indicator", style: { background: this.barStyle.background || this.barStyle.backgroundColor } }), _vm._v("\n " + _vm._s(_vm._f("TimeFilter")(_vm.bar[_vm.barStart])) + "\n - \n " + _vm._s(_vm._f("TimeFilter")(_vm.bar[_vm.barEnd])) + "\n ")]) : _vm._e()])], 1); }; var __vue_staticRenderFns__$2 = []; /* style */ var __vue_inject_styles__$2 = function __vue_inject_styles__(inject) { if (!inject) return; inject("data-v-20272636_0", { source: ".g-gantt-bar[data-v-20272636]{position:absolute;top:2px;left:30px;display:flex;justify-content:space-between;align-items:center;color:#fff;width:300px;height:34px;border-radius:15px;background:#79869c;overflow:hidden}.g-gantt-bar-label[data-v-20272636]{width:100%;height:100%;box-sizing:border-box;padding:0 14px 0 14px;display:flex;justify-content:center;align-items:center}.g-gantt-bar-label>*[data-v-20272636]{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.g-gantt-bar>.g-gantt-bar-handle-left[data-v-20272636],.g-gantt-bar>.g-gantt-bar-handle-right[data-v-20272636]{position:absolute;width:10px;height:100%;background:#fff;opacity:.7;border-radius:40px;cursor:w-resize}.g-gantt-bar-handle-left[data-v-20272636]{left:0}.g-gantt-bar-handle-right[data-v-20272636]{right:0}.g-gantt-bar-label img[data-v-20272636]{pointer-events:none}.g-gantt-tooltip[data-v-20272636]{position:absolute;background:#000;color:#fff;z-index:3;font-size:.7em;padding:3px;border-radius:3px;transition:opacity .2s;display:flex;align-items:center}.g-gantt-tooltip[data-v-20272636]:before{content:'';position:absolute;top:0;left:10%;width:0;height:0;border:10px solid transparent;border-bottom-color:#000;border-top:0;margin-left:-5px;margin-top:-5px}.g-gantt-tooltip>.color-indicator[data-v-20272636]{width:8px;height:8px;border-radius:100%;margin-right:4px}.fade-enter-active[data-v-20272636]{animation:fade-in-data-v-20272636 .3s}.fade-leave-active[data-v-20272636]{animation:fade-in-data-v-20272636 .3s reverse}@keyframes fade-in-data-v-20272636{from{opacity:0}to{opacity:1}}", map: undefined, media: undefined }); }; /* scoped */ var __vue_scope_id__$2 = "data-v-20272636"; /* module identifier */ var __vue_module_identifier__$2 = undefined; /* functional template */ var __vue_is_functional_template__$2 = false; /* style inject SSR */ /* style inject shadow dom */ var __vue_component__$2 = /*#__PURE__*/normalizeComponent({ render: __vue_render__$2, staticRenderFns: __vue_staticRenderFns__$2 }, __vue_inject_styles__$2, __vue_script__$2, __vue_scope_id__$2, __vue_is_functional_template__$2, __vue_module_identifier__$2, false, createInjector, undefined, undefined); // var script$3 = { name: "GGanttRow", components: { GGanttBar: __vue_component__$2 }, props: { label: { type: String, "default": "Row" }, bars: { type: Array, "default": function _default() { return []; } }, barStart: { type: String, required: true }, // property name of the bar objects that represents the start datetime barEnd: { type: String, required: true }, // property name of the bar objects that represents the end datetime, highlightOnHover: Boolean }, inject: ["ganttChartProps", "getThemeColors", "getHourCount", "getChartStart", "getChartEnd"], data: function data() { return { barContainer: {} }; }, computed: { rowLabelStyle: function rowLabelStyle() { return { width: this.ganttChartProps.rowLabelWidth, height: this.ganttChartProps.rowHeight, background: this.$parent.themeColors.ternary, color: this.$parent.themeColors.text }; }, barsContainerStyle: function barsContainerStyle() { return { width: "".concat(100 - this.ganttChartProps.rowLabelWidth.replace('%', ''), "%") }; } }, mounted: function mounted() { this.barContainer = this.$refs.barContainer.getBoundingClientRect(); window.addEventListener("resize", this.onWindowResize); }, methods: { onDragover: function onDragover(e) { e.preventDefault(); // enables dropping content on row if (this.highlightOnHover) { this.$refs["g-gantt-row"].style.backgroundColor = this.getThemeColors().hoverHighlight; } }, onDragleave: function onDragleave() { this.$refs["g-gantt-row"].style.backgroundColor = null; }, onDrop: function onDrop(e) { var _this = this; var barContainer = this.$refs.barContainer.getBoundingClientRect(); var xPos = e.clientX - barContainer.left; var hourDiffFromStart = xPos / barContainer.width * this.getHourCount(); var time = moment(this.getChartStart()).add(hourDiffFromStart, "hours"); var bar = this.bars.find(function (bar) { return time.isBetween(bar[_this.barStart], bar[_this.barEnd]); }); this.$emit("drop", { event: e, bar: bar, time: time.format("YYYY-MM-DD HH:mm:ss") }); }, onMouseover: function onMouseover() { if (this.highlightOnHover) { this.$refs["g-gantt-row"].style.backgroundColor = this.getThemeColors().hoverHighlight; } }, onMouseleave: function onMouseleave() { this.$refs["g-gantt-row"].style.backgroundColor = null; }, onWindowResize: function onWindowResize() { // re-initialize the barContainer DOMRect variable, which will trigger re-rendering in the gantt bars this.barContainer = this.$refs.barContainer.getBoundingClientRect(); } }, watch: { 'ganttChartProps.rowLabelWidth': function ganttChartPropsRowLabelWidth() { this.barContainer = this.$refs.barContainer.getBoundingClientRect(); } } }; /* script */ var __vue_script__$3 = script$3; /* template */ var __vue_render__$3 = function __vue_render__() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c('div', _vm._g({ ref: "g-gantt-row", staticClass: "g-gantt-row", style: { height: _vm.$parent.rowHeight + "px" } }, _vm.$listeners), [_c('div', { staticClass: "g-gantt-row-label", style: _vm.rowLabelStyle }, [_vm._t("label", [_vm._v("\n " + _vm._s(_vm.label) + "\n ")])], 2), _vm._v(" "), _c('div', { ref: "barContainer", staticClass: "g-gantt-row-bars-container", style: _vm.barsContainerStyle, on: { "dragover": function dragover($event) { return _vm.onDragover($event); }, "dragleave": function dragleave($event) { return _vm.onDragleave($event); }, "drop": function drop($event) { return _vm.onDrop($event); }, "mouseover": function mouseover($event) { return _vm.onMouseover(); }, "mouseleave": function mouseleave($event) { return _vm.onMouseleave(); } } }, _vm._l(_vm.bars, function (bar, index) { return _c('g-gantt-bar', { key: "ganttastic_bar_" + index, ref: "ganttBar", refInFor: true, attrs: { "bar": bar, "bar-start": _vm.barStart, "bar-end": _vm.barEnd, "bar-container": _vm.barContainer, "all-bars-in-row": _vm.bars }, scopedSlots: _vm._u([{ key: "bar-label", fn: function fn(ref) { var bar = ref.bar; return [_vm._t("bar-label", null, { "bar": bar })]; } }], null, true) }); }), 1)]); }; var __vue_staticRenderFns__$3 = []; /* style */ var __vue_inject_styles__$3 = function __vue_inject_styles__(inject) { if (!inject) return; inject("data-v-419c73a4_0", { source: ".g-gantt-row[data-v-419c73a4]{display:flex;width:100%;height:40px;transition:background-color .2s}.g-gantt-row>.g-gantt-row-label[data-v-419c73a4]{display:flex;justify-content:center;align-items:center;width:20%;background:#e8e8e8;color:#424242;font-size:.9em;z-index:3;overflow:hidden;font-weight:700}.g-gantt-row>.g-gantt-row-bars-container[data-v-419c73a4]{position:relative;border-top:1px solid #eaeaea;width:70%;border-bottom:1px solid #eaeaea}", map: undefined, media: undefined }); }; /* scoped */ var __vue_scope_id__$3 = "data-v-419c73a4"; /* module identifier */ var __vue_module_identifier__$3 = undefined; /* functional template */ var __vue_is_functional_template__$3 = false; /* style inject SSR */ /* style inject shadow dom */ var __vue_component__$3 = /*#__PURE__*/normalizeComponent({ render: __vue_render__$3, staticRenderFns: __vue_staticRenderFns__$3 }, __vue_inject_styles__$3, __vue_script__$3, __vue_scope_id__$3, __vue_is_functional_template__$3, __vue_module_identifier__$3, false, createInjector, undefined, undefined); var script$4 = { name: "GGanttChart", components: { GGanttTimeaxis: __vue_component__, GGanttGrid: __vue_component__$1 }, props: { chartStart: { type: String, "default": moment().startOf("day").format("YYYY-MM-DD HH:mm:ss") }, chartEnd: { type: String, "default": moment().startOf("day").add(12, "hours").format("YYYY-MM-DD HH:mm:ss") }, hideTimeaxis: Boolean, rowLabelWidth: { type: String, "default": "10%" }, rowHeight: { type: Number, "default": 40 }, locale: { type: String, "default": "en" }, theme: { type: String }, grid: { type: Boolean }, highlightedHours: { type: Array, "default": function _default() { return []; } }, width: { type: String, "default": "100%" }, // the total width of the entire ganttastic component in % pushOnOverlap: { type: Boolean }, snapBackOnOverlap: { type: Boolean }, minGapBetweenBars: { type: Number, "default": 0 } }, data: function data() { return { timemarkerOffset: 0, movedBarsInDrag: new Set() }; }, computed: { hourCount: function hourCount() { var momentChartStart = moment(this.chartStart); var momentChartEnd = moment(this.chartEnd); return Math.floor(momentChartEnd.diff(momentChartStart, "hour", true)); }, themeColors: function themeColors() { return GanttasticThemeColors[this.theme] || GanttasticThemeColors["default"]; } }, methods: { getGanttBarChildrenList: function getGanttBarChildrenList() { var ganttBarChildren = []; var ganttRowChildrenList = this.$children.filter(function (childComp) { return childComp.$options.name === __vue_component__$3.name; }); ganttRowChildrenList.forEach(function (row) { var ganttBarChildrenOfRow = row.$children.filter(function (childComp) { return childComp.$options.name === __vue_component__$2.name; }); ganttBarChildren.push.apply(ganttBarChildren, _toConsumableArray(ganttBarChildrenOfRow)); }); return ganttBarChildren; }, getBarsFromBundle: function getBarsFromBundle(bundleId) { if (bundleId === undefined || bundleId === null) { return []; } return this.getGanttBarChildrenList().filter(function (ganttBarChild) { return ganttBarChild.barConfig.bundle === bundleId; }); }, initDragOfBarsFromBundle: function initDragOfBarsFromBundle(gGanttBar, e) { var _this = this; gGanttBar.initDrag(e); this.movedBarsInDrag.add(gGanttBar.bar); if (gGanttBar.barConfig.bundle !== null && gGanttBar.barConfig.bundle !== undefined) { this.getGanttBarChildrenList().forEach(function (ganttBarChild) { if (ganttBarChild.barConfig.bundle === gGanttBar.barConfig.bundle && ganttBarChild !== gGanttBar) { ganttBarChild.initDrag(e); _this.movedBarsInDrag.add(ganttBarChild.bar); } }); } }, moveBarsFromBundleOfPushedBar: function moveBarsFromBundleOfPushedBar(pushedBar, minuteDiff, overlapType) { var _this2 = this; this.movedBarsInDrag.add(pushedBar); var bundleId = pushedBar.ganttBarConfig.bundle; if (bundleId === undefined || bundleId === null) { return; } this.getGanttBarChildrenList().forEach(function (ganttBarChild) { if (ganttBarChild.barConfig.bundle === bundleId && ganttBarChild.bar !== pushedBar) { ganttBarChild.moveBarByMinutesAndPush(minuteDiff, overlapType); _this2.movedBarsInDrag.add(ganttBarChild.bar); } }); }, shouldSnapBackBar: function shouldSnapBackBar(ganttBar) { if (this.snapBackOnOverlap && ganttBar.barConfig.pushOnOverlap !== false) { var _ganttBar$getOverlapB = ganttBar.getOverlapBarAndType(ganttBar.bar), overlapBar = _ganttBar$getOverlapB.overlapBar; return !!overlapBar; } return false; }, snapBackBundleIfNeeded: function snapBackBundleIfNeeded(ganttBar) { var _this3 = this; var barsFromBundle = this.getBarsFromBundle(ganttBar.barConfig.bundle); if (this.shouldSnapBackBar(ganttBar) || barsFromBundle.some(function (gBar) { return _this3.shouldSnapBackBar(gBar); })) { ganttBar.snapBack(); barsFromBundle.forEach(function (gBar) { return gBar.snapBack(); }); return true; } return false; }, onBarEvent: function onBarEvent(_ref, ganttBar) { var event = _ref.event, type = _ref.type, time = _ref.time; this.$emit("".concat(type, "-bar"), { event: event, bar: ganttBar.bar, time: time }); }, onDragendBar: function onDragendBar(e, ganttBar) { var didSnapBack = this.snapBackBundleIfNeeded(ganttBar); var movedBars = didSnapBack ? new Set() : this.movedBarsInDrag; this.movedBarsInDrag = new Set(); this.$emit("dragend-bar", { event: e, bar: ganttBar.bar, movedBars: movedBars }); }, // ------------------------------------------------------------------------ // -------- METHODS FOR SETTING THE DRAG LIMIT OF A BAR ---------------- // ------------------------------------------------------------------------ // how far you can drag a bar depends on the position of the closest immobile bar // note that if a bar from the same row belongs to a bundle // other rows might need to be taken into consideration, too setDragLimitsOfGanttBar: function setDragLimitsOfGanttBar(bar) { var _this4 = this; if (!this.pushOnOverlap || bar.barConfig.pushOnOverlap === false) { return; } var _loop = function _loop() { var side = _arr[_i]; var _this4$countGapDistan = _this4.countGapDistanceToNextImmobileBar(bar, null, side, false), _this4$countGapDistan2 = _slicedToArray(_this4$countGapDistan, 2), totalGapDistance = _this4$countGapDistan2[0], bundleBarsOnPath = _this4$countGapDistan2[1]; var _loop2 = function _loop2(i) { var barFromBundle = bundleBarsOnPath[i].bar; var gapDist = bundleBarsOnPath[i].gapDistance; var otherBarsFromBundle = _this4.getBarsFromBundle(barFromBundle.barConfig.bundle).filter(function (otherBar) { return otherBar !== barFromBundle;