@lui297/vue-ganttastic
Version:
A simple and customizable Gantt chart component for Vue.js
1,077 lines (1,076 loc) • 35.3 kB
JavaScript
import { inject as Z, computed as _, defineComponent as P, createElementBlock as k, openBlock as T, Fragment as z, renderList as J, unref as C, normalizeStyle as L, renderSlot as R, createElementVNode as x, toDisplayString as W, createTextVNode as K, createCommentVNode as A, toRefs as Y, ref as G, watch as Q, nextTick as de, createBlock as V, Teleport as Be, createVNode as re, Transition as Ce, withCtx as F, onMounted as ae, getCurrentScope as Ee, onScopeDispose as Te, getCurrentInstance as fe, shallowRef as te, toValue as me, useSlots as ke, provide as j, normalizeClass as ne, withModifiers as De, mergeProps as Oe, TransitionGroup as Se } from "vue";
import { DateTime as N, Interval as le } from "luxon";
const ge = Symbol("CHART_ROWS_KEY"), he = Symbol("CONFIG_KEY"), ve = Symbol("EMIT_BAR_EVENT_KEY"), pe = Symbol("BAR_CONTAINER_KEY");
function I() {
const n = Z(he);
if (!n)
throw Error("Failed to inject config!");
return n;
}
function X(n = I()) {
const { chartStart: c, chartEnd: i, barStart: h, barEnd: b } = n, g = _(() => c.value ? f(c.value) : null), s = _(() => i.value ? f(i.value) : null);
function f(a, v) {
let e = a;
if (v !== void 0 && typeof a == "object" && !(a instanceof Date) && (e = v === "start" ? a[h.value] : a[b.value]), N.isDateTime(e))
return e;
if (e instanceof Date)
return N.fromJSDate(e);
if (typeof e == "string") {
const r = N.fromISO(e);
return r.isValid ? r : N.invalid("Invalid ISO string");
} else
return N.invalid("Invalid input type");
}
function l(a) {
return a instanceof Date ? N.fromJSDate(a) : typeof a == "string" ? N.fromISO(a) : a.toISO();
}
return {
chartStartDateTime: g,
chartEndDateTime: s,
toDateTime: f,
format: l
};
}
function ye() {
const { precision: n } = I(), { chartStartDateTime: c, chartEndDateTime: i } = X(), h = _(() => {
switch (n?.value) {
case "hour":
return "day";
case "day":
return "month";
case "date":
case "week":
return "month";
case "month":
return "year";
default:
throw new Error(
"Precision prop incorrect. Must be one of the following: 'hour', 'day', 'date', 'week', 'month'"
);
}
}), b = _(() => {
switch (n.value) {
case "date":
return "day";
case "week":
return "isoWeek";
default:
return n.value;
}
}), g = {
hour: "hh",
date: "dd.MMM",
day: "dd.MMM",
week: "WW",
month: "MMMM yyyy",
year: "yyyy"
};
return {
timeaxisUnits: _(() => {
const f = [], l = [], a = i.value.diff(c.value, "minutes").minutes, v = h.value, e = b.value;
let r = c.value, d = c.value;
for (; d <= i.value; ) {
let p = d.endOf("hour");
e === "month" && (p = d.endOf("month")), e === "isoWeek" && (p = d.endOf("week")), e === "day" && (p = d.endOf("day")), e === "hour" && (p = d.endOf("hour"));
const w = p > i.value ? i.value.diff(d, "minutes").minutes / a * 100 : p.diff(d, "minutes").minutes / a * 100;
l.push({
label: d.toFormat(g[n?.value]),
value: String(d),
date: d.toJSDate(),
dateTime: d,
width: String(w) + "%"
}), e === "month" && (d = d.plus({ month: 1 }).startOf("month")), e === "isoWeek" && (d = d.plus({ week: 1 }).startOf("week")), e === "day" && (d = d.plus({ day: 1 }).startOf("day")), e === "hour" && (d = d.plus({ hour: 1 }).startOf("hour"));
}
for (; r <= i.value; ) {
const p = r.endOf(v), w = p > i.value ? i.value.diff(r, "minutes").minutes / a * 100 : p.diff(r, "minutes").minutes / a * 100;
f.push({
label: r.toFormat(g[v]),
value: String(r),
date: r.toJSDate(),
dateTime: r,
width: String(w) + "%"
}), v === "year" && (r = r.plus({ year: 1 }).startOf("year")), v === "month" && (r = r.plus({ month: 1 }).startOf("month")), v === "day" && (r = r.plus({ day: 1 }).startOf("day"));
}
return { upperUnits: f, lowerUnits: l };
})
};
}
const _e = { class: "g-grid-container" }, Le = /* @__PURE__ */ P({
__name: "GGanttGrid",
props: {
highlightedUnits: {}
},
setup(n) {
const { colors: c } = I(), { timeaxisUnits: i } = ye();
return (h, b) => (T(), k("div", _e, [
(T(!0), k(z, null, J(C(i).lowerUnits, ({ label: g, value: s, width: f }) => (T(), k("div", {
key: g,
class: "g-grid-line",
style: L({
width: f,
background: h.highlightedUnits?.includes(Number(s)) ? C(c).hoverHighlight : void 0
})
}, null, 4))), 128))
]));
}
});
function oe() {
const n = Z(ge);
if (!n)
throw Error("Failed to inject getChartRows!");
return n;
}
const Me = { class: "g-label-column-rows" }, Re = /* @__PURE__ */ P({
__name: "GGanttLabelColumn",
setup(n) {
const { font: c, colors: i, labelColumnTitle: h, rowHeight: b } = I(), g = oe();
return (s, f) => (T(), k("div", {
class: "g-label-column",
style: L({ fontFamily: C(c), color: C(i).text })
}, [
R(s.$slots, "label-column-title", {}, () => [
x("div", {
class: "g-label-column-header",
style: L({ background: C(i).primary })
}, W(C(h)), 5)
]),
x("div", Me, [
(T(!0), k(z, null, J(C(g)(), ({ label: l }, a) => (T(), k("div", {
key: `${l}_${a}`,
class: "g-label-column-row",
style: L({
background: a % 2 === 0 ? C(i).ternary : C(i).quartenary,
height: `${C(b)}px`
})
}, [
R(s.$slots, "label-column-row", { label: l }, () => [
x("span", null, W(l), 1)
])
], 4))), 128))
])
], 4));
}
}), xe = { class: "g-timeaxis" }, $e = { class: "g-timeunits-container" }, Ge = { class: "g-timeunits-container" }, Ie = /* @__PURE__ */ P({
__name: "GGanttTimeaxis",
setup(n) {
const { precision: c, colors: i } = I(), { timeaxisUnits: h } = ye();
return (b, g) => (T(), k("div", xe, [
x("div", $e, [
(T(!0), k(z, null, J(C(h).upperUnits, ({ label: s, value: f, date: l, width: a, dateTime: v }, e) => (T(), k("div", {
key: s,
class: "g-upper-timeunit",
style: L({
background: e % 2 === 0 ? C(i).primary : C(i).secondary,
color: C(i).text,
width: a
})
}, [
R(b.$slots, "upper-timeunit", {
label: s,
value: f,
date: l,
dateTime: v
}, () => [
K(W(s), 1)
])
], 4))), 128))
]),
x("div", Ge, [
(T(!0), k(z, null, J(C(h).lowerUnits, ({ label: s, value: f, date: l, width: a, dateTime: v }, e) => (T(), k("div", {
key: s,
class: "g-timeunit",
style: L({
background: e % 2 === 0 ? C(i).ternary : C(i).quartenary,
color: C(i).text,
flexDirection: C(c) === "hour" ? "column" : "row",
alignItems: C(c) === "hour" ? "" : "center",
width: a
})
}, [
R(b.$slots, "timeunit", {
label: s,
value: f,
date: l,
dateTime: v
}, () => [
K(W(s), 1)
]),
C(c) === "hour" ? (T(), k("div", {
key: 0,
class: "g-timeaxis-hour-pin",
style: L({ background: C(i).text })
}, null, 4)) : A("", !0)
], 4))), 128))
])
]));
}
}), He = "cadetblue", Ne = /* @__PURE__ */ P({
__name: "GGanttBarTooltip",
props: {
bar: {},
modelValue: { type: Boolean }
},
setup(n) {
const c = {
hour: "hh:mm",
day: "dd. MMM HH:mm",
date: "dd. MMMM yyyy",
month: "dd. MMMM yyyy",
week: "d. MMMM yyyy (WW)"
}, i = n, { bar: h } = Y(i), { precision: b, font: g, barStart: s, barEnd: f, rowHeight: l } = I(), a = G("0px"), v = G("0px");
Q(
() => i.bar,
async () => {
await de();
const w = h?.value?.ganttBarConfig.id || "";
if (!w)
return;
const D = document.getElementById(w), { top: S, left: u } = D?.getBoundingClientRect() || {
top: 0,
left: 0
}, t = Math.max(u, 10);
a.value = `${S + l.value - 10}px`, v.value = `${t}px`;
},
{ deep: !0, immediate: !0 }
);
const e = _(() => h?.value?.ganttBarConfig.style?.background || He), { toDateTime: r } = X(), d = _(() => h.value?.[s.value]), p = _(() => h.value?.[f.value]), B = _(() => {
if (!h?.value)
return "";
const w = c[b.value], D = r(d.value).toFormat(w), S = r(p.value).toFormat(w);
return `${D} – ${S}`;
});
return (w, D) => (T(), V(Be, { to: "body" }, [
re(Ce, {
name: "g-fade",
mode: "out-in"
}, {
default: F(() => [
w.modelValue ? (T(), k("div", {
key: 0,
class: "g-gantt-tooltip",
style: L({
top: a.value,
left: v.value,
fontFamily: C(g)
})
}, [
x("div", {
class: "g-gantt-tooltip-color-dot",
style: L({ background: e.value })
}, null, 4),
R(w.$slots, "default", {
bar: C(h),
barStart: d.value,
barEnd: p.value
}, () => [
K(W(B.value), 1)
])
], 4)) : A("", !0)
]),
_: 3
})
]));
}
});
function ee(n = I()) {
const { chartSize: c } = n, { chartStartDateTime: i, chartEndDateTime: h, toDateTime: b, format: g } = X(n), s = _(() => h.value.diff(i.value, "minutes").minutes);
return {
mapTimeToPosition: (a) => {
const v = Number.isNaN(c.width.value) ? 0 : c.width.value, e = b(a).diff(i.value, "minutes").minutes;
return e && !Number.isNaN(e) ? Math.ceil(e / s.value * v) : 0;
},
mapPositionToTime: (a) => {
const v = Number.isNaN(c.width.value) ? 0 : c.width.value, e = a / v * s.value;
return e && !Number.isNaN(e) ? g(i.value.plus({ minutes: e })) : "";
}
};
}
const Fe = /* @__PURE__ */ P({
__name: "GGanttCurrentTime",
setup(n) {
const { mapTimeToPosition: c } = ee(), i = G(N.now()), { colors: h, currentTimeLabel: b } = I(), g = _(() => c(i.value.toISO({ extendedZone: !0 })));
return (s, f) => (T(), k("div", {
class: "g-grid-current-time",
style: L({
left: `${g.value}px`
})
}, [
x("div", {
class: "g-grid-current-time-marker",
style: L({
border: `1px dashed ${C(h).markerCurrentTime}`
})
}, null, 4),
x("span", {
class: "g-grid-current-time-text",
style: L({ color: C(h).markerCurrentTime })
}, [
R(s.$slots, "current-time-label", {}, () => [
K(W(C(b)), 1)
])
], 4)
], 4));
}
});
function Ae(n) {
return Ee() ? (Te(n), !0) : !1;
}
const Ue = typeof window < "u" && typeof document < "u";
typeof WorkerGlobalScope < "u" && globalThis instanceof WorkerGlobalScope;
function We(n) {
return Array.isArray(n) ? n : [n];
}
function Pe(n) {
return fe();
}
function Ve(n, c = !0, i) {
Pe() ? ae(n, i) : c ? n() : de(n);
}
const be = Ue ? window : void 0;
function q(n) {
var c;
const i = me(n);
return (c = i?.$el) != null ? c : i;
}
function qe() {
const n = te(!1), c = fe();
return c && ae(() => {
n.value = !0;
}, c), n;
}
function ze(n) {
const c = qe();
return _(() => (c.value, !!n()));
}
function Je(n, c, i = {}) {
const { window: h = be, ...b } = i;
let g;
const s = ze(() => h && "ResizeObserver" in h), f = () => {
g && (g.disconnect(), g = void 0);
}, l = _(() => {
const e = me(n);
return Array.isArray(e) ? e.map((r) => q(r)) : [q(e)];
}), a = Q(
l,
(e) => {
if (f(), s.value && h) {
g = new ResizeObserver(c);
for (const r of e)
r && g.observe(r, b);
}
},
{ immediate: !0, flush: "post" }
), v = () => {
f(), a();
};
return Ae(v), {
isSupported: s,
stop: v
};
}
function Ke(n, c = { width: 0, height: 0 }, i = {}) {
const { window: h = be, box: b = "content-box" } = i, g = _(() => {
var e, r;
return (r = (e = q(n)) == null ? void 0 : e.namespaceURI) == null ? void 0 : r.includes("svg");
}), s = te(c.width), f = te(c.height), { stop: l } = Je(
n,
([e]) => {
const r = b === "border-box" ? e.borderBoxSize : b === "content-box" ? e.contentBoxSize : e.devicePixelContentBoxSize;
if (h && g.value) {
const d = q(n);
if (d) {
const p = d.getBoundingClientRect();
s.value = p.width, f.value = p.height;
}
} else if (r) {
const d = We(r);
s.value = d.reduce((p, { inlineSize: B }) => p + B, 0), f.value = d.reduce((p, { blockSize: B }) => p + B, 0);
} else
s.value = e.contentRect.width, f.value = e.contentRect.height;
},
i
);
Ve(() => {
const e = q(n);
e && (s.value = "offsetWidth" in e ? e.offsetWidth : c.width, f.value = "offsetHeight" in e ? e.offsetHeight : c.height);
});
const a = Q(
() => q(n),
(e) => {
s.value = e ? c.width : 0, f.value = e ? c.height : 0;
}
);
function v() {
l(), a();
}
return {
width: s,
height: f,
stop: v
};
}
const ue = {
default: {
primary: "#eeeeee",
secondary: "#E0E0E0",
ternary: "#F5F5F5",
quartenary: "#ededed",
hoverHighlight: "rgba(204, 216, 219, 0.5)",
markerCurrentTime: "#000",
text: "#404040",
background: "white"
},
creamy: {
primary: "#ffe8d9",
secondary: "#fcdcc5",
ternary: "#fff6f0",
quartenary: "#f7ece6",
hoverHighlight: "rgba(230, 221, 202, 0.5)",
markerCurrentTime: "#000",
text: "#542d05",
background: "white"
},
crimson: {
primary: "#a82039",
secondary: "#c41238",
ternary: "#db4f56",
quartenary: "#ce5f64",
hoverHighlight: "rgba(196, 141, 141, 0.5)",
markerCurrentTime: "#000",
text: "white",
background: "white"
},
dark: {
primary: "#404040",
secondary: "#303030",
ternary: "#353535",
quartenary: "#383838",
hoverHighlight: "rgba(159, 160, 161, 0.5)",
markerCurrentTime: "#fff",
text: "white",
background: "#525252",
toast: "#1f1f1f"
},
flare: {
primary: "#e08a38",
secondary: "#e67912",
ternary: "#5e5145",
quartenary: "#665648",
hoverHighlight: "rgba(196, 141, 141, 0.5)",
markerCurrentTime: "#000",
text: "white",
background: "white"
},
fuchsia: {
primary: "#de1d5a",
secondary: "#b50b41",
ternary: "#ff7da6",
quartenary: "#f2799f",
hoverHighlight: "rgba(196, 141, 141, 0.5)",
markerCurrentTime: "#000",
text: "white",
background: "white"
},
grove: {
primary: "#3d9960",
secondary: "#288542",
ternary: "#72b585",
quartenary: "#65a577",
hoverHighlight: "rgba(160, 219, 171, 0.5)",
markerCurrentTime: "#000",
text: "white",
background: "white"
},
"material-blue": {
primary: "#0D47A1",
secondary: "#1565C0",
ternary: "#42a5f5",
quartenary: "#409fed",
hoverHighlight: "rgba(110, 165, 196, 0.5)",
markerCurrentTime: "#000",
text: "white",
background: "white"
},
sky: {
primary: "#b5e3ff",
secondary: "#a1d6f7",
ternary: "#d6f7ff",
quartenary: "#d0edf4",
hoverHighlight: "rgba(193, 202, 214, 0.5)",
markerCurrentTime: "#000",
text: "#022c47",
background: "white"
},
slumber: {
primary: "#2a2f42",
secondary: "#2f3447",
ternary: "#35394d",
quartenary: "#2c3044",
hoverHighlight: "rgba(179, 162, 127, 0.5)",
markerCurrentTime: "#fff",
text: "#ffe0b3",
background: "#38383b",
toast: "#1f1f1f"
},
vue: {
primary: "#258a5d",
secondary: "#41B883",
ternary: "#35495E",
quartenary: "#2a3d51",
hoverHighlight: "rgba(160, 219, 171, 0.5)",
markerCurrentTime: "#000",
text: "white",
background: "white"
}
}, Ye = { class: "g-gantt-rows-container" }, Xe = /* @__PURE__ */ P({
__name: "GGanttChart",
props: {
chartStart: {},
chartEnd: {},
precision: { default: "day" },
barStart: {},
barEnd: {},
currentTime: { type: Boolean },
currentTimeLabel: { default: "" },
width: { default: "100%" },
hideTimeaxis: { type: Boolean, default: !1 },
colorScheme: { default: "default" },
grid: { type: Boolean, default: !1 },
pushOnOverlap: { type: Boolean, default: !1 },
noOverlap: { type: Boolean, default: !1 },
rowHeight: { default: 40 },
highlightedUnits: { default: () => [] },
font: { default: "inherit" },
labelColumnTitle: { default: "" },
labelColumnWidth: { default: "150px" }
},
emits: ["click-bar", "mousedown-bar", "mouseup-bar", "dblclick-bar", "mouseenter-bar", "mouseleave-bar", "dragstart-bar", "drag-bar", "dragend-bar", "contextmenu-bar"],
setup(n, { emit: c }) {
const i = n, h = c, { width: b, font: g, colorScheme: s } = Y(i), f = ke(), l = _(
() => typeof s.value != "string" ? s.value : ue[s.value] || ue.default
), a = () => {
const u = f.default?.(), t = [];
return u && u.forEach((o) => {
if (o.props?.bars) {
const { label: m, bars: y } = o.props;
t.push({ label: m, bars: y });
} else Array.isArray(o.children) && o.children.forEach((m) => {
const y = m;
if (y?.props?.bars) {
const { label: E, bars: O } = y.props;
t.push({ label: E, bars: O });
}
});
}), t;
}, v = G(!1), e = G(!1), r = G(void 0);
let d;
const p = (u) => {
d && clearTimeout(d), d = setTimeout(() => {
v.value = !0;
}, 800), r.value = u;
}, B = () => {
clearTimeout(d), v.value = !1;
}, w = (u, t, o, m) => {
switch (u.type) {
case "click":
h("click-bar", { bar: t, e: u, datetime: o });
break;
case "mousedown":
h("mousedown-bar", { bar: t, e: u, datetime: o });
break;
case "mouseup":
h("mouseup-bar", { bar: t, e: u, datetime: o });
break;
case "dblclick":
h("dblclick-bar", { bar: t, e: u, datetime: o });
break;
case "mouseenter":
p(t), h("mouseenter-bar", { bar: t, e: u });
break;
case "mouseleave":
B(), h("mouseleave-bar", { bar: t, e: u });
break;
case "dragstart":
e.value = !0, h("dragstart-bar", { bar: t, e: u });
break;
case "drag":
h("drag-bar", { bar: t, e: u });
break;
case "dragend":
e.value = !1, h("dragend-bar", { bar: t, e: u, movedBars: m });
break;
case "contextmenu":
h("contextmenu-bar", {
bar: t,
e: u,
datetime: N.isDateTime(o) ? o.toJSDate() : o
});
break;
}
}, D = G(null), S = Ke(D);
return j(ge, a), j(he, {
...Y(i),
colors: l,
chartSize: S
}), j(ve, w), (u, t) => (T(), k("div", null, [
x("div", {
class: ne([{ "labels-in-column": !!u.labelColumnTitle }])
}, [
u.labelColumnTitle ? (T(), V(Re, {
key: 0,
style: L({
width: u.labelColumnWidth
})
}, {
"label-column-title": F(() => [
R(u.$slots, "label-column-title")
]),
"label-column-row": F(({ label: o }) => [
R(u.$slots, "label-column-row", { label: o })
]),
_: 3
}, 8, ["style"])) : A("", !0),
x("div", {
ref_key: "ganttChart",
ref: D,
class: ne(["g-gantt-chart", { "with-column": u.labelColumnTitle }]),
style: L({ width: C(b), background: l.value.background, fontFamily: C(g) })
}, [
u.hideTimeaxis ? A("", !0) : (T(), V(Ie, { key: 0 }, {
"upper-timeunit": F(({ label: o, value: m, date: y, dateTime: E }) => [
R(u.$slots, "upper-timeunit", {
label: o,
value: m,
date: y,
dateTime: E
})
]),
timeunit: F(({ label: o, value: m, date: y, dateTime: E }) => [
R(u.$slots, "timeunit", {
label: o,
value: m,
date: y,
dateTime: E
})
]),
_: 3
})),
u.grid ? (T(), V(Le, {
key: 1,
"highlighted-units": u.highlightedUnits
}, null, 8, ["highlighted-units"])) : A("", !0),
u.currentTime ? (T(), V(Fe, { key: 2 }, {
"current-time-label": F(() => [
R(u.$slots, "current-time-label")
]),
_: 3
})) : A("", !0),
x("div", Ye, [
R(u.$slots, "default")
])
], 6)
], 2),
re(Ne, {
"model-value": v.value || e.value,
bar: r.value
}, {
default: F(() => [
R(u.$slots, "bar-tooltip", { bar: r.value })
]),
_: 3
}, 8, ["model-value", "bar"])
]));
}
});
function ce(n, c = () => null, i = () => null, h = I()) {
const { barStart: b, barEnd: g, pushOnOverlap: s } = h, f = G(!1);
let l = 0, a;
const { mapPositionToTime: v } = ee(h), { toDateTime: e } = X(h), r = (u) => {
const t = document.getElementById(n.ganttBarConfig.id);
if (!t)
return;
switch (l = u.clientX - (t.getBoundingClientRect().left || 0), u.target.className) {
case "g-gantt-bar-handle-left":
document.body.style.cursor = "ew-resize", a = B;
break;
case "g-gantt-bar-handle-right":
document.body.style.cursor = "ew-resize", a = w;
break;
default:
a = p;
}
f.value = !0, window.addEventListener("mousemove", a), window.addEventListener("mouseup", S);
}, d = () => {
const u = document.getElementById(n.ganttBarConfig.id), t = u?.closest(".g-gantt-row-bars-container")?.getBoundingClientRect();
return { barElement: u, barContainer: t };
}, p = (u) => {
const { barElement: t, barContainer: o } = d();
if (!t || !o)
return;
const m = t.getBoundingClientRect().width, y = u.clientX - o.left - l, E = y + m;
D(y, E) || (n[b.value] = v(y), n[g.value] = v(E), c(u, n));
}, B = (u) => {
const { barElement: t, barContainer: o } = d();
if (!t || !o)
return;
const m = u.clientX - o.left, y = v(m);
(N.isDateTime(y) ? y : e(y) >= e(n, "end")) || (n[b.value] = y, c(u, n));
}, w = (u) => {
const { barElement: t, barContainer: o } = d();
if (!t || !o)
return;
const m = u.clientX - o.left, y = v(m);
(N.isDateTime(y) ? y : e(y) <= e(n, "start")) || (n[g.value] = y, c(u, n));
}, D = (u, t) => {
if (!s.value)
return !1;
const o = n.ganttBarConfig.dragLimitLeft, m = n.ganttBarConfig.dragLimitRight;
return u && o != null && u < o || t && m != null && t > m;
}, S = (u) => {
f.value = !1, document.body.style.cursor = "", window.removeEventListener("mousemove", a), window.removeEventListener("mouseup", S), i(u, n);
};
return {
isDragging: f,
initDrag: r
};
}
function we() {
const n = Z(ve);
if (!n)
throw Error("Failed to inject emitBarEvent!");
return n;
}
function je() {
const n = I(), c = oe(), i = we(), { pushOnOverlap: h, barStart: b, barEnd: g, noOverlap: s } = n, f = /* @__PURE__ */ new Map(), { toDateTime: l, format: a } = X(), v = (t, o) => {
const { initDrag: m } = ce(t, r, D, n);
i({ ...o, type: "dragstart" }, t), m(o), S(t);
}, e = (t, o) => {
const m = t.ganttBarConfig.bundle;
m != null && (c().forEach((y) => {
y.bars.forEach((E) => {
if (E.ganttBarConfig.bundle === m) {
const O = E === t ? D : () => null, { initDrag: $ } = ce(E, r, O, n);
$(o), S(E);
}
});
}), i({ ...o, type: "dragstart" }, t));
}, r = (t, o) => {
i({ ...t, type: "drag" }, o), d(o);
}, d = (t) => {
if (!h?.value)
return;
let o = t, { overlapBar: m, overlapType: y } = p(o);
for (; m; ) {
S(m);
const E = l(o[b.value]), O = l(o[g.value]), $ = l(m[b.value]), H = l(m[g.value]);
let M;
switch (y) {
case "left":
M = H.diff(E, "minutes").minutes, m[g.value] = a(o[b.value]), m[b.value] = a(
$.minus({ minutes: M })
);
break;
case "right":
M = O.diff($, "minutes").minutes, m[b.value] = a(O), m[g.value] = a(
H.plus({ minutes: M })
);
break;
default:
console.warn(
"Vue-Ganttastic: One bar is inside of the other one! This should never occur while push-on-overlap is active!"
);
return;
}
m && (y === "left" || y === "right") && B(m, M, y), o = m;
const U = p(m);
m = U.overlapBar, y = U.overlapType;
}
}, p = (t) => {
let o = !1, m = !1, y = !1;
const E = c().find((U) => U.bars.includes(t))?.bars ?? [], O = l(t[b.value]), $ = l(t[g.value]), H = E.find((U) => {
if (U === t)
return !1;
const se = l(U[b.value]), ie = l(U[g.value]);
return o = le.fromDateTimes(se, ie).contains(O), m = le.fromDateTimes(se, ie).contains($), y = o && m, o || m || y;
});
let M = null;
return o ? M = "left" : m ? M = "right" : y && (M = "between"), { overlapBar: H, overlapType: M };
}, B = (t, o, m) => {
S(t), t.ganttBarConfig.bundle && c().forEach((y) => {
y.bars.forEach((E) => {
E.ganttBarConfig.bundle === t.ganttBarConfig.bundle && E !== t && (S(E), w(E, o, m));
});
});
}, w = (t, o, m) => {
switch (m) {
case "left":
t[b.value] = a(
l(t, "start").minus({ minutes: o })
), t[g.value] = a(
l(t, "end").minus({ minutes: o })
);
break;
case "right":
t[b.value] = a(
l(t, "start").plus({ minutes: o })
), t[g.value] = a(
l(t, "end").plus({ minutes: o }).toJSDate()
);
}
d(t);
}, D = (t, o) => {
u();
const m = {
...t,
type: "dragend"
};
i(m, o, void 0, new Map(f)), f.clear();
}, S = (t) => {
if (!f.has(t)) {
const o = t[b.value], m = t[g.value];
f.set(t, { oldStart: o, oldEnd: m });
}
}, u = () => {
if (h.value || !s.value)
return;
let t = !1;
f.forEach((o, m) => {
const { overlapBar: y } = p(m);
y != null && (t = !0);
}), t && f.forEach(({ oldStart: o, oldEnd: m }, y) => {
y[b.value] = o, y[g.value] = m;
});
};
return {
initDragOfBar: v,
initDragOfBundle: e
};
}
function Ze() {
const { pushOnOverlap: n } = I(), c = oe(), i = (s) => {
const f = [];
return s != null && c().forEach((l) => {
l.bars.forEach((a) => {
a.ganttBarConfig.bundle === s && f.push(a);
});
}), f;
}, h = (s) => {
if (!n.value || s.ganttBarConfig.pushOnOverlap === !1)
return;
for (const l of ["left", "right"]) {
const a = l, { gapDistanceSoFar: v, bundleBarsAndGapDist: e } = b(
s,
0,
a
);
let r = v;
const d = e;
if (!d)
continue;
for (let B = 0; B < d.length; B++) {
const w = d[B].bar, D = d[B].gapDistance;
i(w.ganttBarConfig.bundle).filter(
(u) => u !== w
).forEach((u) => {
const t = b(u, D, a), o = t.gapDistanceSoFar, m = t.bundleBarsAndGapDist;
o != null && (!r || o < r) && (r = o), m.forEach((y) => {
d.find((E) => E.bar === y.bar) || d.push(y);
});
});
}
const p = document.getElementById(s.ganttBarConfig.id);
r != null && a === "left" ? s.ganttBarConfig.dragLimitLeft = p.offsetLeft - r : r != null && a === "right" && (s.ganttBarConfig.dragLimitRight = p.offsetLeft + p.offsetWidth + r);
}
i(s.ganttBarConfig.bundle).forEach((l) => {
l.ganttBarConfig.dragLimitLeft = s.ganttBarConfig.dragLimitLeft, l.ganttBarConfig.dragLimitRight = s.ganttBarConfig.dragLimitRight;
});
}, b = (s, f = 0, l) => {
const a = s.ganttBarConfig.bundle ? [{ bar: s, gapDistance: f }] : [];
let v = s, e = g(v, l);
if (l === "left")
for (; e; ) {
const r = document.getElementById(v.ganttBarConfig.id), d = document.getElementById(e.ganttBarConfig.id), p = d.offsetLeft + d.offsetWidth;
if (f += r.offsetLeft - p, e.ganttBarConfig.immobile)
return { gapDistanceSoFar: f, bundleBarsAndGapDist: a };
e.ganttBarConfig.bundle && a.push({
bar: e,
gapDistance: f
}), v = e, e = g(e, "left");
}
if (l === "right")
for (; e; ) {
const r = document.getElementById(v.ganttBarConfig.id), d = document.getElementById(e.ganttBarConfig.id), p = r.offsetLeft + r.offsetWidth;
if (f += d.offsetLeft - p, e.ganttBarConfig.immobile)
return { gapDistanceSoFar: f, bundleBarsAndGapDist: a };
e.ganttBarConfig.bundle && a.push({
bar: e,
gapDistance: f
}), v = e, e = g(e, "right");
}
return { gapDistanceSoFar: null, bundleBarsAndGapDist: a };
}, g = (s, f) => {
const l = document.getElementById(s.ganttBarConfig.id), a = c().find((e) => e.bars.includes(s))?.bars ?? [];
let v = [];
return f === "left" ? v = a.filter((e) => {
const r = document.getElementById(e.ganttBarConfig.id);
return r && r.offsetLeft < l.offsetLeft && e.ganttBarConfig.pushOnOverlap !== !1;
}) : v = a.filter((e) => {
const r = document.getElementById(e.ganttBarConfig.id);
return r && r.offsetLeft > l.offsetLeft && e.ganttBarConfig.pushOnOverlap !== !1;
}), v.length > 0 ? v.reduce((e, r) => {
const d = document.getElementById(e.ganttBarConfig.id), p = document.getElementById(r.ganttBarConfig.id), B = Math.abs(d.offsetLeft - l.offsetLeft), w = Math.abs(p.offsetLeft - l.offsetLeft);
return B < w ? e : r;
}, v[0]) : null;
};
return {
setDragLimitsOfGanttBar: h
};
}
const Qe = ["id"], et = { class: "g-gantt-bar-label" }, tt = ["innerHTML"], nt = /* @__PURE__ */ P({
__name: "GGanttBar",
props: {
bar: {}
},
setup(n) {
const c = n, i = we(), h = I(), { rowHeight: b } = h, { bar: g } = Y(c), { mapTimeToPosition: s, mapPositionToTime: f } = ee(), { initDragOfBar: l, initDragOfBundle: a } = je(), { setDragLimitsOfGanttBar: v } = Ze(), e = G(!1), r = _(() => g.value.ganttBarConfig);
function d(O) {
r.value.bundle != null ? a(g.value, O) : l(g.value, O), e.value = !0;
}
const p = () => {
v(g.value), !r.value.immobile && (window.addEventListener("mousemove", d, {
once: !0
}), window.addEventListener(
"mouseup",
() => {
window.removeEventListener("mousemove", d), e.value = !1;
},
{ once: !0 }
));
}, B = Z(pe), w = (O) => {
O.preventDefault(), O.type === "mousedown" && p();
const $ = B?.value?.getBoundingClientRect();
if (!$)
return;
const H = f(O.clientX - $.left);
let M;
H instanceof Date || typeof H == "string" ? M = H : typeof H?.toJSDate == "function" ? M = H.toJSDate() : M = void 0, i(O, g.value, M);
}, { barStart: D, barEnd: S, width: u, chartStart: t, chartEnd: o, chartSize: m } = h, y = G(0), E = G(0);
return ae(() => {
Q(
[g, u, t, o, m.width],
() => {
y.value = s(g.value[D.value]), E.value = s(g.value[S.value]);
},
{ deep: !0, immediate: !0 }
);
}), (O, $) => (T(), k("div", {
id: r.value.id,
class: ne(["g-gantt-bar", r.value.class || ""]),
style: L({
...r.value.style,
position: "absolute",
top: `${C(b) * 0.1}px`,
left: `${y.value}px`,
width: `${E.value - y.value}px`,
height: `${C(b) * 0.8}px`,
zIndex: e.value ? 3 : 2
}),
onMousedown: w,
onClick: w,
onDblclick: w,
onMouseenter: w,
onMouseleave: w,
onContextmenu: w
}, [
x("div", et, [
R(O.$slots, "default", { bar: C(g) }, () => [
x("div", null, W(r.value.label || ""), 1),
r.value.html ? (T(), k("div", {
key: 0,
innerHTML: r.value.html
}, null, 8, tt)) : A("", !0)
])
]),
r.value.hasHandles ? (T(), k(z, { key: 0 }, [
$[0] || ($[0] = x("div", { class: "g-gantt-bar-handle-left" }, null, -1)),
$[1] || ($[1] = x("div", { class: "g-gantt-bar-handle-right" }, null, -1))
], 64)) : A("", !0)
], 46, Qe));
}
}), rt = /* @__PURE__ */ P({
__name: "GGanttRow",
props: {
label: {},
bars: {},
highlightOnHover: { type: Boolean }
},
emits: ["drop"],
setup(n, { emit: c }) {
const i = n, h = c, { rowHeight: b, colors: g, labelColumnTitle: s } = I(), { highlightOnHover: f } = Y(i), l = G(!1), a = _(() => ({
height: `${b.value}px`,
background: f?.value && l.value ? g.value.hoverHighlight : null
})), { mapPositionToTime: v } = ee(), e = G(null);
j(pe, e);
const r = (p) => {
const B = e.value?.getBoundingClientRect();
if (!B) {
console.error("Vue-Ganttastic: failed to find bar container element for row.");
return;
}
const w = p.clientX - B.left, D = v(w);
h("drop", { e: p, datetime: D });
}, d = (p) => !p || /^\s*$/.test(p);
return (p, B) => (T(), k("div", {
class: "g-gantt-row",
style: L(a.value),
onDragover: B[0] || (B[0] = De((w) => l.value = !0, ["prevent"])),
onDragleave: B[1] || (B[1] = (w) => l.value = !1),
onDrop: B[2] || (B[2] = (w) => r(w)),
onMouseover: B[3] || (B[3] = (w) => l.value = !0),
onMouseleave: B[4] || (B[4] = (w) => l.value = !1)
}, [
!d(p.label) && !C(s) ? (T(), k("div", {
key: 0,
class: "g-gantt-row-label",
style: L({ background: C(g).primary, color: C(g).text })
}, [
R(p.$slots, "label", {}, () => [
K(W(p.label), 1)
])
], 4)) : A("", !0),
x("div", Oe({
ref_key: "barContainer",
ref: e,
class: "g-gantt-row-bars-container"
}, p.$attrs), [
re(Se, {
name: "bar-transition",
tag: "div"
}, {
default: F(() => [
(T(!0), k(z, null, J(p.bars, (w) => (T(), V(nt, {
key: w.ganttBarConfig.id,
bar: w
}, {
default: F(() => [
R(p.$slots, "bar-label", { bar: w })
]),
_: 2
}, 1032, ["bar"]))), 128))
]),
_: 3
})
], 16)
], 36));
}
}), st = {
install(n, c) {
n.component("GGanttChart", Xe), n.component("GGanttRow", rt);
}
};
export {
Xe as GGanttChart,
rt as GGanttRow,
st as default,
st as ganttastic
};