vue-ganttastic
Version:
A simple and customizable Gantt chart component for Vue.js
1,472 lines (1,322 loc) • 59.6 kB
JavaScript
/*!
* 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;