UNPKG

@lui297/vue-ganttastic

Version:

A simple and customizable Gantt chart component for Vue.js

1,077 lines (1,076 loc) 35.3 kB
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 };