@xpyjs/gantt-core
Version:
A powerful and flexible Gantt chart component library for modern web applications with TypeScript support
6,493 lines • 254 kB
JavaScript
var Bt = Object.defineProperty;
var zt = (f, t, e) => t in f ? Bt(f, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : f[t] = e;
var a = (f, t, e) => zt(f, typeof t != "symbol" ? t + "" : t, e);
import H from "dayjs";
import { default as si } from "dayjs";
import { merge as ot, isArray as V, isString as U, isFunction as j, cloneDeep as J, isObject as Tt, isNumber as Pt, omit as gt, throttle as ft, isBoolean as mt, debounce as Yt } from "lodash-es";
import v from "konva";
const St = "0.0.1-alpha.5";
function Nt() {
const f = "#eca710", t = "#ffffff", e = "#e7209e", i = "#ffffff", s = "#1c42e8";
[
" __ __ _____ _____ _____ _____ _____ ",
"| | || __|| _ || | ||_ _||_ _|",
"|- -|| | || || | | | | | | | ",
"|__|__||_____||__|__||_|___| |_| |_| "
].forEach((o) => {
console.log(
`%c${o}`,
`color: ${f}; font-weight: bold; font-family: monospace;`
);
}), console.log(
`%c 🚀 欢迎使用 XGantt %c Version: ${St} `,
`background-color: ${e}; color: ${t}; padding: 2px 4px; border-radius: 6px 0 0 6px; font-weight: bold; margin: 4px 0;`,
`background-color: ${s}; color: ${i}; padding: 2px 4px; border-radius: 0 6px 6px 0; font-weight: normal; margin: 4px 0;`
);
}
const z = class z {
/**
* 设置日志配置
* @param options - 新的日志配置
*/
static setOptions(t) {
z.options = { ...z.options, ...t };
}
/**
* 获取当前日志级别
* @returns 当前设置的日志级别
*/
static getLevel() {
return z.options.level;
}
/**
* 输出 DEBUG 级别的日志
* 仅当当前日志级别 <= DEBUG 时输出
* @param args - 需要打印的参数
*/
static debug(...t) {
z.logWithLevel(1, console.debug, ...t);
}
/**
* 输出 INFO 级别的日志
* 仅当当前日志级别 <= INFO 时输出
* @param args - 需要打印的参数
*/
static info(...t) {
z.logWithLevel(2, console.info, ...t);
}
/**
* 输出 WARN 级别的日志
* 仅当当前日志级别 <= WARN 时输出
* @param args - 需要打印的参数
*/
static warn(...t) {
z.logWithLevel(3, console.warn, ...t);
}
/**
* 输出 ERROR 级别的日志
* 仅当当前日志级别 <= ERROR 时输出
* @param args - 需要打印的参数
*/
static error(...t) {
z.logWithLevel(4, console.error, ...t);
}
/**
* 断言方法
* 如果条件为 false,则输出 ERROR 级别的日志
* @param condition - 断言条件
* @param args - 断言失败时需要打印的参数
*/
static assert(t, ...e) {
if (!t && z.options.level <= 4) {
const i = z.formatArgs("Assertion failed:", ...e);
console.error(...i);
}
}
/**
* 返回日志信息
*/
static getMessage(...t) {
return z.formatArgs(...t).join("");
}
/**
* 抛出异常
*/
static exception(...t) {
return new Error(z.getMessage(...t));
}
/**
* 根据级别输出日志的核心方法
* @param level - 当前尝试输出的日志级别
* @param logFn - 使用的 console 方法 (console.log, console.warn, etc.)
* @param args - 需要打印的参数
*/
static logWithLevel(t, e, ...i) {
if (z.options.level <= t) {
const s = z.formatArgs(...i);
e(...s);
}
}
/**
* 格式化日志参数,添加前缀和可选的时间戳
* @param args - 原始日志参数
* @returns 格式化后的日志参数数组
*/
static formatArgs(...t) {
const e = [z.Prefix];
return z.options.showTimestamp && e.unshift(`[${H().format("YYYY-MM-DD HH:mm:ss.SSS")}]`), [e.join(""), ...t];
}
};
a(z, "Prefix", "[XGantt]"), a(z, "options", {
// 默认级别,INFO 及以上会被打印
level: 2,
// 默认不显示时间戳
showTimestamp: !1
});
let L = z;
const at = () => ({
data: [],
links: {
show: !1,
key: "id",
data: [],
distance: 20,
dash: [6, 3],
width: 1,
gap: 5,
arrow: {
width: 6,
height: 8
},
radius: 3,
create: {
enabled: !1,
mode: "hover",
radius: 3,
width: 2,
from: !0,
to: !0
},
move: {
enabled: !1
}
},
baselines: {
data: [],
taskKey: "taskId",
show: !1,
fields: {
startTime: "startTime",
endTime: "endTime",
name: "name",
id: "id",
target: "target",
highlight: "highlight"
},
mode: "line",
position: "bottom",
backgroundColor: "#999",
opacity: 0.6,
radius: 2,
label: {
show: !1,
forceDisplay: !1,
color: "#666",
fontSize: 10,
position: "right",
fontFamily: "Arial"
},
compare: {
enabled: !1,
tolerance: 0.5,
mode: "both",
target: "end",
delayed: {
backgroundColor: "#ff4444",
opacity: 0.8
},
ahead: {
backgroundColor: "#44ff44",
opacity: 0.8
},
indicator: {
show: !0,
position: "top",
fontFamily: "Arial",
fontSize: 10,
size: 6,
delayed: {
show: !0,
color: "#af1b1b",
opacity: 1
},
ahead: {
show: !0,
color: "#1baf1b",
opacity: 1
},
ontime: {
show: !1,
color: "#999",
opacity: 1
}
}
}
},
milestone: {
show: !1,
shape: "diamond",
border: {
width: 1
},
label: {
show: !0,
text: "",
fontSize: 10,
fontFamily: "Arial",
position: "top-right"
}
},
summary: {
show: !1,
mode: "expand",
move: {
enabled: !1
}
},
fields: {
id: "id",
startTime: "startTime",
endTime: "endTime",
name: "name",
progress: "progress",
children: "children",
type: "type"
},
selection: {
enabled: !1,
includeSelf: !0
},
expand: {
show: !0,
enabled: !0
},
dateFormat: "YYYY-MM-DD HH:mm:ss",
locale: "en",
unit: "day",
table: {
width: 100,
ellipsis: !0,
align: "center",
headerAlign: "center",
emptyText: "-"
},
chart: {
autoCellWidth: !1,
cellWidth: "normal"
},
primaryColor: "#eca710",
border: {
color: "#e5e5e5"
},
header: {
height: 80,
color: "#000",
fontSize: 14,
fontWeight: 600,
fontFamily: "Arial"
},
row: {
height: 30,
indent: 16,
hover: {
backgroundColor: "#000",
opacity: 0.05
},
select: {
backgroundColor: "#000",
opacity: 0.1
}
},
bar: {
height: 20,
show: !0,
move: {
byUnit: !1,
link: {
child: "none",
parent: "none"
}
}
},
today: {
show: !0,
type: "line",
backgroundColor: "lightblue",
opacity: 1,
width: 1
},
weekend: {
show: !0,
backgroundColor: "#c9c9c9",
opacity: 0.1
},
holiday: {
opacity: 0.1
}
});
class Ut {
constructor() {
a(this, "options", at());
}
getOptions() {
return this.options;
}
setOptions(t, e = { merge: !0 }) {
var i;
this.options = e.merge ? ot(at(), this.options, t) : ot(at(), t), V((i = t.links) == null ? void 0 : i.data) && (this.options.links.data = t.links.data);
}
update(t) {
this.setOptions(t);
}
getRowBackgroundColor(t) {
var s;
let e = "";
const i = (s = this.options.row) == null ? void 0 : s.backgroundColor;
return U(i) ? e = i : V(i) && i.length > 0 ? e = i[t.level] : j(i) && (e = i(t.getEmitData())), e;
}
unpackFunc(t, e) {
return j(t) ? t(e.getEmitData()) : t;
}
}
class Xt {
constructor() {
a(this, "events", /* @__PURE__ */ new Map());
}
/**
* 注册事件监听器
* @param event 事件名称
* @param callback 回调函数
*/
on(t, e) {
var i;
this.events.has(t) || this.events.set(t, []), (i = this.events.get(t)) == null || i.push(e);
}
/**
* 触发事件
* @param event 事件名称
* @param args 参数列表
*/
emit(t, ...e) {
var i;
this.events.has(t) && ((i = this.events.get(t)) == null || i.forEach((s) => s(...e)));
}
/**
* 移除特定事件的特定监听器
* @param event 事件名称
* @param callback 要移除的回调函数
*/
off(t, e) {
var i;
this.events.has(t) && this.events.set(
t,
((i = this.events.get(t)) == null ? void 0 : i.filter((s) => s !== e)) || []
);
}
/**
* 移除所有事件监听器
*/
offAll() {
this.events.clear();
}
}
var y = /* @__PURE__ */ ((f) => (f.LOADED = "loaded", f.COLUMN_WIDTH_CHANGE = "column-width-change", f.MOVE_GUIDELINE = "move-guideline", f.SHOW_GUIDELINE = "show-guideline", f.HIDE_GUIDELINE = "hide-guideline", f.TOGGLE_COLLAPSE = "toggle-collapse", f.SCROLL = "scroll", f.CHART_OFFSET_CHANGE = "chart_offset_change", f.DATA_UPDATE = "data-update", f.VIEW_UPDATE = "view-update", f.UPDATE_TABLE_HEADER = "update_table_header", f.UPDATE_TABLE_BODY = "update_table_body", f.UPDATE_CHART_HEADER = "update_chart_header", f.UPDATE_TASK = "update_task", f.UPDATE_LINK = "update_link", f.CREATE_LINK = "create_link", f.TASK_SELECTED = "task_selected", f.TASK_UNSELECTED = "task_unselected", f.SELECT_LINK = "select_link", f.CHECK_TASK = "check_task", f.CONTEXT_LINK = "context_link", f.ROW_CLICK = "row-click", f.ROW_DBL_CLICK = "row-dbl-click", f.ROW_CONTEXTMENU = "row-contextmenu", f.SLIDER_CLICK = "slider-click", f.SLIDER_DBL_CLICK = "slider-dbl-click", f.SLIDER_CONTEXTMENU = "slider-contextmenu", f.SLIDER_MOVING = "slider-moving", f.SLIDER_HOVER = "slider-hover", f.SLIDER_LEAVE = "slider-leave", f.ROW_HIGHLIGHT = "row-highlight", f.ROW_UNHIGHLIGHT = "row-unhighlight", f.TASK_DRAG_START = "task-drag-start", f.TASK_DRAG_MOVE = "task-drag-move", f.TASK_DRAG_END = "task-drag-end", f.BASELINE_CLICK = "baseline-click", f.BASELINE_CONTEXTMENU = "baseline-contextmenu", f.BASELINE_MOUSEOVER = "baseline-mouseover", f.BASELINE_MOUSEOUT = "baseline-mouseout", f.ERROR = "error", f))(y || {}), q = /* @__PURE__ */ ((f) => (f.LINK_NOT_ALLOWED = "LINK_NOT_ALLOWED", f.LINK_SAME = "LINK_SAME", f.LINK_EXIST = "LINK_EXIST", f))(q || {});
function Z() {
return Math.random().toString(36).substring(2, 15);
}
class dt {
constructor(t, e, i, s, n) {
a(this, "__key__", Z());
/**
* 任务ID
* 如果没有提供,则会自动生成一个唯一ID
*/
a(this, "id");
/**
* 任务名称
*/
a(this, "name");
/**
* 任务开始时间
* 如果没有提供,则默认为 undefined
*/
a(this, "startTime");
/**
* 任务结束时间
* 如果没有提供,则默认为 undefined
*/
a(this, "endTime");
/**
* 任务进度
*/
a(this, "progress");
/** 任务类型 */
a(this, "type");
/**
* 是否展开
* 如果没有提供,则默认为 true
*/
a(this, "expanded");
/**
* 子任务列表
* 如果没有子任务,则默认为空数组
*/
a(this, "children");
/**
* 父任务
* 如果没有父任务,则默认为 undefined
*/
a(this, "parent");
/**
* 任务层级,从0开始
*/
a(this, "level");
/**
* 在扁平化列表中的索引位置,从0开始
*/
a(this, "flatIndex");
/**
* 时间持续间隔
*/
a(this, "duration", 0);
/**
* 原始数据
*/
a(this, "data");
a(this, "fields");
this.store = t, this.event = e, this.fields = this.store.getOptionManager().getOptions().fields, this.id = n || i[this.fields.id] || Z(), this.data = i, this.name = i[this.fields.name] || "", this.type = i[this.fields.type] || "task", this.updateMode(), this.progress = i[this.fields.progress], this.expanded = this.store.getOptionManager().getOptions().expand.show ? this.store.getOptionManager().getOptions().expand.enabled : !0, this.children = [], this.level = s && s.level !== void 0 ? s.level + 1 : 0, this.parent = s, this.flatIndex = 0, this.store.updateTime(this.startTime, this.endTime);
}
getField(t) {
if (!t || U(t) && t.trim() === "")
return;
if (!t.includes("."))
return this.data[t];
const e = t.split(".");
let i = this.data;
for (let s = 0; s < e.length; s++) {
const n = e[s];
if (i == null || typeof i != "object" || !(n in i))
return;
i = i[n];
}
return Tt(i) ? J(i) : i;
}
/** 切换展示模式时,需要调整时间 */
updateMode() {
this.data[this.fields.startTime] && (this.startTime = H(this.data[this.fields.startTime])), this.data[this.fields.endTime] && (this.endTime = H(this.data[this.fields.endTime])), this.startTime && this.endTime && (this.duration = this.endTime.diff(this.startTime)), this.isMilestone() && (this.endTime = this.startTime);
}
updateData(t) {
this.data = t, t[this.fields.name] && (this.name = t[this.fields.name]), t[this.fields.type] && (this.type = t[this.fields.type]), this.updateMode(), t[this.fields.progress] !== void 0 && (this.progress = t[this.fields.progress]), this.event.emit(y.UPDATE_TASK, this);
}
updateTime(t, e) {
var s, n;
this.startTime = t, this.endTime = this.isMilestone() ? t : e;
const i = (n = (s = this.store) == null ? void 0 : s.getOptionManager().getOptions()) == null ? void 0 : n.dateFormat;
this.data[this.fields.startTime || "startTime"] = this.startTime.format(i), this.isMilestone() ? this.data[this.fields.endTime || "endTime"] = this.startTime.add(this.duration).format(i) : this.data[this.fields.endTime || "endTime"] = this.endTime.format(i), this.event.emit(y.UPDATE_TASK, this);
}
clone() {
return new dt(
this.store,
this.event,
J(this.data),
this.parent,
this.id
);
}
getEmitData() {
return {
data: this.data,
$index: this.flatIndex,
level: this.level + 1
};
}
getAllChildren() {
const t = [], e = (i) => {
i.forEach((s) => {
t.push(s), V(s.children) && s.children.length > 0 && e(s.children);
});
};
return e(this.children), t;
}
isMilestone() {
return this.store.getOptionManager().getOptions().milestone.show ? this.type === "milestone" : !1;
}
isSummary() {
return this.store.getOptionManager().getOptions().summary.show ? this.type === "summary" : !1;
}
}
class Vt {
constructor(t, e, i) {
/** 基线ID */
a(this, "id");
/** 任务ID */
a(this, "taskId");
/** 开始时间 */
a(this, "startTime");
/** 结束时间 */
a(this, "endTime");
/** 基线名称 */
a(this, "name");
/** 原始数据 */
a(this, "data");
/** 是否高亮 */
a(this, "highlight", !0);
/** 是否为指示器对比基线 */
a(this, "target", !1);
this.store = t, this.event = e;
const s = this.store.getOptionManager().getOptions().fields, n = this.store.getOptionManager().getOptions().baselines.fields;
this.taskId = i[t.getOptionManager().getOptions().baselines.taskKey], this.id = i[s.id] || i[n.id] || Z(), this.name = i[s.name] || i[n.name] || "", this.highlight = i[n.highlight] !== !1, this.target = i[n.target] === !0;
const o = i[s.startTime] || i[n.startTime];
o && (this.startTime = H(o));
const r = i[s.endTime] || i[n.endTime];
r && (this.endTime = H(r)), this.data = i;
}
getField(t) {
return this.data[t];
}
/**
* 验证基线的有效性
*/
validate() {
return !this.taskId || !this.startTime || !this.endTime ? !1 : this.startTime.isBefore(this.endTime);
}
/**
* 获取基线与任务的时间差异分析
*/
getTimeDiff() {
if (!this.validate()) return null;
const t = this.store.getDataManager().getTaskById(this.taskId);
if (!t || !t.startTime || !t.endTime) return null;
const e = this.store.getTimeAxis().getCellUnit(), i = this.startTime.diff(t.startTime, e, !0), s = this.endTime.diff(t.endTime, e, !0), n = this.store.getOptionManager().getOptions().baselines.compare.tolerance, o = i < -n ? "delayed" : i > n ? "ahead" : "ontime", r = s < -n ? "delayed" : s > n ? "ahead" : "ontime", l = this.endTime.diff(this.startTime, e, !0), c = t.endTime.diff(t.startTime, e, !0), g = l > 0 ? (c - l) / l * 100 : 0;
return { startDiff: i, endDiff: s, startStatus: o, endStatus: r, progressDiff: g, unit: e };
}
}
class Kt {
constructor(t, e) {
/**
* 原始数据
*/
a(this, "rawData", []);
/**
* 任务列表。树形结构
*/
a(this, "tasks", []);
/**
* 任务映射,使用ID作为键,便于快速查找
*/
a(this, "taskMap", /* @__PURE__ */ new Map());
/**
* 缓存扁平化的可视任务列表
* 用于提高性能,避免每次都遍历树形结构
*/
a(this, "visibleTasksCache", []);
/** 标记缓存是否需要更新 */
a(this, "isDirty", !0);
/** 缓存被折叠的任务 ID */
a(this, "collapsedTaskIds", /* @__PURE__ */ new Set());
/** 存储当前选中的任务ID */
a(this, "selectedTaskId", null);
/** 选中列表 */
a(this, "checkedList", []);
/** 基线数据 */
a(this, "baselines", []);
/** 基线映射,使用ID作为键 */
a(this, "baselineMap", /* @__PURE__ */ new Map());
/** 任务与基线映射,使用任务ID作为键。 一个任务可以对应多条基线 */
a(this, "baselineTaskMap", /* @__PURE__ */ new Map());
/** 数据最大层级。 0 开始 */
a(this, "dataLevel", 0);
this.store = t, this.event = e;
}
/**
* 设置源数据并初始化任务
*/
setData(t, e = !1) {
this.rawData = t, this.initTasks(e), this.invalidateCache(), this.event.emit(y.DATA_UPDATE);
}
/**
* 初始化任务
*/
initTasks(t = !1) {
this.dataLevel = 0, t ? (this.tasks = [], this.taskMap.clear(), this.collapsedTaskIds.clear(), this.rawData.forEach((e) => {
this.tasks.push(this.createTask(e));
})) : this.rawData.length > 0 ? this.updateTask(this.rawData, this.tasks) : (this.tasks = [], this.taskMap.clear(), this.collapsedTaskIds.clear());
}
createTask(t, e) {
const i = this.store.getOptionManager().getOptions().fields, s = new dt(this.store, this.event, t, e);
return Array.isArray(t[i.children]) && (s.children = t[i.children].map(
(n) => this.createTask(n, s)
)), this.taskMap.set(s.id, s), this.dataLevel = Math.max(this.dataLevel, s.level), s;
}
updateTask(t, e, i) {
let s = 0;
for (; s < t.length; ) {
const n = t[s], o = e[s];
if (n && !o) {
const r = this.createTask(n, i);
e.push(r), this.taskMap.set(r.id, r), this.dataLevel = Math.max(this.dataLevel, r.level);
} else !n && o ? (this.taskMap.delete(o.id), e.splice(s, 1)) : n && o && (n[this.store.getOptionManager().getOptions().fields.id] === o.id ? (o.updateData(n), this.dataLevel = Math.max(this.dataLevel, o.level)) : (this.taskMap.delete(o.id), e[s] = this.createTask(n, o.parent), this.taskMap.set(e[s].id, e[s]), this.dataLevel = Math.max(this.dataLevel, e[s].level)));
if (n[this.store.getOptionManager().getOptions().fields.children]) {
const r = n[this.store.getOptionManager().getOptions().fields.children];
if (o && o.children)
this.updateTask(r, o.children, o);
else {
const l = r.map(
(c) => this.createTask(c, e[s])
);
e[s].children = l;
}
} else o && o.children && (o.children = []);
s++;
}
e.length >= s && e.splice(s).forEach((o) => {
this.taskMap.delete(o.id);
});
}
/**
* 获取源数据
*/
getData() {
return this.rawData;
}
/**
* 获取所有任务
*/
getTasks(t = !0) {
return t ? this.tasks : Array.from(this.taskMap.values());
}
/**
* 通过 ID 获取任务
*/
getTaskById(t) {
return this.taskMap.get(t);
}
/**
* 移动任务位置
*/
// moveTask(
// id: string,
// targetParentId?: string,
// index?: number
// ): Task | undefined {
// const task = this.getTaskById(id);
// if (!task) {
// return undefined;
// }
// // 从原位置移除
// if (task.parent && task.parent.children) {
// task.parent.children = task.parent.children.filter(
// child => child.id !== id
// );
// } else {
// this.tasks = this.tasks.filter(t => t.id !== id);
// }
// // 移动到新位置
// let targetTasks: Task[];
// let targetParent: Task | undefined;
// if (targetParentId) {
// targetParent = this.getTaskById(targetParentId);
// if (!targetParent) {
// return undefined;
// }
// targetTasks = targetParent.children || [];
// targetParent.children = targetTasks;
// } else {
// targetTasks = this.tasks;
// }
// // 更新任务的父任务和层级
// task.parent = targetParent;
// task.level = targetParent
// ? targetParent.level !== undefined
// ? targetParent.level + 1
// : 0
// : 0;
// // 更新子任务的层级
// if (task.children && task.children.length > 0) {
// this.updateChildrenLevel(task);
// }
// // 插入到目标位置
// if (index !== undefined && index >= 0 && index <= targetTasks.length) {
// targetTasks.splice(index, 0, task);
// } else {
// targetTasks.push(task);
// }
// this.invalidateCache(); // 移动任务后,缓存失效
// this.event.emit(EventName.VIEW_UPDATE);
// return task;
// }
/**
* 展开任务
*/
expandTask(t, e = !1) {
const i = this.getTaskById(t);
return i ? (i.expanded = !i.expanded, i.expanded ? this.collapsedTaskIds.delete(i.id) : this.collapsedTaskIds.add(i.id), e && i.children && i.children.length > 0 && i.children.forEach((s) => {
this.expandTask(s.id, e);
}), this.invalidateCache(), this.event.emit(y.VIEW_UPDATE), !0) : !1;
}
/**
* 按条件筛选任务
*/
// filterTasks(criteria: (task: Task) => boolean): Task[] {
// return Array.from(this.taskMap.values()).filter(criteria);
// }
/**
* 排序任务
*/
// sortTasks(
// compareFn: (a: Task, b: Task) => number,
// parentId?: string
// ): Task[] {
// let tasksToSort: Task[];
// if (parentId) {
// const parent = this.getTaskById(parentId);
// if (!parent || !parent.children) {
// return [];
// }
// tasksToSort = parent.children;
// } else {
// tasksToSort = this.tasks;
// }
// tasksToSort.sort(compareFn);
// this.invalidateCache(); // 排序后,缓存失效
// // this.emit("tasks:sorted", { parentId, tasks: tasksToSort });
// return tasksToSort;
// }
/**
* 获取扁平化的任务列表,包括已展开的子任务
* 使用缓存提高性能,只有在必要时才会重建列表
*/
getVisibleTasks() {
if (!this.isDirty && this.visibleTasksCache.length > 0)
return this.visibleTasksCache;
const t = [];
let e = 0;
const i = (s, n) => {
this.collapsedTaskIds.has(s.id) && s.expanded && (s.expanded = !1), s.flatIndex = e++, t.push(s), s.expanded && s.children && s.children.length > 0 && s.children.forEach((o) => i(o));
};
return this.tasks.forEach((s) => i(s)), this.visibleTasksCache = t, this.isDirty = !1, t;
}
/**
* 获取可展示任务数量
*/
getVisibleSize() {
return this.getVisibleTasks().length;
}
/** 检查任务是否可见 */
isTaskVisible(t) {
return this.getVisibleTasks().some((e) => e.id === t.id);
}
/**
* 清空所有数据
*/
clear() {
this.rawData = [], this.tasks = [], this.taskMap.clear(), this.visibleTasksCache = [], this.isDirty = !0, this.collapsedTaskIds.clear(), this.event.emit(y.DATA_UPDATE);
}
/**
* 更新子任务的层级
*/
// private updateChildrenLevel(task: Task): void {
// if (!task.children || task.children.length === 0) {
// return;
// }
// const parentLevel = task.level !== undefined ? task.level : 0;
// task.children.forEach(child => {
// child.level = parentLevel + 1;
// this.updateChildrenLevel(child);
// });
// }
/**
* 使缓存失效,标记需要重新生成扁平化任务列表
*/
invalidateCache() {
this.isDirty = !0;
}
/**
* 选择任务
* @param taskId 任务ID
* @returns 是否选择成功
*/
selectTask(t) {
const e = this.getTaskById(t);
return e ? (this.selectedTaskId === t || (this.unselectTask(), this.selectedTaskId = t, this.event.emit(y.TASK_SELECTED, e)), !0) : !1;
}
/**
* 取消任务选择
*/
unselectTask() {
if (this.selectedTaskId) {
const t = this.selectedTaskId;
this.selectedTaskId = null, this.event.emit(y.TASK_UNSELECTED, t);
}
}
/**
* 检查任务是否被选中
* @param taskId 任务ID
* @returns 是否被选中
*/
isTaskSelected(t) {
return this.selectedTaskId === t;
}
/**
* 获取当前选中的任务
* @returns 选中的任务,如果没有则返回undefined
*/
getSelectedTask() {
return this.selectedTaskId ? this.getTaskById(this.selectedTaskId) : void 0;
}
getCheckedList() {
return this.checkedList;
}
updateCheckedList(t, e) {
const i = this.checkedList.findIndex((s) => s.id === e.id);
t ? i === -1 ? this.checkedList.push(e) : this.checkedList.splice(i, 1, e) : i !== -1 && this.checkedList.splice(i, 1);
}
toggleAllChecked(t) {
t ? this.checkedList = this.getVisibleTasks().slice() : this.checkedList = [];
}
isTaskChecked(t) {
return this.checkedList.findIndex((e) => e.id === t.id) !== -1;
}
updateTaskTime(t, e, i, s, n = []) {
let o = e, r = i;
const l = this.store.getOptionManager().getOptions().bar.move.link.child, c = this.store.getOptionManager().getOptions().bar.move.link.parent, g = this.store.getTimeAxis().getCellUnit();
let h = t.parent;
for (; c !== "none" && h; ) {
if (c === "expand") {
let m = h.startTime || o, p = h.endTime || r;
(!h.startTime || o.isBefore(h.startTime)) && (m = o), (!h.endTime || r.isAfter(h.endTime)) && (p = r), (h.startTime === void 0 || h.endTime === void 0 || !m.isSame(h.startTime) || !p.isSame(h.endTime)) && (n.findIndex((u) => u.id === h.id) === -1 && n.push(h.clone()), h.updateTime(m, p));
} else c === "strict" && (h.startTime && o.isBefore(h.startTime) && (o = h.startTime, r.isSameOrBefore(o) && (r = o.add(1, g))), h.endTime && r.isAfter(h.endTime) && (r = h.endTime, o.isAfter(r) && (o = r.subtract(1, g))));
h = h.parent;
}
let d = t.children || [];
for (; l !== "none" && d.length > 0; ) {
const m = [];
d.forEach((p) => {
let u = p.startTime || o, x = p.endTime || r, w = o.diff(t.startTime), E = r.diff(t.endTime);
l === "scale" ? s === "both" ? (n.findIndex((T) => T.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u.add(w), x.add(E))) : s === "left" ? (u = u.add(w), u.isSameOrAfter(x.subtract(1, g)) && (x.isBefore(t.endTime) ? x = u.add(1, g) : u = x.subtract(1, g), u.isSameOrBefore(o) && (o = u)), n.findIndex((T) => T.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u, x)) : s === "right" && (x = x.add(E), x.isSameOrBefore(u.add(1, g)) && (u.isAfter(t.startTime) ? u = x.subtract(1, g) : x = u.add(1, g)), x.isSameOrAfter(r) && (r = x), n.findIndex((T) => T.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u, x)) : l === "fixed" && (s === "both" ? (n.findIndex((T) => T.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u.add(w), x.add(E))) : s === "left" ? u.isSameOrBefore(o) && (u = o, u.isSameOrAfter(x.subtract(1, g)) && (x.isBefore(t.endTime) ? x = u.add(1, g) : u = x.subtract(1, g), u.isSameOrBefore(o) && (o = u)), n.findIndex((T) => T.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u, x)) : s === "right" && x.isSameOrAfter(r) && (x = r, x.isSameOrBefore(u.add(1, g)) && (u.isAfter(t.startTime) ? u = x.subtract(1, g) : x = u.add(1, g)), x.isSameOrAfter(r) && (r = x), n.findIndex((T) => T.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u, x))), p.children && p.children.length > 0 && m.push(...p.children);
}), d = m;
}
n.findIndex((m) => m.id === t.id) === -1 && n.push(t.clone()), t.updateTime(o, r);
}
//** 基线数据操作 */
setBaselines(t) {
this.baselines = [], this.baselineMap.clear(), this.baselineTaskMap.clear(), t.forEach((e) => {
var s, n;
const i = new Vt(this.store, this.event, e);
this.baselines.push(i), this.baselineMap.set(i.id, i), this.baselineTaskMap.has(i.taskId) || this.baselineTaskMap.set(i.taskId, []), i.target ? (s = this.baselineTaskMap.get(i.taskId)) == null || s.unshift(i) : (n = this.baselineTaskMap.get(i.taskId)) == null || n.push(i);
});
}
getBaselines() {
return this.baselines;
}
/** 根据ID获取基线 */
getBaselineById(t) {
return this.baselineMap.get(t);
}
/** 根据任务ID获取基线 */
getBaselinesByTaskId(t) {
return this.baselineTaskMap.get(t) || [];
}
}
function G(f, t, e) {
if (!Number.isFinite(f) || !Number.isFinite(t) || !Number.isFinite(e))
return Number.isFinite(t) ? t : 0;
const i = Math.min(t, e), s = Math.max(t, e);
return Math.min(Math.max(i, f), s);
}
function st(f, t) {
let e = f;
return U(e) && (/%$/.test(e) ? e = t * parseFloat(e) / 100 : e = parseFloat(e)), isNaN(e) ? 0 : e;
}
function pt(f, t) {
if (t === 0)
throw new Error("基准值不能为0");
if (Math.abs(f) <= t / 2)
return 0;
const e = Math.floor(f / t), i = Math.ceil(f / t), s = e * t, n = i * t, o = Math.abs(f - s), r = Math.abs(f - n);
return o <= r ? s : n;
}
function nt(f, t = 4) {
return typeof f == "number" ? [f, f, f, f] : Array.isArray(f) ? [
f[0] ?? t,
f[1] ?? t,
f[2] ?? t,
f[3] ?? t
] : [t, t, t, t];
}
function jt(f, t = 100) {
if (!Number.isFinite(f) || !Number.isFinite(t) || t === 0 || f < 0)
return 0;
const e = f / Math.abs(t);
return Math.min(e, 1);
}
function lt(f, t = 2, e = !1) {
const i = f.toFixed(t);
return e ? i : i.replace(/\.?0+$/, "");
}
function xt(f, t = 16, e = 16) {
return new Promise((i, s) => {
let n = f;
if (!/viewBox\s*=\s*["'][^"']*["']/.test(n)) {
const g = n.match(/width\s*=\s*["']([^"']*)["']/), h = n.match(/height\s*=\s*["']([^"']*)["']/), d = g ? parseFloat(g[1]) : t, m = h ? parseFloat(h[1]) : e;
n = n.replace(
/<svg([^>]*)>/,
`<svg$1 viewBox="0 0 ${d} ${m}">`
);
}
n = n.replace(/width\s*=\s*["'][^"']*["']/, `width="${t}"`), n = n.replace(/height\s*=\s*["'][^"']*["']/, `height="${e}"`), /width\s*=/.test(n) || (n = n.replace(/<svg/, `<svg width="${t}"`)), /height\s*=/.test(n) || (n = n.replace(/<svg/, `<svg height="${e}"`)), /preserveAspectRatio\s*=/.test(n) || (n = n.replace(
/<svg([^>]*)>/,
'<svg$1 preserveAspectRatio="xMidYMid meet">'
));
const r = new Image();
r.onload = () => {
URL.revokeObjectURL(r.src), i(r);
}, r.onerror = (g) => {
URL.revokeObjectURL(r.src), s(g);
};
const l = new Blob([n], { type: "image/svg+xml" }), c = URL.createObjectURL(l);
r.src = c;
});
}
function qt(f) {
var s;
if (typeof f == "object" && f !== null)
return {
r: G(f.r ?? 0, 0, 255),
g: G(f.g ?? 0, 0, 255),
b: G(f.b ?? 0, 0, 255),
a: G(f.a ?? 1, 0, 1)
};
if (typeof f != "string")
return L.warn(`Invalid color value type: ${typeof f}`), null;
let t = f.trim();
const e = (s = document == null ? void 0 : document.createElement("canvas")) == null ? void 0 : s.getContext("2d");
if (e && (e.fillStyle = t, t = e.fillStyle), t.startsWith("#")) {
const n = t.slice(1);
let o, r, l, c, g = 1;
try {
o = parseInt(n, 16);
} catch {
return L.warn(`Invalid hex color: ${f}`), null;
}
if (n.length === 3)
r = (o >> 8 & 15) * 17, l = (o >> 4 & 15) * 17, c = (o & 15) * 17;
else if (n.length === 6)
r = o >> 16 & 255, l = o >> 8 & 255, c = o & 255;
else if (n.length === 8)
r = o >> 24 & 255, l = o >> 16 & 255, c = o >> 8 & 255, g = (o & 255) / 255;
else
return L.warn(`Invalid hex color length: ${f}`), null;
return { r, g: l, b: c, a: g };
}
let i = t.match(
/rgba?\(\s*(\d+%?)\s*,\s*(\d+%?)\s*,\s*(\d+%?)\s*(?:,\s*([\d.]+)\s*)?\)/i
);
if (i) {
const n = (o) => o.endsWith("%") ? G(parseFloat(o) / 100 * 255, 0, 255) : G(parseInt(o, 10), 0, 255);
return {
r: n(i[1]),
g: n(i[2]),
b: n(i[3]),
a: i[4] !== void 0 ? G(parseFloat(i[4]), 0, 1) : 1
};
}
return L.warn(`Could not parse color: ${f}`), null;
}
function Qt(f, t, e, i, s = !1, n = !1) {
const o = (d) => {
const m = Math.round(G(d, 0, 255)).toString(16);
return m.length === 1 ? "0" + m : m;
}, r = o(f), l = o(t), c = o(e), g = o(i * 255);
if (s && r[0] === r[1] && l[0] === l[1] && c[0] === c[1] && i === 1 && // Alpha 必须为 1 才能缩写
!n)
return `#${r[0]}${l[0]}${c[0]}`;
const h = `#${r}${l}${c}`;
return n || i < 1 ? `${h}${g}` : h;
}
class tt {
/**
* 创建一个新的 Colorjs 实例。
* 推荐使用 colorjs(value) 工厂函数来创建。
* @param value - 颜色值 (字符串, 如 '#rgb', '#rrggbb', 'rgb()', 'rgba()', 颜色名; 或对象 {r, g, b, a})
* @throws {Error} 如果颜色值无法解析
*/
constructor(t) {
// 使用 private 属性,强制通过方法访问和修改
a(this, "_r");
a(this, "_g");
a(this, "_b");
a(this, "_a");
const e = qt(t);
e === null ? (L.error(`Failed to parse color: ${t}. Using default black.`), this._r = 0, this._g = 0, this._b = 0, this._a = 1) : (this._r = Math.round(e.r), this._g = Math.round(e.g), this._b = Math.round(e.b), this._a = e.a);
}
// --- Getters ---
/** 获取 Red 通道值 (0-255) */
get R() {
return this._r;
}
/** 获取 Green 通道值 (0-255) */
get G() {
return this._g;
}
/** 获取 Blue 通道值 (0-255) */
get B() {
return this._b;
}
/** 获取 Alpha 通道值 (0-1) */
get A() {
return this._a;
}
red(t) {
return t === void 0 ? this._r : (this._r = Math.round(G(t, 0, 255)), this);
}
green(t) {
return t === void 0 ? this._g : (this._g = Math.round(G(t, 0, 255)), this);
}
blue(t) {
return t === void 0 ? this._b : (this._b = Math.round(G(t, 0, 255)), this);
}
alpha(t) {
return t === void 0 ? this._a : (this._a = G(t, 0, 1), this);
}
// --- 输出方法 ---
/**
* 输出为 Hex (#RRGGBB) 或 HexA (#RRGGBBAA) 格式字符串。
* @param allow3Char - 是否允许输出 #RGB 简写格式 (如果可能, 默认 false)。
* @param forceAlpha - 是否强制输出 Alpha 通道 (即使 a=1, 默认 false)。
* @returns Hex/HexA 字符串。
*/
toHex(t = !1, e = !1) {
return Qt(
this._r,
this._g,
this._b,
this._a,
t,
e
);
}
/**
* 输出为 rgb() 或 rgba() 格式字符串。
* @returns 'rgb(r, g, b)' 或 'rgba(r, g, b, a)' 格式字符串。
*/
toRgb() {
const t = Math.round(this._r), e = Math.round(this._g), i = Math.round(this._b);
if (this._a === 1)
return `rgb(${t}, ${e}, ${i})`;
{
const s = parseFloat(this._a.toFixed(2));
return `rgba(${t}, ${e}, ${i}, ${s})`;
}
}
/**
* 输出为包含 r, g, b, a 的对象。
* @returns RGBA 对象 { r, g, b, a }。
*/
toObject() {
return { r: this._r, g: this._g, b: this._b, a: this._a };
}
/**
* 默认字符串表示形式,输出为 rgba 格式。
* @returns rgba 格式字符串。
*/
toString() {
return this.toRgb();
}
// --- 操作方法 (返回 this 以支持链式调用) ---
/**
* 增加颜色亮度。
* @param amount - 增加的百分比 (0-100),默认为 10。
* @returns 当前 Colorjs 实例。
*/
brighten(t = 10) {
if (t < 0) return this.darken(-t);
const e = G(t, 0, 100) / 100;
return this._r = Math.round(G(this._r + (255 - this._r) * e, 0, 255)), this._g = Math.round(G(this._g + (255 - this._g) * e, 0, 255)), this._b = Math.round(G(this._b + (255 - this._b) * e, 0, 255)), this;
}
/**
* 降低颜色亮度 (变暗)。
* @param amount - 降低的百分比 (0-100),默认为 10。
* @returns 当前 Colorjs 实例。
*/
darken(t = 10) {
if (t < 0) return this.brighten(-t);
const e = G(t, 0, 100) / 100;
return this._r = Math.round(G(this._r * (1 - e), 0, 255)), this._g = Math.round(G(this._g * (1 - e), 0, 255)), this._b = Math.round(G(this._b * (1 - e), 0, 255)), this;
}
/**
* 判断颜色是否偏亮。
* 使用标准的亮度计算公式。
* @returns 如果颜色偏亮则返回 true,否则返回 false。
*/
isLight() {
return (this._r * 299 + this._g * 587 + this._b * 114) / 1e3 > 128;
}
/**
* 判断颜色是否偏暗。
* @returns 如果颜色偏暗则返回 true,否则返回 false。
*/
isDark() {
return !this.isLight();
}
/**
* 混合当前颜色与指定颜色。
* @param colorToMix - 要混合的颜色 (Colorjs 实例或可被 colorjs() 解析的颜色值)。
* @param amount - 混合的比例 (0-100),表示 `colorToMix` 所占的权重,默认为 50 (各占一半)。
* @returns 当前 Colorjs 实例。
*/
mix(t, e = 50) {
const i = G(e, 0, 100) / 100, s = F(t);
return this._r = Math.round(
G(this._r * (1 - i) + s.R * i, 0, 255)
), this._g = Math.round(
G(this._g * (1 - i) + s.G * i, 0, 255)
), this._b = Math.round(
G(this._b * (1 - i) + s.B * i, 0, 255)
), this._a = G(this._a * (1 - i) + s.A * i, 0, 1), this;
}
/**
* 创建当前颜色对象的副本。
* @returns 一个新的 Colorjs 实例,具有相同的颜色值。
*/
clone() {
return new tt({
r: this._r,
g: this._g,
b: this._b,
a: this._a
});
}
// --- 静态方法 ---
/**
* 扩展 Colorjs 功能的插件机制。
* @param plugin - 插件函数。
* @param option - 传递给插件的选项 (可选)。
*/
static extend(t, e) {
typeof t == "function" ? t(e, tt, F) : L.warn(
"Invalid plugin provided to Colorjs.extend. Expected a function."
);
}
}
const F = (f) => f instanceof tt ? f : new tt(f);
class Et {
constructor(t, e, i) {
a(this, "element");
a(this, "iconElement");
a(this, "_state", 0);
a(this, "options");
var o;
this.context = t, this.container = e, this.task = i;
const n = (this.task ? this.context.store.getDataManager().isTaskChecked(this.task) : !1) ? 1 : 0;
this.options = {
initialState: n,
size: 14
}, this.element = document.createElement("div"), this.iconElement = document.createElement("div"), this._state = this.options.initialState, this.createElement(), this.updateIcon(), this.bindEvents(), this.registerEvents(), (o = this.container) == null || o.appendChild(this.element);
}
createElement() {
this.element.className = "x-gantt-checkbox", this.element.style.width = `${this.options.size}px`, this.element.style.height = `${this.options.size}px`, this.element.style.setProperty(
"border",
`1px solid ${this.context.store.getOptionManager().getOptions().border.color}`,
"important"
), this.iconElement.className = "x-gantt-checkbox__icon", this.iconElement.style.cssText = `
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
color: #ffffff;
font-size: ${Math.floor(this.options.size * 0.75)}px;
line-height: 1;
`, this.element.appendChild(this.iconElement), this.element.addEventListener("mouseenter", () => {
this._state === 0 && this.element.classList.add("hover");
}), this.element.addEventListener("mouseleave", () => {
this._state === 0 && this.element.classList.remove("hover");
});
}
updateIcon() {
const t = this.context.store.getOptionManager().getOptions().primaryColor;
this.iconElement.innerHTML = "";
let e = "#ffffff", i = F(t).alpha(0.5).toHex();
switch (this._state) {
case 0:
e = "#ffffff", i = i;
break;
case 1:
e = t, i = t, this.iconElement.innerHTML = `
<svg width="12" height="9" viewBox="0 0 12 9" fill="none">
<path d="M10.5 1.5L4.5 7.5L1.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
`;
break;
case 2:
e = t, i = t, this.iconElement.innerHTML = `
<svg width="8" height="2" viewBox="0 0 8 2" fill="none">
<rect width="8" height="2" fill="currentColor" rx="1"/>
</svg>
`;
break;
}
this.iconElement.style.setProperty(
"background-color",
e,
"important"
), this.iconElement.style.setProperty(
"border-color",
i,
"important"
);
}
bindEvents() {
this.element.addEventListener("click", (t) => {
if (t.preventDefault(), t.stopPropagation(), this.task) {
const e = this.context.store.getDataManager().isTaskChecked(this.task);
e ? (this.context.store.getDataManager().updateCheckedList(!1, this.task), this.setState(
0
/* UNCHECKED */
)) : (this.context.store.getDataManager().updateCheckedList(!0, this.task), this.setState(
1
/* CHECKED */
)), this.context.event.emit(y.CHECK_TASK, [this.task], !e);
} else {
const e = this.context.store.getDataManager().getCheckedList().length === this.context.store.getDataManager().getVisibleSize();
this.setState(
e ? 1 : 0
/* UNCHECKED */
), this.context.store.getDataManager().toggleAllChecked(!e), this.context.event.emit(
y.CHECK_TASK,
this.context.store.getDataManager().getVisibleTasks(),
!e
);
}
}), this.element.addEventListener("contextmenu", (t) => {
if (t.preventDefault(), t.stopPropagation(), this.task) {
const e = this.task.getAllChildren();
if (e.length === 0) return;
this.context.store.getOptionManager().getOptions().selection.includeSelf && e.unshift(this.task);
const i = e.every(
(s) => this.context.store.getDataManager().isTaskChecked(s)
);
i ? (e.forEach((s) => {
this.context.store.getDataManager().updateCheckedList(!1, s);
}), this.setState(
0
/* UNCHECKED */
)) : (e.forEach((s) => {
this.context.store.getDataManager().updateCheckedList(!0, s);
}), this.setState(
1
/* CHECKED */
)), this.context.event.emit(y.CHECK_TASK, e, !i);
} else {
const e = this.context.store.getDataManager().getCheckedList().length === this.context.store.getDataManager().getVisibleSize();
this.setState(
e ? 1 : 0
/* UNCHECKED */
), this.context.store.getDataManager().toggleAllChecked(!e), this.context.event.emit(
y.CHECK_TASK,
this.context.store.getDataManager().getVisibleTasks(),
!e
);
}
});
}
registerEvents() {
this.context.event.on(y.CHECK_TASK, this.updateState.bind(this));
}
/** 获取元素 */
getElement() {
return this.element;
}
/**
* 设置状态
*/
setState(t) {
this._state !== t && (this._state = t, this.updateIcon());
}
/**
* 更新状态
*/
updateState() {
if (this.task) {
const t = this.context.store.getDataManager().isTaskChecked(this.task);
this.setState(
t ? 1 : 0
/* UNCHECKED */
);
} else {
const t = this.context.store.getDataManager().getCheckedList().length === this.context.store.getDataManager().getVisibleSize();
this.setState(
t ? 1 : 0
/* UNCHECKED */
);
}
}
/**
* 销毁组件
*/
destroy() {
this.element && this.element.parentNode && this.element.parentNode.removeChild(this.element);
}
}
const yt = "handler_column";
class Jt {
constructor(t) {
/** 源列数据 */
a(this, "sourceColumns", []);
/** 处理后的所有列数据 */
a(this, "columns", []);
/** 叶子列数据,只包含最终显示的列 */
a(this, "leafColumns", []);
/** 临时叶子列数据,用于更新源数据,读取宽度等原信息 */
a(this, "temporaryLeafColumns", []);
/**
* 保存所有行列合并的信息
*
* Map<task_id, Map<col_index, object>>
*/
a(this, "mergeInfo", /* @__PURE__ */ new Map());
/**
* 收起表格
*/
a(this, "collapseTable", !1);
this.context = t;
}
/**
* 初始化列数据
*/
init(t) {
t != null && t.length && (this.sourceColumns = t), this.columns = [], this.leafColumns = [], this.processColumns(this.sourceColumns, this.columns);
}
/**
* 处理列数据,将源数据转换为内部数据结构
*/
processColumns(t, e = [], i, s = 1) {
t.forEach((n, o) => {
var p;
const r = "children" in n && Array.isArray(n.children) && n.children.length > 0, l = !r;
let c = "";
r ? c = `group-${o}` : c = `field-${n.field}`;
const g = [...(i == null ? void 0 : i.path) || [], c];
c = "column-" + o + "-" + g.join("-");
const h = n.label || (l ? n.field : ""), d = l ? ((p = this.temporaryLeafColumns.find((u) => u.key === c)) == null ? void 0 : p.width) || n.width || 100 : "auto", m = {
label: h,
level: s,
maxLevel: s,
column: n,
children: [],
path: g,
key: c,
isLeaf: l,
width: d
};
if (e.push(m), l)
this.leafColumns.push(m);
else if (r) {
const u = n.children;
this.processColumns(
u,
m.children,
m,
s + 1
), m.maxLevel = Math.max(
m.maxLevel,
m.children.reduce((x, w) => Math.max(x, w.maxLevel), 0)
);
}
}), this.temporaryLeafColumns = J(this.leafColumns);
}
/**
* 根据 key 查找列
*/
findColumnByKey(t) {
return this.columns.find((e) => e.key === t);
}
update(t) {
this.init(t), this.clearMergeInfo();
}
getColumns() {
return this.columns;
}
getColumn(t) {
return this.leafColumns.find((e) => e.key === t);
}
getLeafColumns() {
return this.leafColumns;
}
getTotalWidth() {
return this.isCollapsed() ? 0 : this.leafColumns.reduce((t, e) => t + e.width, this.getHandlerColumn().width);
}
getColumnWidth(t) {
if (t === yt) return this.getHandlerColumn().width;
const e = this.leafColumns.find((i) => i.key === t);
return typeof (e == null ? void 0 : e.width) == "number" ? e.width : 0;
}
setColumnWidth(t, e) {
const i = this.leafColumns.find((s) => s.key === t);
i && (i.width = e), this.context.event.emit(y.COLUMN_WIDTH_CHANGE, t, e);
}
isLastColumn(t) {
return this.leafColumns.findIndex((i) => i.key === t) === this.leafColumns.length - 1;
}
addMergeInfo(t, e, i) {
this.mergeInfo.has(t) || this.mergeInfo.set(t, /* @__PURE__ */ new Map()), this.mergeInfo.get(t).set(e, i);
}
getMergeInfo(t, e) {
var i;
return (i = this.mergeInfo.get(t)) == null ? void 0 : i.get(e);
}
clearMergeInfo() {
this.mergeInfo.clear();
}
getHandlerColumn() {
let t = 0;
return this.context.store.getOptionManager().getOptions().selection.enabled && (t += 40), this.context.store.getDataManager().dataLevel > 0 && this.context.store.getOptionManager().getOptions().expand.show && (t += 40), {
label: "",
level: 1,
maxLevel: 1,
column: {
field: "",
resizable: !1,
align: "left",
headerAlign: "left",
customStyle: {
paddingLeft: this.context.store.getOptionManager().getOptions().expand.show ? "8px" : 0
},
headerRender: () => this.context.store.getOptionManager().getOptions().selection.enabled ? new Et(this.context).getElement() : null,
ellipsis: !1
},
children: [],
path: [],
key: yt,
isLeaf: !0,
width: t
};
}
isMultiHeader() {
return this.columns.some((t) => t.maxLevel > 1);
}
collapse() {
this.collapseTable = !this.collapseTable, this.context.event.emit(y.TOGGLE_COLLAPSE);
}
isCollapsed() {
return this.collapseTable;
}
}
var Y = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {};
function N(f) {
return f && f.__esModule && Object.prototype.hasOwnProperty.call(f, "default") ? f.default : f;
}
var kt = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
var e, i, s = 1e3, n = 6e4, o = 36e5, r = 864e5, l = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, c = 31536e6, g = 2628e6, h = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/, d = { years: c, months: g, days: r, hours: o, minutes: n, seconds: s, milliseconds: 1, weeks: 6048e5 }, m = function(k) {
return k instanceof O;
}, p = function(k, S, b) {
return new O(k, b, S.$l);
}, u = function(k) {
return i.p(k) + "s";
}, x = function(k) {
return k < 0;
}, w = function(k) {
return x(k) ? Math.ceil(k) : Math.floor(k);
}, E = function(k) {
return Math.abs(k);
}, T = function(k, S) {
return k ? x(k) ? { negative: !0, format: "" + E(k) + S } : { negative: !1, format: "" + k + S } : { negative: !1, format: "" };
}, O = function() {
function k(b, D, I) {
var _ = this;
if (this.$d = {}, this.$l = I, b === void 0 && (this.$ms = 0, this.parseFromMilliseconds()), D) return p(b * d[u(D)], this);
if (typeof b == "number") return this.$ms = b, this.parseFromMilliseconds(), this;
if (typeof b == "object") return Object.keys(b).forEach(function(B) {
_.$d[u(B)] = b[B];
}), this.calMilliseconds(), this;
if (typeof b == "string") {
var M = b.match(h);
if (M) {
var A = M.slice(2).map(function(B) {
return B != null ? Number(B) : 0;
});
return this.$d.years = A[0], this.$d.months = A[1], this.$d.weeks = A[2], this.$d.days = A[3], this.$d.hours = A[4], this.$d.minutes = A[5], this.$d.seconds = A[6], this.calMilliseconds(), this;
}
}
return this;
}
var S = k.prototype;
return S.calMilliseconds = function() {
var b = this;
this.$ms = Object.keys(this.$d).reduce(function(D, I) {
return D + (b.$d[I] || 0) * d[I];
}, 0);
}, S.parseFromMilliseconds = function() {
var b = this.$ms;
this.$d.years = w(b / c), b %= c, this.$d.months = w(b / g), b %= g, this.$d.days = w(b / r), b %= r, this.$d.hours = w(b / o), b %= o, this.$d.minutes = w(b / n), b %= n, this.$d.seconds = w(b / s), b %= s, this.$d.milliseconds = b;
}, S.toISOString = function() {
var b = T(this.$d.years, "Y"), D = T(this.$d.months, "M"), I = +this.$d.days || 0;
this.$d.weeks && (I += 7 * this.$d.weeks);
var _ = T(I, "D"), M = T(this.$d.hours, "H"), A = T(this.$d.minutes, "M"), B = this.$d.seconds || 0;
this.$d.milliseconds && (B += this.$d.milliseconds / 1e3, B = Math.round(1e3 * B) / 1e3);
var $ = T(B, "S"), R = b.negative || D.negative || _.negative || M.negative || A.negative || $.negative, W = M.format || A.format || $.format ? "T" : "", P = (R ? "-" : "") + "P" + b.format + D.format + _.format + W + M.format + A.format + $.format;
return P === "P" || P === "-P" ? "P0D" : P;
}, S.toJSON = function() {
return this.toISOString();
}, S.format = function(b) {
var D = b || "YYYY-MM-DDTHH:mm:ss", I = { Y: this.$d.years, YY: i.s(this.$d.years, 2, "0"), YYYY: i.s(this.$d.years, 4, "0"), M: this.$d.months, MM: i.s(this.$d.months, 2, "0"), D: this.$d.days, DD: i.s(this.$d.days, 2, "0"), H: this.$d.hours, HH: i.s(this.$d.hours, 2, "0"), m: this.$d.minutes, mm: i.s(this.$d.minutes, 2, "0"), s: this.$d.seconds, ss: i.s(this.$d.seconds, 2, "0"), SSS: i.s(this.$d.milliseconds, 3, "0") };
return D.replace(l, function(_, M) {
return M || String(I[_]);
});
}, S.as = function(b) {
return this.$ms / d[u(b)];
}, S.get = function(b) {
var D = this.$ms, I = u(b);
return I === "milliseconds" ? D %= 1e3 : D = I === "weeks" ? w(D / d[I]) : this.$d[I], D || 0;
}, S.add = function(b, D, I) {
var _;
return _ = D ? b * d[u(D)] : m(b) ? b.$ms : p(b, this).$ms, p(this.$ms + _ * (I ? -1 : 1), this);
}, S.subtract = function(b, D) {
return this.add(b, D, !0);
}, S.locale = function(b) {
var D = this.clone();
return D.$l = b, D;
}, S.clone = function() {
return p(this.$ms, this);
}, S.humanize = function(b) {
return e().add(this.$ms, "ms").locale(this.$l).fromNow(!b);
}, S.valueOf = function() {
return this.asMilliseconds();
}, S.milliseconds = function() {
return this.get("milliseconds");
}, S.asMilliseconds = function() {
return this.as("milliseconds");
}, S.seconds = function() {
return this.get("seconds");
}, S.asSeconds = function() {
return this.as("seconds");
}, S.minutes = function() {
return this.get("minutes");
}, S.asMinutes = function() {
return this.as("minutes");
}, S.hours = function() {
return this.get("hours");
}, S.asHours = function() {
return this.as("hours");
}, S.days = function() {
return this.get("days");
}, S.asDays = function() {
return this.as("days");
}, S.weeks = function() {
return this.get("weeks");
}, S.asWeeks = function() {
return this.as("weeks");
}, S.months = function() {
return this.get("months");
}, S.asMonths = function() {
return this.as("months");
}, S.years = function() {
return this.get("years");
}, S.asYears = function() {
return this.as("years");
}, k;
}(), C = function(k, S, b) {
return k.add(S.years() * b, "y").add(S.months() * b, "M").add(S.days() * b, "d").add(S.hours() * b, "h").add(S.minutes() * b, "m").add(S.seconds() * b, "s").add(S.milliseconds() * b, "ms");
};
return function(k, S, b) {
e = b, i = b().$utils(), b.duration = function(_, M) {
var A = b.locale();
return p(_, { $l: A }, M);
}, b.isDuration = m;
var D = S.prototype.add, I = S.prototype.subtract;
S.prototype.add = function(_, M) {
return m(_) ? C(this, _, 1) : D.bind(this)(_, M);
}, S.prototype.subtract = function(_, M) {
return m(_) ? C(this, _, -1) : I.bind(this)(_, M);
};
};
});
})(kt);
var Zt = kt.exports;
const te = /* @__PURE__ */ N(Zt);
var Ot = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
return function(e, i, s) {
i.prototype.isBetween = function(n, o, r, l) {
var c = s(n), g = s(o), h = (l = l || "()")[0] === "(", d = l[1] === ")";
return (h ? this.isAfter(c, r) : !this.isBefore(c, r)) && (d ? this.isBefore(g, r) : !this.isAfter(g, r)) || (h ? this.isBefore(c, r) : !this.isAfter(c, r)) && (d ? this.isAfter(g, r) : !this.isBefore(g, r));
};
};
});
})(Ot);
var ee = Ot.exports;
const ie = /* @__PURE__ */ N(ee);
var Mt = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
return function(e, i) {
i.prototype.isSameOrBefore = function(s, n) {
return this.isSame(s, n) || this.isBefore(s, n);
};
};
});
})(Mt);
var se = Mt.exports;
const ne = /* @__PURE__ */ N(se);
var Lt = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
return function(e, i) {
i.prototype.isSameOrAfter = function(s, n) {
return this.isSame(s, n) || this.isAfter(s, n);
};
};
});
})(Lt);
var oe = Lt.exports;
const re = /* @__PURE__ */ N(oe);
var Ct = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
return function(e, i, s) {
var n = i.prototype, o = function(h) {
return h && (h.indexOf ? h : h.s);
}, r = function(h, d, m, p, u) {
var x = h.name ? h : h.$locale(), w = o(x[d]), E = o(x[m]), T = w || E.map(function(C) {
return C.slice(0, p);
});
if (!u) return T;
var O = x.weekStart;
return T.map(function(C, k) {
return T[(k + (O || 0)) % 7];
});
}, l = function() {
return s.Ls[s.locale()];
}, c = function(h, d) {
return h.formats[d] || function(m) {
return m.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, function(p, u, x) {
return u || x.slice(1);
});
}(h.formats[d.toUpperCase()]);
}, g = function() {
var h = this;
return { months: function(d) {
return d ? d.format("MMMM") : r(h, "months");
}, monthsShort: function(d) {
return d ? d.format("MMM") : r(h, "monthsShort", "months", 3);
}, firstDayOfWeek: function() {
return h.$locale().weekStart || 0;
}, weekdays: function(d) {
return d ? d.format("dddd") : r(h, "weekdays");
}, weekdaysMin: function(d) {
return d ? d.format("dd") : r(h, "weekdaysMin", "weekdays", 2);
}, weekdaysShort: function(d) {
return d ? d.format("ddd") : r(h, "weekdaysShort", "weekdays", 3);
}, longDateFormat: function(d) {
return c(h.$locale(), d);
}, meridiem: this.$locale().meridiem, ordinal: this.$locale().ordinal };
};
n.localeData = function() {
return g.bind(this)();
}, s.localeData = function() {
var h = l();
return { firstDayOfWeek: function() {
return h.weekStart || 0;
}, weekdays: function() {
return s.weekdays();
}, weekdaysShort: function() {
return s.weekdaysShort();
}, weekdaysMin: function() {
return s.weekdaysMin();
}, months: function() {
return s.months();
}, monthsShort: function() {
return s.monthsShort();
}, longDateFormat: function(d) {
return c(h, d);
}, meridiem: h.meridiem, ordinal: h.ordinal };
}, s.months = function() {
return r(l(), "months");
}, s.monthsShort = function() {
return r(l(), "monthsShort", "months", 3);
}, s.weekdays = function(h) {
return r(l(), "weekdays", null, null, h);
}, s.weekdaysShort = function(h) {
return r(l(), "weekdaysShort", "weekdays", 3, h);
}, s.weekdaysMin = function(h) {
return r(l(), "weekdaysMin", "weekdays", 2, h);
};
};
});
})(Ct);
var ae = Ct.exports;
const he = /* @__PURE__ */ N(ae);
var Dt = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
var e = "week", i = "year";
return function(s, n, o) {
var r = n.prototype;
r.week = function(l) {
if (l === void 0 && (l = null), l !== null) return this.add(7 * (l - this.week()), "day");
var c = this.$locale().yearStart || 1;
if (this.month() === 11 && this.date() > 25) {
var g = o(this).startOf(i).add(1, i).date(c), h = o(this).endOf(e);
if (g.isBefore(h)) return 1;
}
var d = o(this).startOf(i).date(c).startOf(e).subtract(1, "millisecond"), m = this.diff(d, e, !0);
return m < 0 ? o(this).startOf("week").week() : Math.ceil(m);
}, r.weeks = function(l) {
return l === void 0 && (l = null), this.week(l);
};
};
});
})(Dt);
var le = Dt.exports;
const ce = /* @__PURE__ */ N(le);
var _t = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
return function(e, i) {
i.prototype.weekYear = function() {
var s = this.month(), n = this.week(), o = this.year();
return n === 1 && s === 11 ? o + 1 : s === 0 && n >= 52 ? o - 1 : o;
};
};
});
})(_t);
var de = _t.exports;
const ue = /* @__PURE__ */ N(de);
var Ht = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
return function(e, i) {
var s = i.prototype, n = s.format;
s.format = function(o) {
var r = this, l = this.$locale();
if (!this.isValid()) return n.bind(this)(o);
var c = this.$utils(), g = (o || "YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g, function(h) {
switch (h) {
case "Q":
return Math.ceil((r.$M + 1) / 3);
case "Do":
return l.ordinal(r.$D);
case "gggg":
return r.weekYear();
case "GGGG":
return r.isoWeekYear();
case "wo":
return l.ordinal(r.week(), "W");
case "w":
case "ww":
return c.s(r.week(), h === "w" ? 1 : 2, "0");
case "W":
case "WW":
return c.s(r.isoWeek(), h === "W" ? 1 : 2, "0");
case "k":
case "kk":
return c.s(String(r.$H === 0 ? 24 : r.$H), h === "k" ? 1 : 2, "0");
case "X":
return Math.floor(r.$d.getTime() / 1e3);
case "x":
return r.$d.getTime();
case "z":
return "[" + r.offsetName() + "]";
case "zzz":
return "[" + r.offsetName("long") + "]";
default:
return h;
}
});
return n.bind(this)(g);
};
};
});
})(Ht);
var ge = Ht.exports;
const fe = /* @__PURE__ */ N(ge);
var At = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
return function(e, i, s) {
s.updateLocale = function(n, o) {
var r = s.Ls[n];
if (r) return (o ? Object.keys(o) : []).forEach(function(l) {
r[l] = o[l];
}), r;
};
};
});
})(At);
var me = At.exports;
const pe = /* @__PURE__ */ N(me);
var It = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
var e = "day";
return function(i, s, n) {
var o = function(c) {
return c.add(4 - c.isoWeekday(), e);
}, r = s.prototype;
r.isoWeekYear = function() {
return o(this).year();
}, r.isoWeek = function(c) {
if (!this.$utils().u(c)) return this.add(7 * (c - this.isoWeek()), e);
var g, h, d, m, p = o(this), u = (g = this.isoWeekYear(), h = this.$u, d = (h ? n.utc : n)().year(g).startOf("year"), m = 4 - d.isoWeekday(), d.isoWeekday() > 4 && (m += 7), d.add(m, e));
return p.diff(u, "week") + 1;
}, r.isoWeekday = function(c) {
return this.$utils().u(c) ? this.day() || 7 : this.day(this.day() % 7 ? c : c - 7);
};
var l = r.startOf;
r.startOf = function(c, g) {
var h = this.$utils(), d = !!h.u(g) || g;
return h.p(c) === "isoweek" ? d ? this.date(this.date() - (this.isoWeekday() - 1)).startOf("day") : this.date(this.date() - 1 - (this.isoWeekday() - 1) + 7).endOf("day") : l.bind(this)(c, g);
};
};
});
})(It);
var xe = It.exports;
const ye = /* @__PURE__ */ N(xe);
var Gt = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
var e = { year: 0, month: 1, day: 2, hour: 3, minute: 4, second: 5 }, i = {};
return function(s, n, o) {
var r, l = function(d, m, p) {
p === void 0 && (p = {});
var u = new Date(d), x = function(w, E) {
E === void 0 && (E = {});
var T = E.timeZoneName || "short", O = w + "|" + T, C = i[O];
return C || (C = new Intl.DateTimeFormat("en-US", { hour12: !1, timeZone: w, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit", timeZoneName: T }), i[O] = C), C;
}(m, p);
return x.formatToParts(u);
}, c = function(d, m) {
for (var p = l(d, m), u = [], x = 0; x < p.length; x += 1) {
var w = p[x], E = w.type, T = w.value, O = e[E];
O >= 0 && (u[O] = parseInt(T, 10));
}
var C = u[3], k = C === 24 ? 0 : C, S = u[0] + "-" + u[1] + "-" + u[2] + " " + k + ":" + u[4] + ":" + u[5] + ":000", b = +d;
return (o.utc(S).valueOf() - (b -= b % 1e3)) / 6e4;
}, g = n.prototype;
g.tz = function(d, m) {
d === void 0 && (d = r);
var p, u = this.utcOffset(), x = this.toDate(), w = x.toLocaleString("en-US", { timeZone: d }), E = Math.round((x - new Date(w)) / 1e3 / 60), T = 15 * -Math.round(x.getTimezoneOffset() / 15) - E;
if (!Number(T)) p = this.utcOffset(0, m);
else if (p = o(w, { locale: this.$L }).$set("millisecond", this.$ms).utcOffset(T, !0), m) {
var O = p.utcOffset();
p = p.add(u - O, "minute");
}
return p.$x.$timezone = d, p;
}, g.offsetName = function(d) {
var m = this.$x.$timezone || o.tz.guess(), p = l(this.valueOf(), m, { timeZoneName: d }).find(function(u) {
return u.type.toLowerCase() === "timezonename";
});
return p && p.value;
};
var h = g.startOf;
g.startOf = function(d, m) {
if (!this.$x || !this.$x.$timezone) return h.call(this, d, m);
var p = o(this.format("YYYY-MM-DD HH:mm:ss:SSS"), { locale: this.$L });
return h.call(p, d, m).tz(this.$x.$timezone, !0);
}, o.tz = function(d, m, p) {
var u = p && m, x = p || m || r, w = c(+o(), x);
if (typeof d != "string") return o(d).tz(x);
var E = function(k, S, b) {
var D = k - 60 * S * 1e3, I = c(D, b);
if (S === I) return [D, S];
var _ = c(D -= 60 * (I - S) * 1e3, b);
return I === _ ? [D, I] : [k - 60 * Math.min(I, _) * 1e3, Math.max(I, _)];
}(o.utc(d, u).valueOf(), w, x), T = E[0], O = E[1], C = o(T).utcOffset(O);
return C.$x.$timezone = x, C;
}, o.tz.guess = function() {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}, o.tz.setDefault = function(d) {
r = d;
};
};
});
})(Gt);
var we = Gt.exports;
const be = /* @__PURE__ */ N(we);
var Rt = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
var e = "minute", i = /[+-]\d\d(?::?\d\d)?/g, s = /([+-]|\d\d)/g;
return function(n, o, r) {
var l = o.prototype;
r.utc = function(u) {
var x = { date: u, utc: !0, args: arguments };
return new o(x);
}, l.utc = function(u) {
var x = r(this.toDate(), { locale: this.$L, utc: !0 });
return u ? x.add(this.utcOffset(), e) : x;
}, l.local = function() {
return r(this.toDate(), { locale: this.$L, utc: !1 });
};
var c = l.parse;
l.parse = function(u) {
u.utc && (this.$u = !0), this.$utils().u(u.$offset) || (this.$offset = u.$offset), c.call(this, u);
};
var g = l.init;
l.init = function() {
if (this.$u) {
var u = this.$d;
this.$y = u.getUTCFullYear(), this.$M = u.getUTCMonth(), this.$D = u.getUTCDate(), this.$W = u.getUTCDay(), this.$H = u.getUTCHours(), this.$m = u.getUTCMinutes(), this.$s = u.getUTCSeconds(), this.$ms = u.getUTCMilliseconds();
} else g.call(this);
};
var h = l.utcOffset;
l.utcOffset = function(u, x) {
var w = this.$utils().u;
if (w(u)) return this.$u ? 0 : w(this.$offset) ? h.call(this) : this.$offset;
if (typeof u == "string" && (u = function(C) {
C === void 0 && (C = "");
var k = C.match(i);
if (!k) return null;
var S = ("" + k[0]).match(s) || ["-", 0, 0], b = S[0], D = 60 * +S[1] + +S[2];
return D === 0 ? 0 : b === "+" ? D : -D;
}(u), u === null)) return this;
var E = Math.abs(u) <= 16 ? 60 * u : u, T = this;
if (x) return T.$offset = E, T.$u = u === 0, T;
if (u !== 0) {
var O = this.$u ? this.toDate().getTimezoneOffset() : -1 * this.utcOffset();
(T = this.local().add(E + O, e)).$offset = E, T.$x.$localOffset = O;
} else T = this.utc();
return T;
};
var d = l.format;
l.format = function(u) {
var x = u || (this.$u ? "YYYY-MM-DDTHH:mm:ss[Z]" : "");
return d.call(this, x);
}, l.valueOf = function() {
var u = this.$utils().u(this.$offset) ? 0 : this.$offset + (this.$x.$localOffset || this.$d.getTimezoneOffset());
return this.$d.valueOf() - 6e4 * u;
}, l.isUTC = function() {
return !!this.$u;
}, l.toISOString = function() {
return this.toDate().toISOString();
}, l.toString = function() {
return this.toDate().toUTCString();
};
var m = l.toDate;
l.toDate = function(u) {
return u === "s" && this.$offset ? r(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate() : m.call(this);
};
var p = l.diff;
l.diff = function(u, x, w) {
if (u && this.$u === u.$u) return p.call(this, u, x, w);
var E = this.local(), T = r(u).local();
return p.call(E, T, x, w);
};
};
});
})(Rt);
var ve = Rt.exports;
const Te = /* @__PURE__ */ N(ve);
var Se = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i();
})(Y, function() {
return { name: "en", weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), ordinal: function(e) {
var i = ["th", "st", "nd", "rd"], s = e % 100;
return "[" + e + (i[(s - 20) % 10] || i[s] || i[0]) + "]";
} };
});
})(Se);
var Ee = { exports: {} };
(function(f, t) {
(function(e, i) {
f.exports = i(H);
})(Y, function(e) {
function i(o) {
return o && typeof o == "object" && "default" in o ? o : { default: o };
}
var s = i(e), n = { name: "zh", weekdays: "星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"), weekdaysShort: "周日_周一_周二_周三_周四_周五_周六".split("_"), weekdaysMin: "日_一_二_三_四_五_六".split("_"), months: "一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"), monthsShort: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"), ordinal: function(o, r) {
return r === "W" ? o + "周" : o + "日";
}, weekStart: 1, yearStart: 4, formats: { LT: "HH:mm", LTS: "HH:mm:ss", L: "YYYY/MM/DD", LL: "YYYY年M月D日", LLL: "YYYY年M月D日Ah点mm分", LLLL: "YYYY年M月D日ddddAh点mm分", l: "YYYY/M/D", ll: "YYYY年M月D日", lll: "YYYY年M月D日 HH:mm", llll: "YYYY年M月D日dddd HH:mm" }, relativeTime: { future: "%s后", past: "%s前", s: "几秒", m: "1 分钟", mm: "%d 分钟", h: "1 小时", hh: "%d 小时", d: "1 天", dd: "%d 天", M: "1 个月", MM: "%d 个月", y: "1 年", yy: "%d 年" }, meridiem: function(o, r) {
var l = 100 * o + r;
return l < 600 ? "凌晨" : l < 900 ? "早上" : l < 1100 ? "上午" : l < 1300 ? "中午" : l < 1800 ? "下午" : "晚上";
} };
return s.default.locale(n, null, !0), n;
});
})(Ee);
const ke = (f, t) => {
const e = t.prototype;
e.setLocale = function(s) {
return this.$locale = s || H().locale(), this.$L = this.$locale, this;
};
const i = e.format;
e.format = function(s) {
return this.$L = H().locale(), i.bind(this)(s);
};
};
H.extend(te);
H.extend(ie);
H.extend(ne);
H.extend(re);
H.extend(ce);
H.extend(he);
H.extend(ue);
H.extend(fe);
H.extend(pe);
H.extend(ye);
H.extend(be);
H.extend(Te);
H.extend(ke);
function wt(f) {
try {
if (H.locale() === f) return;
if (H.locale(f) !== f) throw Error();
L.info(`Locale set to ${f}`);
} catch {
L.warn(`Failed to set locale ${f}, fallback to en`), H.locale("en");
}
}
const ht = () => ({
small: {
hour: 15,
day: 15,
week: 5,
month: 3,
quarter: 3
},
normal: {
hour: 30,
day: 30,
week: 10,
month: 7,
quarter: 7
},
large: {
hour: 60,
day: 60,
week: 20,
month: 14,
quarter: 14
}
});
class Oe {
constructor() {
a(this, "startTime", H().startOf("day"));
a(this, "endTime", H().endOf("day"));
/** 结束的标准时间。切换单位会影响结尾的扩展,需要单独记录一个标准时间 */
a(this, "targetEnd", H().endOf("day"));
/** 固定起始日期 */
a(this, "strictStart", !1);
/** 固定截止日期 */
a(this, "strictEnd", !1);
/** 是否锁定时间范围 */
a(this, "isStrict", !1);
/** 是否自适应宽度 */
a(this, "isAuto", !1);
/** 表头的日期列表 */
a(this, "timeline", []);
a(this, "headerGroupFormat");
a(this, "headerCellFormat");
a(this, "isDirty", !0);
// 标记缓存是否需要更新
/** 是否第一次赋值,如果第一次赋值,允许全部赋值 */
a(this, "isFirstTime", !0);
/** 总宽度 */
a(this, "allWidth", 0);
/** 每一格的宽度 */
a(this, "cellWidth");
/** 用户设定的单位 */
a(this, "unit", "day");
this.cellWidth = J(ht().normal);
}
getStartTime() {
return this.startTime;
}
getEndTime() {
return this.endTime;
}
getCellWidth() {
const t = this.cellWidth[this.getChildUnit()];
if (this.isAuto) {
const e = this.allWidth / this.getCellCount();
return Math.max(isNaN(e) ? 0 : e, t);
}
return t;
}
getCellCount() {
return this.timeline.reduce((t, e) => {
var i;
return t + (((i = e.children) == null ? void 0 : i.length) || 0);
}, 0);
}
getCellUnit() {
return this.getFinelyUnit();
}
setAllWidth(t) {
if (this.allWidth = t, !this.strictEnd) {
const e = this.getCellWidth(), i = this.targetEnd.diff(this.startTime, this.getFinelyUnit());
if (e * i < this.allWidth) {
const s = this.allWidth - e * i, n = Math.ceil(s / e);
this.endTime = this.targetEnd.add(n, this.getFinelyUnit()), this.invalidateCache();
}
}
}
getTimeLeft(t) {
const e = this.getCellWidth(), i = this.getFinelyUnit(), s = 60 * 60 * (i === "day" ? 24 : 1) / e;
return t.diff(this.startTime, "second") / s;
}
/**
* 根据横向位置计算对应的时间
* @param left 横向位置
* @returns 对应的时间对象
*/
getTimeByLeft(t) {
const e = this.getCellWidth(), i = this.getFinelyUnit(), s = 60 * 60 * (i === "day" ? 24 : 1) / e, n = t * s;
return this.startTime.add(n, "second");
}
init(t) {
this.isDirty = !0;
const { unit: e, chart: i } = t;
this.isAuto = !!i.autoCellWidth;
const s = {
hour: "hour",
day: "day",
week: "week",
month: "month",
quarter: "quarter"
}[e];
s || L.warn(`Unknown unit: [${e}]. Falling back to "day".`), this.unit = s || "day", i.startTime && (this.startTime = H(i.startTime).startOf(this.getFinelyUnit()), this.strictStart = !0), i.endTime && (this.endTime = H(i.endTime).endOf(this.getFinelyUnit()), this.strictEnd = !0), this.isStrict = this.strictStart && this.strictEnd, i.cellWidth && (Pt(i.cellWidth) ? this.cellWidth = {
hour: i.cellWidth,
day: i.cellWidth,
week: i.cellWidth,
month: i.cellWidth,
quarter: i.cellWidth
} : U(i.cellWidth) ? this.cellWidth = J(
ht()[i.cellWidth] || ht().normal
) : Tt(i.cellWidth) && (this.cellWidth = Object.assign(this.cellWidth, i.cellWidth))), this.headerCellFormat = i.headerCellFormat, this.headerGroupFormat = i.headerGroupFormat;
}
update(t) {
this.init(t), this.endTime = this.targetEnd.clone();
}
setDate(t, e) {
this.isStrict || (!this.strictStart && t && (this.isFirstTime || t.isBefore(this.startTime)) && (this.startTime = t.startOf(this.getFinelyUnit())), !this.strictEnd && e && (this.isFirstTime || e.isAfter(this.endTime)) && (this.endTime = e.endOf(this.getFinelyUnit())), this.targetEnd = this.endTime.clone(), this.isFirstTime = !1, this.invalidateCache());
}
/** 获取表头的日期列表 */
getTimeline() {
if (!this.isDirty && this.timeline.length > 0)
return this.timeline;
const t = [];
let e = this.startTime.clone();
for (t.push({
date: e,
label: this.formatterGroupLabel(e),
children: [
{
date: e,
label: this.formatterCellLabel(e)
}
]
}); e.isSameOrBefore(this.endTime, this.getFinelyUnit()); ) {
const i = e.add(1, this.getFinelyUnit()).startOf(this.getFinelyUnit()).clone(), s = this.formatterGroupLabel(i), n = t.find((o) => o.label === s);
n ? (n.children || (n.children = []), n.children.push({
date: i,
label: this.formatterCellLabel(i)
})) : t.push({
date: i,
label: s,
children: [
{
date: i,
label: this.formatterCellLabel(i)
}
]
}), e = i;
}
return this.isDirty = !1, this.timeline = t, t;
}
clear() {
this.isDirty = !0, this.isFirstTime = !0;
}
/**
* 缓存失效标记
*/
invalidateCache() {
this.isDirty = !0;
}
/** 获取细粒度单位 */
getFinelyUnit() {
return this.unit === "hour" ? "hour" : "day";
}
/** 获取下层单位 */
getChildUnit() {
return this.unit;
}
/** 获取上层单位 */
getGroupUnit() {
switch (this.unit) {
case "hour":
return "day";
case "month":
case "quarter":
return "year";
case "day":
case "week":
default:
return "month";
}
}
/** 格式化上层文本 */
formatterGroupLabel(t) {
if (j(this.headerGroupFormat)) {
const i = this.headerGroupFormat(t.toDate(), this.unit);
if (i) return i;
}
if (U(this.headerGroupFormat))
return t.format(this.headerGroupFormat);
switch (this.getGroupUnit()) {
case "month":
return t.format("YYYY-MM");
case "year":
return t.format("YYYY");
case "day":
default:
return t.format("YYYY-MM-DD");
}
}
/**
* 格式化下层文本
*/
formatterCellLabel(t) {
if (j(this.headerCellFormat)) {
const i = this.headerCellFormat(t.toDate(), this.unit);
if (i) return i;
}
if (U(this.headerCellFormat))
return t.format(this.headerCellFormat);
switch (this.getChildUnit()) {
case "hour":
return t.format("H");
case "week":
return t.format("wo");
case "month":
return t.format("MMM");
case "quarter":
return t.format("[Q]Q");
case "day":
default:
return t.format("Do");
}
}
/**
* 获取时间轴的总宽度
* @returns 时间轴总宽度(像素)
*/
getTotalWidth() {
return this.getCellCount() * this.getCellWidth();
}
expand(t, e = 1) {
t === "left" ? this.startTime = this.startTime.subtract(e, this.getFinelyUnit()) : t === "right" ? this.endTime = this.endTime.add(e, this.getFinelyUnit()) : t === "all" && (this.startTime = this.startTime.subtract(e, this.getFinelyUnit()), this.endTime = this.endTime.add(e, this.getFinelyUnit())), this.targetEnd = this.endTime.clone(), this.invalidateCache();
}
/**
* 判定一个时间是否在时间轴上
* @param time 时间
* @returns 是否在时间轴上
*/
isInTimeAxis(t) {
return t.isSameOrAfter(this.startTime) && t.isSameOrBefore(this.endTime);
}
}
class Me {
// 使用私有构造函数防止直接创建实例
constructor(t, e) {
// 声明成员属性类型
a(this, "optionManager");
a(this, "dataManager");
a(this, "columnManager");
a(this, "timeAxis");
var n;
this.context = t;
const i = gt(e, ["data"]), s = e == null ? void 0 : e.data;
if (s && !V(s))
throw L.exception("Data should be a array.");
this.optionManager = new Ut(), this.optionManager.setOptions(i), i.locale && wt(i.locale), this.timeAxis = new Oe(), this.timeAxis.init(this.optionManager.getOptions()), this.columnManager = new Jt(this.context), i.table && i.table.columns && this.columnManager.init(i.table.columns), this.dataManager = new Kt(this, this.context.event), s && this.dataManager.setData(s, !0), (n = e == null ? void 0 : e.baselines) != null && n.data && this.dataManager.setBaselines(e.baselines.data);
}
getOptionManager() {
return this.optionManager;
}
getDataManager() {
return this.dataManager;
}
getColumnManager() {
return this.columnManager;
}
getTimeAxis() {
return this.timeAxis;
}
setOption(t, e = { merge: !0 }) {
var n, o;
const i = gt(t, ["data"]), s = t == null ? void 0 : t.data;
this.optionManager.setOptions(i, e), ((n = i.milestone) == null ? void 0 : n.show) !== void 0 && this.dataManager.getVisibleTasks().forEach((r) => {
r.updateMode();
}), V(s) && this.dataManager.setData(s, !1), V((o = t.baselines) == null ? void 0 : o.data) && this.dataManager.setBaselines(t.baselines.data), i.locale && wt(i.locale), i.table && i.table.columns && this.columnManager.update(i.table.columns), this.timeAxis.update(this.optionManager.getOptions());
}
updateTime(t, e) {
this.timeAxis.setDate(t, e);
}
}
class Le {
constructor(t, e, i) {
a(this, "rootElement");
a(this, "options");
// 滚动条元素
a(this, "hScrollbar");
a(this, "vScrollbar");
a(this, "hScrollThumb");
a(this, "vScrollThumb");
a(this, "scrollbarContainer");
// 内容尺寸和滚动位置
a(this, "viewportWidth", 0);
a(this, "viewportHeight", 0);
a(this, "contentWidth", 0);
a(this, "contentHeight", 0);
a(this, "scrollLeft", 0);
a(this, "scrollTop", 0);
// 滚动条状态
a(this, "isDraggingHScroll", !1);
a(this, "isDraggingVScroll", !1);
a(this, "isMouseOverRoot", !1);
a(this, "isMouseOverScrollbar", !1);
a(this, "hideTimeout", null);
a(this, "showTimeout", null);
// 新增:显示计时器
a(this, "isVisible", !1);
// 拖拽状态
a(this, "dragStartX", 0);
a(this, "dragStartY", 0);
a(this, "thumbStartScrollLeft", 0);
a(this, "thumbStartScrollTop", 0);
// 动画状态
a(this, "isAnimating", !1);
a(this, "animationFrameId", null);
a(this, "animationStartTime", 0);
a(this, "animationStartScrollLeft", 0);
a(this, "animationStartScrollTop", 0);
a(this, "animationTargetScrollLeft", 0);
a(this, "animationTargetScrollTop", 0);
a(this, "animationSource", "api");
// 记录动画触发源
// 节流处理
a(this, "throttledHandleMouseMove");
a(this, "throttledHandleWheel");
a(this, "handleRootMouseMove", () => {
!this.isVisible && this.isMouseOverRoot ? this.scheduleShow() : this.isVisible && !this.isMouseOverScrollbar && this.scheduleHide();
});
a(this, "handleScrollbarMouseEnter", () => {
this.isMouseOverScrollbar = !0, this.scheduleShow();
});
a(this, "handleScrollbarMouseLeave", () => {
this.isMouseOverScrollbar = !1, this.isMouseOverRoot && this.scheduleHide();
});
a(this, "handleMouseEnter", () => {
this.isMouseOverRoot = !0, this.scheduleShow();
});
a(this, "handleMouseLeave", () => {
this.isMouseOverRoot = !1, !this.isDraggingHScroll && !this.isDraggingVScroll && !this.isMouseOverScrollbar && (this.clearTimeouts(!0, !1), this.scheduleHide());
});
a(this, "handleHorizontalThumbMouseDown", (t) => {
t.preventDefault(), t.stopPropagation(), this.isDraggingHScroll = !0, this.dragStartX = t.clientX, this.thumbStartScrollLeft = this.scrollLeft, this.hScrollThumb.style.backgroundColor = this.options.thumb.color, this.scheduleShow(), document.addEventListener("mousemove", this.throttledHandleMouseMove), document.addEventListener("mouseup", this.handleMouseUp);
});
a(this, "handleVerticalThumbMouseDown", (t) => {
t.preventDefault(), t.stopPropagation(), this.isDraggingVScroll = !0, this.dragStartY = t.clientY, this.thumbStartScrollTop = this.scrollTop, this.vScrollThumb.style.backgroundColor = this.options.thumb.color, this.scheduleShow(), document.addEventListener("mousemove", this.throttledHandleMouseMove), document.addEventListener("mouseup", this.handleMouseUp);
});
a(this, "handleHorizontalTrackMouseDown", (t) => {
if (t.target !== this.hScrollbar) return;
t.preventDefault();
const e = this.hScrollbar.getBoundingClientRect(), i = this.hScrollThumb.offsetWidth, s = t.clientX - e.left, n = this.hScrollbar.clientWidth, o = this.contentWidth - this.viewportWidth, r = n - i, l = (s - i / 2) / r * o;
this.scrollTo({ x: l, y: this.scrollTop }, "track");
});
a(this, "handleVerticalTrackMouseDown", (t) => {
if (t.target !== this.vScrollbar) return;
t.preventDefault();
const e = this.vScrollbar.getBoundingClientRect(), i = this.vScrollThumb.offsetHeight, s = t.clientY - e.top, n = this.vScrollbar.clientHeight, o = this.contentHeight - this.viewportHeight, r = n - i, l = (s - i / 2) / r * o;
this.scrollTo({ x: this.scrollLeft, y: l }, "track");
});
a(this, "handleMouseUp", () => {
if (this.isDraggingHScroll || this.isDraggingVScroll) {
const t = this.isDraggingHScroll, e = this.isDraggingVScroll;
this.isDraggingHScroll = !1, this.isDraggingVScroll = !1, t && (this.hScrollThumb.style.backgroundColor = this.options.thumb.color), e && (this.vScrollThumb.style.backgroundColor = this.options.thumb.color), document.removeEventListener("mousemove", this.throttledHandleMouseMove), document.removeEventListener("mouseup", this.handleMouseUp), !this.isMouseOverRoot && !this.isMouseOverScrollbar ? this.scheduleHide() : this.scheduleHide();
}
});
// --- 动画处理 ---
a(this, "animationStep", (t) => {
if (!this.isAnimating) return;
const e = t - this.animationStartTime, i = this.options.animationDuration, s = Math.min(1, e / i), n = s * (2 - s), o = this.animationStartScrollLeft + (this.animationTargetScrollLeft - this.animationStartScrollLeft) * n, r = this.animationStartScrollTop + (this.animationTargetScrollTop - this.animationStartScrollTop) * n, l = this.scrollLeft !== o, c = this.scrollTop !== r;
(l || c) && this.emit(this.animationSource, o, r), s < 1 ? this.animationFrameId = requestAnimationFrame(this.animationStep) : (this.isAnimating = !1, this.animationFrameId = null, (this.scrollLeft !== this.animationTargetScrollLeft || this.scrollTop !== this.animationTargetScrollTop) && this.emit(this.animationSource, this.animationTargetScrollLeft, this.animationTargetScrollTop), this.scheduleHide());
});
this.root = t, this.rootElement = e, this.options = ot(
{
showHorizontal: !0,
showVertical: !0,
track: {
size: 8,
radius: 4,
color: "transparent"
},
thumb: {
size: 30,
radius: 4,
color: "rgba(0, 0, 0, 0.4)"
},
showDelay: 0,
// 延迟显示时间 (ms)
hideDelay: 500,
// 延迟隐藏时间 (ms)
animationDuration: 100,
// 平滑滚动动画时长 (ms)
showDuration: 200,
// 滚动条显示动画时长 (ms)
hideDuration: 200
// 滚动条隐藏动画时长 (ms)
},
i
), this.throttledHandleMouseMove = ft(
this.handleMouseMove.bind(this),
16
), this.throttledHandleWheel = ft(this.handleWheel.bind(this), 16, {
leading: !0,
trailing: !1
}), this.createElements(), this.applyStyles(), this.bindEvents(), this.rootElement.matches(":hover") ? this.handleMouseEnter() : (this.clearTimeouts(), this.hideScrollbars(!0));
}
// --- 元素创建与管理 ---
createElements() {
this.scrollbarContainer = document.createElement("div"), this.scrollbarContainer.className = "x-gantt-scrollbar-container", this.rootElement.appendChild(this.scrollbarContainer), this.hScrollbar = this.createScrollbarElement("horizontal"), this.hScrollThumb = this.createScrollThumbElement("horizontal"), this.hScrollbar.appendChild(this.hScrollThumb), this.vScrollbar = this.createScrollbarElement("vertical"), this.vScrollThumb = this.createScrollThumbElement("vertical"), this.vScrollbar.appendChild(this.vScrollThumb), this.scrollbarContainer.appendChild(this.hScrollbar), this.scrollbarContainer.appendChild(this.vScrollbar);
}
createScrollbarElement(t) {
const e = document.createElement("div");
return e.className = `x-gantt-scrollbar x-gantt-${t}-scrollbar`, e;
}
createScrollThumbElement(t) {
const e = document.createElement("div");
return e.className = `x-gantt-scrollbar-thumb x-gantt-${t}-thumb`, e;
}
// --- 样式应用 ---
applyStyles() {
const t = this.scrollbarContainer.style;
t.position = "absolute", t.top = "0", t.left = "0", t.width = "100%", t.height = "100%", t.pointerEvents = "none", t.zIndex = "100", this.applyScrollbarStyles(this.hScrollbar, "horizontal"), this.applyScrollbarStyles(this.vScrollbar, "vertical"), this.applyThumbStyles(this.hScrollThumb, "horizontal"), this.applyThumbStyles(this.vScrollThumb, "vertical");
}
applyScrollbarStyles(t, e) {
const i = t.style;
i.position = "absolute", i.backgroundColor = this.options.track.color, i.borderRadius = `${this.options.track.size / 2}px`, i.opacity = "0", i.transition = `opacity ${this.options.hideDuration / 1e3}s ease-out`, i.pointerEvents = "auto", e === "horizontal" ? (i.bottom = "0px", i.left = "0px", i.height = `${this.options.track.size}px`, i.width = "0px") : (i.right = "0px", i.top = "0px", i.width = `${this.options.track.size}px`, i.height = "0px");
}
applyThumbStyles(t, e) {
const i = t.style;
i.position = "absolute", i.backgroundColor = this.options.thumb.color, i.borderRadius = `${this.options.thumb.radius}px`, i.cursor = "pointer", i.transition = "background-color 0.2s", i.pointerEvents = "auto", e === "horizontal" ? (i.height = "100%", i.top = "0", i.left = "0") : (i.width = "100%", i.left = "0", i.top = "0");
}
// --- 事件绑定 ---
bindEvents() {
this.rootElement.addEventListener("mouseenter", this.handleMouseEnter), this.rootElement.addEventListener("mouseleave", this.handleMouseLeave), this.rootElement.addEventListener("mousemove", this.handleRootMouseMove), this.hScrollThumb.addEventListener(
"mousedown",
this.handleHorizontalThumbMouseDown
), this.vScrollThumb.addEventListener(
"mousedown",
this.handleVerticalThumbMouseDown
), this.hScrollbar.addEventListener(
"mousedown",
this.handleHorizontalTrackMouseDown
), this.vScrollbar.addEventListener(
"mousedown",
this.handleVerticalTrackMouseDown
), this.hScrollbar.addEventListener(
"mouseenter",
this.handleScrollbarMouseEnter
), this.vScrollbar.addEventListener(
"mouseenter",
this.handleScrollbarMouseEnter
), this.hScrollbar.addEventListener(
"mouseleave",
this.handleScrollbarMouseLeave
), this.vScrollbar.addEventListener(
"mouseleave",
this.handleScrollbarMouseLeave
), this.rootElement.addEventListener("wheel", this.throttledHandleWheel, {
passive: !1
});
}
unbindEvents() {
this.rootElement.removeEventListener("mouseenter", this.handleMouseEnter), this.rootElement.removeEventListener("mouseleave", this.handleMouseLeave), this.rootElement.removeEventListener("mousemove", this.handleRootMouseMove), this.hScrollThumb.removeEventListener(
"mousedown",
this.handleHorizontalThumbMouseDown
), this.vScrollThumb.removeEventListener(
"mousedown",
this.handleVerticalThumbMouseDown
), this.hScrollbar.removeEventListener(
"mousedown",
this.handleHorizontalTrackMouseDown
), this.vScrollbar.removeEventListener(
"mousedown",
this.handleVerticalTrackMouseDown
), this.hScrollbar.removeEventListener(
"mouseenter",
this.handleScrollbarMouseEnter
), this.vScrollbar.removeEventListener(
"mouseenter",
this.handleScrollbarMouseEnter
), this.hScrollbar.removeEventListener(
"mouseleave",
this.handleScrollbarMouseLeave
), this.vScrollbar.removeEventListener(
"mouseleave",
this.handleScrollbarMouseLeave
), this.rootElement.removeEventListener("wheel", this.throttledHandleWheel), document.removeEventListener("mousemove", this.throttledHandleMouseMove), document.removeEventListener("mouseup", this.handleMouseUp);
}
// --- 事件处理 ---
emit(t, e, i) {
this.scrollLeft = G(e, 0, this.contentWidth - this.viewportWidth), this.scrollTop = G(i, 0, this.contentHeight - this.viewportHeight), this.updateThumbStyles(), this.root.event.emit(y.SCROLL, {
x: this.scrollLeft,
y: this.scrollTop,
source: t
});
}
handleMouseMove(t) {
if (!(!this.isDraggingHScroll && !this.isDraggingVScroll)) {
if (this.scheduleShow(), this.isDraggingHScroll) {
const e = t.clientX - this.dragStartX, i = this.hScrollbar.clientWidth, s = this.hScrollThumb.offsetWidth, n = Math.max(0, i - s), o = Math.max(0, this.contentWidth - this.viewportWidth);
if (n === 0 || o === 0) return;
const r = e / n * o, l = this.thumbStartScrollLeft + r;
this.scrollTo({ x: l, y: this.scrollTop }, "drag");
}
if (this.isDraggingVScroll) {
const e = t.clientY - this.dragStartY, i = this.vScrollbar.clientHeight, s = this.vScrollThumb.offsetHeight, n = Math.max(0, i - s), o = Math.max(
0,
this.contentHeight - this.viewportHeight
);
if (n === 0 || o === 0) return;
const r = e / n * o, l = this.thumbStartScrollTop + r;
this.scrollTo({ x: this.scrollLeft, y: l }, "drag");
}
}
}
handleWheel(t) {
if (t.target !== this.rootElement && !this.rootElement.contains(t.target) && L.debug(
"Wheel event ignored, target not root or descendant:",
t.target
), !this.isMouseOverRoot && !this.isMouseOverScrollbar) {
L.debug("Wheel event ignored, mouse not over root or scrollbar");
return;
}
const e = this.canScrollHorizontal(), i = this.canScrollVertical();
if (!e && !i)
return;
t.preventDefault();
let s = t.deltaX, n = t.deltaY;
Math.abs(t.deltaX) < Math.abs(t.deltaY) && t.shiftKey && e && (s = n, n = 0);
const o = this.scrollLeft + s, r = this.scrollTop + n;
this.emit("wheel", o, r);
}
// 处理滚轮滚动的平滑动画
animateWheelScroll(t, e) {
this.cancelAnimation();
const i = this.clampScroll({
x: t,
y: e
});
if (this.scrollLeft === i.x && this.scrollTop === i.y)
return;
this.isAnimating = !0, this.animationStartTime = performance.now(), this.animationStartScrollLeft = this.scrollLeft, this.animationStartScrollTop = this.scrollTop, this.animationTargetScrollLeft = i.x, this.animationTargetScrollTop = i.y, this.animationSource = "wheel";
const s = 150, n = (o) => {
if (!this.isAnimating) return;
const r = o - this.animationStartTime, l = Math.min(1, r / s), c = l * (2 - l), g = this.animationStartScrollLeft + (this.animationTargetScrollLeft - this.animationStartScrollLeft) * c, h = this.animationStartScrollTop + (this.animationTargetScrollTop - this.animationStartScrollTop) * c, d = this.scrollLeft !== g, m = this.scrollTop !== h;
(d || m) && this.emit("wheel", g, h), l < 1 ? this.animationFrameId = requestAnimationFrame(n) : (this.isAnimating = !1, this.animationFrameId = null, (this.scrollLeft !== this.animationTargetScrollLeft || this.scrollTop !== this.animationTargetScrollTop) && this.emit("wheel", this.animationTargetScrollLeft, this.animationTargetScrollTop), this.scheduleHide());
};
this.animationFrameId = requestAnimationFrame(n);
}
// --- 滚动条显隐 ---
clearTimeouts(t = !0, e = !0) {
t && this.showTimeout !== null && (window.clearTimeout(this.showTimeout), this.showTimeout = null), e && this.hideTimeout !== null && (window.clearTimeout(this.hideTimeout), this.hideTimeout = null);
}
scheduleShow() {
if (this.isVisible || this.showTimeout !== null) {
this.hideTimeout !== null && this.clearTimeouts(!1, !0);
return;
}
this.clearTimeouts(!0, !0), this.options.showDelay <= 0 ? this.showScrollbars() : this.showTimeout = window.setTimeout(() => {
this.showScrollbars(), this.showTimeout = null;
}, this.options.showDelay);
}
showScrollbars() {
this.clearTimeouts(), this.isVisible = !0, this.hScrollbar.style.transition = `opacity ${this.options.showDuration / 1e3}s ease-in`, this.vScrollbar.style.transition = `opacity ${this.options.showDuration / 1e3}s ease-in`, requestAnimationFrame(() => {
this.canScrollHorizontal() && this.options.showHorizontal ? this.hScrollbar.style.opacity = "1" : this.hScrollbar.style.opacity = "0", this.canScrollVertical() && this.options.showVertical ? this.vScrollbar.style.opacity = "1" : this.vScrollbar.style.opacity = "0", setTimeout(() => {
this.isVisible && (this.hScrollbar.style.transition = `opacity ${this.options.hideDuration / 1e3}s ease-out`, this.vScrollbar.style.transition = `opacity ${this.options.hideDuration / 1e3}s ease-out`);
}, this.options.showDuration);
}), this.scheduleHide();
}
scheduleHide() {
if (this.isDraggingHScroll || this.isDraggingVScroll || this.isMouseOverScrollbar) {
this.clearTimeouts(!0, !0);
return;
}
this.hideTimeout === null && (this.clearTimeouts(!0, !1), this.hideTimeout = window.setTimeout(() => {
!this.isMouseOverRoot && !this.isDraggingHScroll && !this.isDraggingVScroll && !this.isMouseOverScrollbar && this.hideScrollbars(), this.hideTimeout = null;
}, this.options.hideDelay));
}
hideScrollbars(t = !1) {
!t && (this.isDraggingHScroll || this.isDraggingVScroll || this.isMouseOverScrollbar) || (this.clearTimeouts(!0, !0), this.isVisible = !1, this.hScrollbar.style.opacity = "0", this.vScrollbar.style.opacity = "0");
}
// --- 尺寸更新与计算 ---
/**
* 更新视口和内容尺寸,并重新计算滚动条状态。
* @param viewportWidth 可见区域宽度
* @param viewportHeight 可见区域高度
* @param contentWidth 内容总宽度
* @param contentHeight 内容总高度
* @param tableWidth 左侧表格宽度 (用于调整水平滚动条的起始位置和宽度)
* @param headerHeight 头部高度 (用于调整垂直滚动条的起始位置和高度)
*/
updateSize(t, e, i, s, n = 0, o = 0) {
this.viewportWidth = Math.max(0, t), this.viewportHeight = Math.max(0, e), this.contentWidth = Math.max(this.viewportWidth, i), this.contentHeight = Math.max(this.viewportHeight, s);
const r = this.canScrollHorizontal() && this.options.showHorizontal, l = this.canScrollVertical() && this.options.showVertical;
if (r) {
const g = this.viewportWidth - (l ? this.options.track.size : 0);
this.hScrollbar.style.display = "block", this.hScrollbar.style.left = `${n}px`, this.hScrollbar.style.width = `${Math.max(0, g)}px`, this.hScrollbar.style.bottom = "0px", this.hScrollbar.style.right = l ? `${this.options.track.size}px` : "0px";
} else
this.hScrollbar.style.display = "none";
if (l) {
const g = this.viewportHeight - o - (r ? this.options.track.size : 0);
this.vScrollbar.style.display = "block", this.vScrollbar.style.top = `${o}px`, this.vScrollbar.style.height = `${Math.max(0, g)}px`, this.vScrollbar.style.right = "0px", this.vScrollbar.style.bottom = r ? `${this.options.track.size}px` : "0px";
} else
this.vScrollbar.style.display = "none";
this.updateThumbStyles();
const c = this.clampScroll({
x: this.scrollLeft,
y: this.scrollTop
});
(c.x !== this.scrollLeft || c.y !== this.scrollTop) && this.emit("api", c.x, c.y), this.isMouseOverRoot || this.isDraggingHScroll || this.isDraggingVScroll ? this.scheduleShow() : !r && !l ? this.hideScrollbars(!0) : this.isVisible ? this.scheduleShow() : this.hideScrollbars(!0);
}
updateThumbStyles() {
if (this.canScrollHorizontal() && this.options.showHorizontal) {
const t = this.hScrollbar.clientWidth, e = Math.max(
this.options.thumb.size,
t * (this.viewportWidth / this.contentWidth)
// 注意这里是用总视口宽度算比例
), i = Math.min(t, e);
this.hScrollThumb.style.width = `${i}px`;
const s = this.contentWidth - this.viewportWidth, n = t - i, o = s > 0 ? this.scrollLeft / s * n : 0;
this.hScrollThumb.style.transform = `translateX(${Math.max(
0,
Math.min(o, n)
)}px)`, this.hScrollThumb.style.left = "0px";
} else
this.hScrollThumb.style.width = "0px";
if (this.canScrollVertical() && this.options.showVertical) {
const t = this.vScrollbar.clientHeight, e = Math.max(
this.options.thumb.size,
t * (this.viewportHeight / this.contentHeight)
// 注意用总视口高度
), i = Math.min(t, e);
this.vScrollThumb.style.height = `${i}px`;
const s = this.contentHeight - this.viewportHeight, n = t - i, o = s > 0 ? this.scrollTop / s * n : 0;
this.vScrollThumb.style.transform = `translateY(${Math.max(
0,
Math.min(o, n)
)}px)`, this.vScrollThumb.style.top = "0px";
} else
this.vScrollThumb.style.height = "0px";
}
canScrollHorizontal() {
return this.contentWidth > this.viewportWidth;
}
canScrollVertical() {
return this.contentHeight > this.viewportHeight;
}
clampScroll(t) {
const e = Math.max(0, this.contentWidth - this.viewportWidth), i = Math.max(0, this.contentHeight - this.viewportHeight);
return {
x: Math.max(0, Math.min(t.x, e)),
y: Math.max(0, Math.min(t.y, i))
};
}
// --- 滚动控制 ---
/**
* 滚动到指定位置
* @param pos 目标滚动位置 {x, y}
* @param source 滚动来源
*/
scrollTo(t, e = "api") {
this.scheduleShow();
const i = this.clampScroll(ot(this.getScrollPosition(), t));
if (this.scrollLeft === i.x && this.scrollTop === i.y) {
if (this.isAnimating && this.animationTargetScrollLeft === i.x && this.animationTargetScrollTop === i.y)
return;
this.cancelAnimation();
return;
}
const s = (e === "api" || e === "track") && this.options.animationDuration > 0;
if (this.cancelAnimation(), s)
this.isAnimating = !0, this.animationStartTime = performance.now(), this.animationStartScrollLeft = this.scrollLeft, this.animationStartScrollTop = this.scrollTop, this.animationTargetScrollLeft = i.x, this.animationTargetScrollTop = i.y, this.animationSource = e, this.animationFrameId = requestAnimationFrame(this.animationStep);
else {
this.isAnimating = !1;
const n = this.scrollLeft !== i.x, o = this.scrollTop !== i.y;
(n || o) && this.emit(e, i.x, i.y);
}
}
cancelAnimation() {
this.animationFrameId !== null && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null), this.isAnimating = !1;
}
/**
* 获取当前滚动位置
*/
getScrollPosition() {
return { x: this.scrollLeft, y: this.scrollTop };
}
// --- 销毁 ---
destroy() {
this.unbindEvents(), this.clearTimeouts(), this.cancelAnimation(), this.scrollbarContainer.parentNode && this.scrollbarContainer.parentNode.removeChild(this.scrollbarContainer), this.rootElement = null, this.eventManager = null, this.hScrollbar = null, this.vScrollbar = null, this.hScrollThumb = null, this.vScrollThumb = null, this.scrollbarContainer = null, L.debug("Scrollbar destroyed");
}
}
function Q(f, t = "") {
const e = ["px", "%", "vh", "vw", "rem", "em"];
if (f == null)
return t;
if (typeof f == "number")
return isFinite(f) ? `${f}px` : t;
if (typeof f == "string") {
const i = f.trim();
if (i === "")
return t;
for (const n of e)
if (i.endsWith(n)) {
const o = i.substring(0, i.length - n.length).trim(), r = Number(o);
if (!isNaN(r) && isFinite(r))
return `${r}${n}`;
break;
}
const s = Number(i);
if (!isNaN(s) && isFinite(s))
return `${s}px`;
}
return t;
}
class it {
/**
* 创建表格单元格
* @param container 父容器(tr元素)
* @param column 列配置
* @param task 任务数据
* @param level 任务层级
* @param rowIndex 行索引
* @param colIndex 列索引
* @param colspan 横向合并的列数
* @param rowspan 纵向合并的行数
*/
constructor(t, e, i, s, n, o, r = 1, l = 1, c) {
a(this, "element");
a(this, "isEmpty", !1);
a(this, "isHandler", !1);
this.context = t, this.container = e, this.column = i, this.task = s, this.rowIndex = n, this.colIndex = o, this.colspan = r, this.rowspan = l, this.isEmpty = c === "empty", this.isHandler = c === "handler", this.element = document.createElement("div"), this.element.className = "x-gantt-table-cell", this.element.style.boxSizing = "border-box", this.element.style.display = "inline-flex", this.element.style.flexShrink = "0", this.element.style.flexGrow = "0", this.element.style.flexBasis = "auto", this.element.style.pointerEvents = "all", this.element.style.setProperty(
"border-color",
this.context.getOptions().border.color,
"important"
), this.element.style.textAlign = this.column.column.align || this.context.getOptions().table.align, !this.context.store.getColumnManager().isLastColumn(this.column.key) && this.context.getOptions().border.show && !this.isEmpty && this.element.classList.add("border"), this.updateWidth(), this.updateHeight(), this.isEmpty ? (this.element.style.borderBottom = "none", this.element.style.pointerEvents = "none", this.element.style.backgroundColor = "transparent", this.element.style.setProperty(
"border-color",
"transparent",
"important"
)) : this.isHandler ? this.setHandler() : this.setContent(), this.container.appendChild(this.element);
}
setContent() {
const t = document.createElement("div");
if (t.className = "x-gantt-table-cell__content", t.style.overflow = "hidden", (this.column.column.ellipsis ?? this.context.getOptions().table.ellipsis ?? !0) && (t.style.textOverflow = "ellipsis"), t.style.whiteSpace = "nowrap", t.style.flex = "1", t.style.height = "100%", t.style.alignContent = "center", this.colIndex === 0 && (t.style.paddingLeft = Q(
this.task.level * this.context.getOptions().row.indent,
"16px"
)), typeof this.column.column.render == "function")
try {
const e = this.column.column.render(this.task.getEmitData());
typeof e == "string" ? t.innerHTML = e : e instanceof HTMLElement ? t.appendChild(e) : L.warn(
"Table cell render function does not return a valid value.",
e
);
} catch (e) {
L.error("Table cell render error:", e), t.textContent = this.task.getField(this.column.column.field) ?? this.context.getOptions().table.emptyText;
}
else
t.textContent = this.task.getField(this.column.column.field) ?? this.context.getOptions().table.emptyText;
this.column.column.customStyle && Object.assign(t.style, this.column.column.customStyle), this.element.appendChild(t);
}
setHandler() {
const t = document.createElement("div");
if (t.className = "x-gantt-table-cell__content", t.style.overflow = "hidden", t.style.whiteSpace = "nowrap", t.style.display = "inline-flex", t.style.flex = "1", t.style.height = "100%", this.context.getOptions().selection.enabled) {
const e = document.createElement("div");
e.style.display = "flex", e.style.flex = "0.5", e.style.justifyContent = "center", e.style.alignItems = "center", new Et(this.context, e, this.task), t.appendChild(e);
}
if (this.context.getOptions().expand.show && this.task.children && this.task.children.length > 0) {
const e = document.createElement("div");
e.className = "x-gantt-table-cell__expand", e.style.display = "flex", e.style.flex = "0.5", e.style.color = this.context.getOptions().primaryColor, e.style.alignItems = "center", e.style.justifyContent = "center", e.style.height = "100%", e.style.width = "14px", e.style.height = "100%", e.style.cursor = "pointer", e.innerHTML = '<svg t="1746693752280" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2612" width="14" height="14"><path d="M724.48 521.728c-1.8432 7.7824-5.7344 14.848-11.3664 20.48l-341.9136 342.016c-16.6912 16.6912-43.7248 16.6912-60.3136 0s-16.6912-43.7248 0-60.3136L622.6944 512 310.8864 200.0896c-16.6912-16.6912-16.6912-43.7248 0-60.3136 16.6912-16.6912 43.7248-16.6912 60.3136 0l341.9136 341.9136c10.8544 10.8544 14.6432 26.112 11.3664 40.0384z" fill="currentColor" p-id="2613"></path></svg>', e.style.transform = this.task.expanded ? "rotate(90deg)" : "", e.addEventListener("click", (i) => {
i.stopPropagation(), this.context.store.getDataManager().expandTask(this.task.id, !1);
}), t.appendChild(e);
}
this.element.appendChild(t);
}
/**
* 移除单元格
*/
remove() {
this.element && this.element.parentNode && this.element.parentNode.removeChild(this.element);
}
/**
* 更新宽度
*/
updateWidth() {
if (this.isHandler) {
this.element.style.width = Q(
this.context.store.getColumnManager().getHandlerColumn().width
);
return;
}
const t = this.context.store.getColumnManager().getLeafColumns().slice(this.colIndex, this.colIndex + Math.max(1, this.colspan)).reduce((e, i) => e + i.width, 0);
this.element.style.width = Q(t);
}
/**
* 更新高度
*/
updateHeight() {
const t = this.context.getOptions().row.height;
this.element.style.height = Q(t * Math.max(1, this.rowspan));
}
}
class bt {
/**
* 创建表格行
* @param context 上下文
* @param container 父容器
* @param task 任务数据
*/
constructor(t, e, i, s, n = !1) {
// 行元素
a(this, "element");
// 行内单元格集合
a(this, "cells", []);
this.context = t, this.container = e, this.task = i, this.top = s, this.element = document.createElement("div"), this.element.className = "x-gantt-table-row", this.element.style.display = "flex", this.element.style.flexDirection = "row", this.element.style.flexWrap = "nowrap", this.element.style.position = "absolute", this.element.style.pointerEvents = "none", this.element.style.width = `${this.context.store.getColumnManager().getTotalWidth()}px`, n && this.raise(), this.updateStyles(), this.container.appendChild(this.element), this.bindEvents(), this.registerEvents();
}
/**
* 绑定触发事件
*/
bindEvents() {
this.element.addEventListener("mouseenter", () => {
this.context.event.emit(y.ROW_HIGHLIGHT, this.task.id);
}), this.element.addEventListener("mouseleave", () => {
this.context.event.emit(y.ROW_UNHIGHLIGHT, this.task.id);
}), this.element.addEventListener("click", (t) => {
this.context.store.getDataManager().isTaskSelected(this.task.id) || (this.context.store.getDataManager().selectTask(this.task.id), this.context.event.emit(y.ROW_CLICK, t, this.task));
}), this.element.addEventListener("dblclick", (t) => {
this.context.event.emit(y.ROW_DBL_CLICK, t, this.task);
}), this.element.addEventListener("contextmenu", (t) => {
t.preventDefault(), this.context.store.getDataManager().selectTask(this.task.id), this.context.event.emit(y.ROW_CONTEXTMENU, t, this.task.id);
});
}
/**
* 注册全局接收事件
*/
registerEvents() {
this.context.event.on(y.ROW_HIGHLIGHT, (t) => {
this.task.id === t ? this.element.classList.add("hover") : this.element.classList.remove("hover");
}), this.context.event.on(y.ROW_UNHIGHLIGHT, (t) => {
this.task.id === t && this.element.classList.remove("hover");
}), this.context.event.on(y.TASK_SELECTED, (t) => {
this.task.id === t.id && this.element.classList.add("selected");
}), this.context.event.on(y.TASK_UNSELECTED, (t) => {
this.task.id === t && this.element.classList.remove("selected");
});
}
/**
* 更新行样式
*/
updateStyles() {
this.updateTop(this.top), this.context.store.getDataManager().isTaskSelected(this.task.id), this.element.style.backgroundColor = this.context.store.getOptionManager().getRowBackgroundColor(this.task);
}
/**
* 对元素提级
*/
raise() {
this.element.style.zIndex = "2";
}
/**
* 更新 top 值
*/
updateTop(t) {
this.top = t;
const e = this.context.store.getOptionManager().getOptions().row.height;
this.element.style.top = `${-this.top + this.task.flatIndex * e}px`;
}
/**
* 创建单元格
*/
create() {
var i, s;
this.clearCells();
const t = this.context.store.getColumnManager().getHandlerColumn();
if (t.width !== 0) {
const n = new it(
this.context,
this.element,
t,
this.task,
this.task.flatIndex,
-1,
1,
1,
"handler"
);
this.cells.push(n);
}
const e = this.context.store.getColumnManager().getLeafColumns();
for (let n = 0; n < e.length; n++) {
const o = e[n], r = this.context.store.getColumnManager().getMergeInfo(this.task.id, n);
if (r) {
if (r.task.id !== this.task.id) {
const l = new it(
this.context,
this.element,
o,
this.task,
this.task.flatIndex,
n,
1,
1,
"empty"
);
this.element.style.backgroundColor = "transparent", this.raise(), this.cells.push(l);
} else if (r.originColumnIndex === n) {
const l = new it(
this.context,
this.element,
o,
r.task,
r.task.flatIndex,
n,
r.colspan,
r.rowspan
);
this.cells.push(l);
}
} else {
let l = 1, c = 1;
const g = (s = (i = o.column).merge) == null ? void 0 : s.call(
i,
this.task.getField(o.column.field),
this.task.data,
n,
this.task.level + 1
);
if (g && (typeof g.col != "number" ? L.error("colspan function must returned a number") : l = g.col, typeof g.row != "number" ? L.error("rowspan function must returned a number") : c = g.row), l > 1 || c > 1) {
if (c > 1)
for (let p = 1; p < c; p++) {
const u = this.context.store.getDataManager().getVisibleTasks()[this.task.flatIndex + p];
if (u && this.task.level !== u.level) {
c = p;
break;
}
}
const d = {
task: this.task,
originColumnIndex: n,
colspan: l,
rowspan: c
};
let m = this.task;
for (let p = c; p > 0; p--)
if (m) {
for (let u = 0; u < l; u++)
this.context.store.getColumnManager().addMergeInfo(m.id, u + n, d);
m = this.context.store.getDataManager().getVisibleTasks().at(m.flatIndex + 1);
}
for (let p = 0; p < l; p++)
this.context.store.getColumnManager().addMergeInfo(this.task.id, p + n, d);
}
const h = new it(
this.context,
this.element,
o,
this.task,
this.task.flatIndex,
n,
l,
c
);
this.cells.push(h);
}
}
this.context.store.getDataManager().isTaskSelected(this.task.id) && this.element.classList.add("selected");
}
/**
* 更新行
*/
update(t) {
this.task = t, this.create();
}
/**
* 更新宽度
*/
updateWidth() {
this.element.style.width = `${this.context.store.getColumnManager().getTotalWidth()}px`, this.cells.forEach((t) => t.updateWidth());
}
/**
* 清除单元格
*/
clearCells() {
for (this.cells.forEach((t) => t.remove()), this.cells = []; this.element.firstChild; )
this.element.removeChild(this.element.firstChild);
}
/**
* 移除行
*/
remove() {
this.clearCells(), this.element.parentNode && this.element.parentNode.removeChild(this.element);
}
}
class Ce {
constructor(t, e) {
a(this, "element");
a(this, "rows", /* @__PURE__ */ new Map());
a(this, "mergeRows", /* @__PURE__ */ new Map());
this.context = t, this.container = e, this.element = document.createElement("div"), this.element.className = "x-gantt-table-body", this.element.style.width = "100%", this.element.style.position = "relative", this.container.appendChild(this.element);
}
render(t, e) {
this.mergeRows.forEach((n) => n.remove()), this.mergeRows.clear();
const i = /* @__PURE__ */ new Set();
e.forEach((n) => {
i.add(n.id);
});
const s = [];
this.rows.forEach((n, o) => {
i.has(o) || s.push(o);
}), s.forEach((n) => {
const o = this.rows.get(n);
o && o.remove(), this.rows.delete(n);
}), e.forEach((n, o) => {
const r = n.id;
if (this.rows.has(r)) {
const l = this.rows.get(r);
l.update(n), l.updateTop(t);
} else {
const l = new bt(this.context, this.element, n, t);
l.create(), this.rows.set(r, l);
}
this.context.store.getColumnManager().getLeafColumns().forEach((l, c) => {
const g = this.context.store.getColumnManager().getMergeInfo(n.id, c);
if (g && g.rowspan > 1) {
const h = g.task.id;
if (!this.rows.has(h) && !this.mergeRows.has(h)) {
const d = new bt(
this.context,
this.element,
g.task,
t,
!0
);
d.create(), this.mergeRows.set(h, d);
}
}
});
});
}
/**
* 刷新所有行
*/
refresh(t, e) {
this.rows.forEach((i) => {
i.remove();
}), this.rows.clear(), this.render(t, e);
}
/**
* 更新任务
*/
updateTask(t) {
this.rows.has(t.id) && this.rows.get(t.id).update(t);
}
/** 更新全部行 */
update() {
this.rows.forEach((t) => {
t.create();
});
}
/**
* 更新列宽
*/
updateWidth() {
this.rows.forEach((t) => {
t.updateWidth();
}), this.mergeRows.forEach((t) => {
t.updateWidth();
});
}
}
class ct {
constructor(t, e, i, s) {
a(this, "columnElement");
this.context = t, this.root = e, this.container = i, this.column = s, this.columnElement = document.createElement("div"), this.initElement(), this.container.appendChild(this.columnElement);
}
initElement() {
const t = this.context.store.getColumnManager(), e = t.getColumnWidth(this.column.key), i = this.column.column.headerAlign || this.context.getOptions().table.headerAlign, s = this.column.column.ellipsis ?? this.context.getOptions().table.ellipsis ?? !0;
this.columnElement.className = "x-gantt-table-header-cell", (t.isMultiHeader() || this.context.getOptions().border.show) && this.columnElement.classList.add("border"), this.columnElement.style.height = "100%", this.columnElement.style.width = `${e}px`, this.columnElement.style.display = "flex", this.columnElement.style.flexShrink = "0", this.columnElement.style.alignItems = "center", this.columnElement.style.padding = "0 8px", this.columnElement.style.boxSizing = "border-box", this.columnElement.style.setProperty(
"border-color",
this.context.getOptions().border.color,
"important"
);
const n = document.createElement("div");
if (n.className = "x-gantt-table-header-cell__content", n.style.flex = "1", n.style.textAlign = i, n.style.overflow = "hidden", n.style.whiteSpace = "nowrap", s && (n.style.textOverflow = "ellipsis"), n.style.position = "relative", n.style.fontWeight = `${this.context.getOptions().header.fontWeight}`, n.style.fontSize = Q(
this.context.getOptions().header.fontSize
), n.style.setProperty(
"color",
this.context.getOptions().header.color,
"important"
), n.style.fontFamily = this.context.getOptions().header.fontFamily, this.column.column.headerRender) {
const o = this.column.column.headerRender();
typeof o == "string" ? n.innerHTML = o : o instanceof HTMLElement && (n.innerHTML = "", n.appendChild(o));
} else
n.textContent = this.column.label || this.column.column.label || "";
this.column.column.customStyle && Object.assign(n.style, this.column.column.customStyle), this.columnElement.appendChild(n), this.addResizeHandle();
}
/**
* 设置列宽
*/
setWidth(t) {
this.columnElement.style.width = `${t}px`, this.context.store.getColumnManager().setColumnWidth(this.column.key, t);
}
/**
* 添加拖拽把手
*/
addResizeHandle() {
if (this.column.column.resizable === !1 || this.context.store.getColumnManager().isLastColumn(this.column.key))
return;
const t = document.createElement("div");
t.className = "x-gantt-column-resize-handle", t.style.position = "absolute", t.style.top = "0", t.style.right = "0", t.style.width = "5px", t.style.height = "100%", t.style.cursor = "col-resize", t.style.zIndex = "2", this.columnElement.appendChild(t);
let e = 0, i = 0, s = null, n = 0;
const o = (c) => {
c.preventDefault(), c.stopPropagation(), e = c.clientX, i = this.columnElement.offsetWidth, s = this.root.getBoundingClientRect();
const g = (d) => r(d), h = (d) => l(d, g, h);
document.addEventListener("mousemove", g), document.addEventListener("mouseup", h), n = e - s.left, this.context.event.emit(y.SHOW_GUIDELINE, n);
}, r = (c) => {
if (c.preventDefault(), !s) return;
const g = c.clientX - e, h = i + g, d = Math.max(50, h), m = e - s.left - i, u = this.root.clientWidth - 20;
let x = m + d;
x = Math.min(u, x), this.context.event.emit(y.MOVE_GUIDELINE, x);
}, l = (c, g, h) => {
document.removeEventListener("mousemove", g), document.removeEventListener("mouseup", h), this.context.event.emit(y.HIDE_GUIDELINE);
const d = c.clientX - e, m = Math.max(50, i + d);
this.setWidth(m);
};
t.addEventListener("mousedown", o);
}
}
class ut {
constructor(t, e, i, s) {
a(this, "groupElement");
a(this, "titleContainer");
a(this, "childContainer");
a(this, "children", []);
this.context = t, this.root = e, this.container = i, this.column = s, this.groupElement = document.createElement("div"), this.titleContainer = document.createElement("div"), this.childContainer = document.createElement("div"), this.initElement(), this.initChildren(), this.container.appendChild(this.groupElement);
}
initElement() {
const e = this.context.getOptions().header.height / this.column.maxLevel;
this.groupElement.className = "x-gantt-table-header-group", (this.context.store.getColumnManager().isMultiHeader() || this.context.getOptions().border.show) && this.groupElement.classList.add("border"), this.groupElement.style.display = "flex", this.groupElement.style.flexShrink = "0", this.groupElement.style.flexGrow = "0", this.groupElement.style.flexDirection = "column", this.groupElement.style.height = "100%", this.groupElement.style.overflow = "hidden", this.groupElement.style.boxSizing = "border-box", this.titleContainer.className = "x-gantt-table-header-cell", (this.context.store.getColumnManager().isMultiHeader() || this.context.getOptions().border.show) && this.titleContainer.classList.add("border"), this.titleContainer.style.height = `${e}px`, this.titleContainer.style.flex = "0 0 auto", this.titleContainer.style.display = "flex", this.titleContainer.style.alignItems = this.context.getOptions().table.headerAlign, this.titleContainer.style.justifyContent = "center", this.titleContainer.style.padding = "0 8px", this.titleContainer.style.boxSizing = "border-box", this.titleContainer.style.overflow = "hidden", this.titleContainer.style.whiteSpace = "nowrap", this.context.getOptions().table.ellipsis && (this.titleContainer.style.textOverflow = "ellipsis"), this.titleContainer.style.borderBottom = `1px solid ${this.context.getOptions().border.color}`, this.titleContainer.style.setProperty(
"border-color",
this.context.getOptions().border.color,
"important"
), this.titleContainer.style.fontWeight = `${this.context.getOptions().header.fontWeight}`, this.titleContainer.style.fontSize = Q(
this.context.getOptions().header.fontSize
), this.titleContainer.style.fontFamily = this.context.getOptions().header.fontFamily, this.titleContainer.style.setProperty(
"color",
this.context.getOptions().header.color,
"important"
), this.titleContainer.textContent = this.column.label || "", this.childContainer.className = "x-gantt-table-header-children", this.childContainer.style.flex = "1 0 auto", this.childContainer.style.display = "flex", this.childContainer.style.width = "100%", this.groupElement.appendChild(this.titleContainer), this.groupElement.appendChild(this.childContainer);
}
initChildren() {
this.column.children.forEach((t) => {
if (t.isLeaf) {
const e = new ct(
this.context,
this.root,
this.childContainer,
t
);
this.children.push(e);
} else if (t.children.length > 0) {
const e = new ut(
this.context,
this.root,
this.childContainer,
t
);
this.children.push(e);
}
});
}
}
class De {
constructor(t, e) {
a(this, "headerElement");
a(this, "headerColumns", []);
this.context = t, this.container = e, this.headerElement = document.createElement("div"), this.initElement(), this.container.appendChild(this.headerElement);
}
initElement() {
this.headerElement.className = "x-gantt-table-header", this.headerElement.style.display = "flex", this.headerElement.style.height = `${this.context.getOptions().header.height}px`, this.headerElement.style.minHeight = `${Math.max(
this.context.getOptions().header.height,
30
)}px`, this.headerElement.style.setProperty(
"background-color",
this.context.getOptions().header.backgroundColor || this.context.getOptions().primaryColor,
"important"
), this.headerElement.style.setProperty(
"color",
this.context.getOptions().header.color,
"important"
), this.headerElement.style.fontSize = `${this.context.getOptions().header.fontSize}px`, this.headerElement.style.fontWeight = `${this.context.getOptions().header.fontWeight}`, this.headerElement.style.zIndex = "10", this.headerElement.style.width = "100%", this.headerElement.style.flexShrink = "0", this.headerElement.style.borderBottom = `1px solid ${this.context.getOptions().border.color}`, this.headerElement.style.setProperty(
"border-color",
this.context.getOptions().border.color,
"important"
);
}
/**
* 渲染表头
*/
render() {
this.headerColumns = [], this.headerElement.innerHTML = "", this.initElement();
const t = this.context.store.getColumnManager(), e = t.getColumns();
if (t.getHandlerColumn().width !== 0) {
const i = new ct(
this.context,
this.headerElement,
this.headerElement,
t.getHandlerColumn()
);
this.headerColumns.push(i);
}
e.forEach((i) => {
if (i.isLeaf) {
const s = new ct(
this.context,
this.headerElement,
this.headerElement,
i
);
this.headerColumns.push(s);
} else if (i.children.length > 0) {
const s = new ut(
this.context,
this.headerElement,
this.headerElement,
i
);
this.headerColumns.push(s);
}
});
}
}
class _e {
constructor(t, e) {
a(this, "tableContainer");
a(this, "tableHeader");
a(this, "tableBody");
this.context = t, this.container = e, this.tableContainer = document.createElement("div"), this.tableContainer.className = "x-gantt-table-container", this.tableContainer.style.position = "relative", this.tableContainer.style.width = "100%", this.tableContainer.style.height = "100%", this.tableContainer.style.overflow = "hidden", this.tableContainer.style.display = "flex", this.tableContainer.style.flexDirection = "column", this.container.appendChild(this.tableContainer), this.tableHeader = new De(t, this.tableContainer), this.tableBody = new Ce(t, this.tableContainer), this.listenEvents();
}
render(t, e) {
this.tableHeader.render(), this.refresh(t, e);
}
refresh(t, e) {
this.tableBody.render(t, e);
}
updateWidth() {
this.tableBody.updateWidth();
}
updateTask(t) {
this.tableBody.updateTask(t);
}
listenEvents() {
this.context.event.on(y.UPDATE_TABLE_HEADER, () => {
this.tableHeader.render();
}), this.context.event.on(y.UPDATE_TABLE_BODY, () => {
this.tableBody.update();
});
}
}
class He {
constructor(t, e) {
a(this, "layer");
a(this, "background");
// 表头背景
a(this, "groupHeader");
// 主表头 (年/月)
a(this, "cellHeader");
// 次表头 (月/日)
a(this, "cellCache", /* @__PURE__ */ new Map());
// 状态变量
a(this, "width", 0);
a(this, "height", 0);
a(this, "offsetX", 0);
this.context = t, this.stage = e, this.layer = new v.Layer(), this.stage.add(this.layer), this.background = new v.Rect({
fill: this.context.getOptions().header.backgroundColor || this.context.getOptions().primaryColor,
name: "header-background"
}), this.layer.add(this.background), this.groupHeader = new v.Group({ name: "primary-header" }), this.cellHeader = new v.Group({ name: "secondary-header" }), this.layer.add(this.groupHeader), this.layer.add(this.cellHeader), this.resize(this.stage.width()), this.registerEvents();
}
/**
* 调整表头大小
*/
resize(t) {
this.width = t, this.height = this.context.getOptions().header.height, this.background.width(t), this.background.height(this.height), this.calculateHeader();
}
/**
* 设置偏移量 (响应滚动)
* 表头只需要水平滚动,不需要垂直滚动
*/
setOffset(t, e) {
this.offsetX !== t && (this.offsetX = t, this.groupHeader.x(t), this.cellHeader.x(t), this.calculateHeader());
}
/**
* 注册事件监听
*/
registerEvents() {
this.context.event.on(y.ROW_HIGHLIGHT, (t) => {
this.highlightDate(t);
}), this.context.event.on(y.ROW_UNHIGHLIGHT, (t) => {
this.unhighlightDate(t);
}), this.context.event.on(y.UPDATE_TASK, (t) => {
this.highlightDate(t.id);
});
}
/**
* 渲染表头
*/
render() {
this.calculateHeader(), this.layer.moveToTop(), this.layer.batchDraw();
}
/**
* 计算并绘制表头
*/
calculateHeader() {
var c;
this.clearHeader();
const t = this.context.store.getTimeAxis(), e = t.getCellWidth(), i = Math.max(0, -this.offsetX), s = i + this.width, n = Math.floor(this.height / 2), o = this.context.getOptions().border.color;
this.layer.add(
new v.Line({
points: [0, n, this.width, n],
stroke: o,
strokeWidth: 1
})
), this.layer.add(
new v.Line({
points: [0, this.height, this.width, this.height],
stroke: o,
strokeWidth: 1
})
);
const r = t.getTimeline();
let l = 0;
for (let g = 0; g < r.length; g++) {
const h = r[g], d = e * (((c = h.children) == null ? void 0 : c.length) ?? 0);
if (l + d < i) {
l += d;
continue;
}
if (l > s)
break;
const p = this.createCell(
`group-${h.date.format("YYYY-MM-DD")}`,
l,
0,
d,
n,
o,
h.label
);
if (this.groupHeader.add(p), V(h.children) && h.children.length > 0) {
let u = l;
for (let x = 0; x < h.children.length; ) {
const w = h.children[x];
let E = 1;
for (; h.children[x + E] && w.label === h.children[x + E].label; )
E++;
if (x += E, x >= h.children.length && r[g + 1] && r[g + 1].children) {
let k = 0;
for (; r[g + 1].children[k] && w.label === r[g + 1].children[k].label; )
r[g + 1].children[k].hide = !0, k++;
k > 0 && (E += k);
}
const T = e * E;
if (u + T < i) {
u += T;
continue;
}
if (u > s)
break;
const C = this.createCell(
`cell-${w.date.format("YYYY-MM-DD")}`,
u,
n,
T,
n,
w.hide ? "transparent" : o,
w.hide ? "" : w.label
);
this.cellHeader.add(C), w.hide && C.visible(!1), u += T;
}
}
l += d;
}
this.layer.batchDraw();
}
createCell(t, e, i, s, n, o, r) {
const l = new v.Group();
l.x(e), l.y(i);
const c = new v.Rect({
id: t,
x: 0,
y: 0,
width: s,
height: n,
fill: this.context.getOptions().header.backgroundColor || this.context.getOptions().primaryColor,
name: "header-cell-bg"
});
l.add(c);
let g = this.context.getOptions().header.fontSize;
t.startsWith("cell-") && (this.cellCache.set(t, c), g -= 2);
const h = new v.Line({
points: [s, 0, s, n],
stroke: o,
strokeWidth: 1,
name: "header-cell-right-border"
});
l.add(h);
const d = new v.Text({
x: 0,
y: 0,
width: s,
height: n,
text: r,
fontSize: g,
fontFamily: this.context.getOptions().header.fontFamily,
fontStyle: `${this.context.getOptions().header.fontWeight}`,
fill: this.context.getOptions().header.color,
align: "center",
verticalAlign: "middle",
wrap: "none",
ellipsis: !0,
name: "header-cell-text"
});
return l.add(d), l;
}
/**
* 清除表头内容
*/
clearHeader() {
this.groupHeader.destroyChildren(), this.cellHeader.destroyChildren(), this.cellCache.clear();
}
/**
* 销毁表头层
*/
destroy() {
this.layer.destroy(), this.cellCache.clear();
}
/**
* 高亮日期
*/
highlightDate(t) {
const e = this.context.store.getDataManager().getTaskById(t);
e && e.startTime && e.endTime && this.handleHighlight("in", e);
}
/**
* 取消高亮日期
*/
unhighlightDate(t) {
const e = this.context.store.getDataManager().getTaskById(t);
e && e.startTime && e.endTime && this.handleHighlight("out", e);
}
// 拖拽块的高亮动画
handleHighlight(t, e) {
var o, r;
if (!this.context.getOptions().highlight || this.context.getOptions().unit !== "day") return;
const i = this.cellCache.get(
`cell-${(o = e == null ? void 0 : e.startTime) == null ? void 0 : o.format("YYYY-MM-DD")}`
), s = this.cellCache.get(
`cell-${(r = e == null ? void 0 : e.endTime) == null ? void 0 : r.format("YYYY-MM-DD")}`
), n = this.context.getOptions().header.backgroundColor || this.context.getOptions().primaryColor;
n && (this.cellCache.forEach((l) => {
new v.Tween({
node: l,
fill: n,
duration: 0.02
}).play();
}), t === "in" && (i && new v.Tween({
node: i,
fill: F(n).brighten(30).toHex(),
duration: 0.02
}).play(), s && new v.Tween({
node: s,
fill: F(n).brighten(30).toHex(),
duration: 0
}).play()));
}
}
class Ae {
constructor(t, e) {
// 网格线组
a(this, "verticalLines");
a(this, "horizontalLines");
// 状态变量
a(this, "width", 0);
a(this, "height", 0);
a(this, "offsetX", 0);
a(this, "offsetY", 0);
this.context = t, this.layer = e, this.verticalLines = new v.Group({ name: "vertical-grid-lines" }), this.horizontalLines = new v.Group({ name: "horizontal-grid-lines" }), this.layer.add(this.verticalLines), this.layer.add(this.horizontalLines);
}
/**
* 调整网格大小
*/
resize(t, e) {
this.width = t, this.height = e, this.clearGrid(), this.calculateGrid();
}
/**
* 设置偏移量 (响应滚动)
*/
setOffset(t, e) {
this.offsetX = t, this.offsetY = e, this.verticalLines.x(t), this.horizontalLines.y(e), this.calculateGrid();
}
/**
* 渲染网格
*/
render() {
this.layer.batchDraw();
}
/**
* 销毁网格层
*/
destroy() {
this.layer.destroy();
}
/**
* 计算网格位置
*/
calculateGrid() {
this.clearGrid();
const t = this.context.getOptions().header.height, e = this.width, i = this.context.store.getTimeAxis().getCellWidth(), s = this.context.getOptions().row.height, n = this.context.store.getDataManager().getVisibleSize(), o = n * s, r = Math.max(
0,
Math.floor(-this.offsetX / i) - 2
), l = Math.min(
this.context.store.getTimeAxis().getCellCount(),
Math.ceil((-this.offsetX + this.width) / i) + 2
), c = Math.max(
0,
Math.floor((-this.offsetY + t) / s) - 2
), g = Math.min(
n,
Math.ceil((-this.offsetY + this.height) / s) + 2
);
if (this.context.getOptions().border.show && ["day", "hour"].includes(this.context.getOptions().unit))
for (let h = r; h <= l; h++) {
const d = h * i, m = new v.Line({
points: [d, t, d, o + t],
stroke: this.context.getOptions().border.color,
strokeWidth: 0.5,
name: "vertical-grid-line"
});
this.verticalLines.add(m);
}
for (let h = c; h <= g; h++) {
const d = h * s + t, m = new v.Line({
points: [0, d, Math.max(this.width, e), d],
stroke: this.context.getOptions().border.color,
strokeWidth: 0.5,
name: "horizontal-grid-line"
});
this.horizontalLines.add(m);
}
}
/**
* 清除网格线
*/
clearGrid() {
this.verticalLines.destroyChildren(), this.horizontalLines.destroyChildren();
}
}
const vt = '<svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 15 15"><path fill="currentColor" fill-rule="evenodd" d="M5.5 4.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25m4 0a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25M10.625 7.5a1.125 1.125 0 1 1-2.25 0a1.125 1.125 0 0 1 2.25 0M5.5 8.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25m5.125 2.875a1.125 1.125 0 1 1-2.25 0a1.125 1.125 0 0 1 2.25 0M5.5 12.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25" clip-rule="evenodd"/></svg>';
class Ie {
constructor(t, e, i, s, n) {
a(this, "offsetX", 0);
a(this, "offsetY", 0);
a(this, "sliderGroup");
a(this, "slider");
a(this, "sliderBar", null);
a(this, "sliderType", "");
a(this, "leftHandleGroup", null);
a(this, "rightHandleGroup", null);
a(this, "progressGroup", null);
a(this, "handlerWidth", 10);
// 自动滚动相关变量
a(this, "autoMoveTimer", null);
a(this, "autoScrollTimer", null);
a(this, "autoExpandTimer", null);
a(this, "EDGE_THRESHOLD", 20);
// 边缘检测阈值,单位px
a(this, "SCROLL_STEP", 5);
// 每次滚动的步长,单位px
a(this, "MOVE_INTERVAL", 1e3 / 60);
// 移动间隔,单位ms,约60fps
a(this, "AUTO_EXPAND_INTERVAL", 500);
// 自动扩展间隔,单位ms
// 拖拽状态变量
a(this, "isDragging", !1);
a(this, "draggingDirection", "none");
// 记录拖拽时的原始数据
a(this, "oldTasks", []);
this.context = t, this.x = e, this.y = i, this.task = s, this.rowWidth = n, this.sliderGroup = new v.Group({
x: e,
y: i,
id: `chart-slider-bar-${s.id}`
}), this.render(), this.bindEvents();
}
update(t, e) {
this.x = t, this.y = e, this.sliderGroup.position({ x: t, y: e }), this.render();
}
setOffset(t, e) {
this.offsetX = t, this.offsetY = e;
}
/** 太多需要 function 的判断,搞一个统一的转换 */
unpackFunc(t) {
return this.context.store.getOptionManager().unpackFunc(t, this.task);
}
render() {
var p, u, x, w, E, T, O, C, k, S, b, D, I;
if (!this.task.startTime || !this.task.endTime) return;
if (this.task.endTime.isBefore(this.task.startTime)) {
L.error("The endTime of the current task is earlier than the startTime.", this.task);
return;
}
const t = this.context.getOptions().row.height, e = st(
this.unpackFunc(this.context.getOptions().bar.height),
t
), i = (t - e) / 2, s = this.context.store.getTimeAxis().getTimeLeft(this.task.startTime), o = this.context.store.getTimeAxis().getTimeLeft(this.task.endTime) - s, r = this.unpackFunc(this.context.getOptions().bar.backgroundColor) || this.context.getOptions().primaryColor, l = nt(
this.unpackFunc(this.context.getOptions().bar.radius)
), c = this.unpackFunc(this.context.getOptions().bar.shadowColor) || "rgba(0, 0, 0, 0.2)", g = this.unpackFunc(this.context.getOptions().bar.shadowBlur) || 0, h = this.unpackFunc(this.context.getOptions().bar.shadowOffsetX) || 0, d = this.unpackFunc(this.context.getOptions().bar.shadowOffsetY) || 0;
this.slider || (this.slider = new v.Group({
dragBoundFunc: (_) => {
let M = 0, A = Math.abs(this.rowWidth - this.slider.width());
if (this.context.getOptions().bar.move.link.parent === "strict" && this.task.parent) {
if (this.task.parent.startTime) {
const $ = this.task.parent.startTime;
M = this.context.store.getTimeAxis().getTimeLeft($);
}
if (this.task.parent.endTime) {
const $ = this.task.parent.endTime, R = this.context.store.getTimeAxis().getTimeLeft($);
A = Math.abs(R - this.slider.width());
}
}
return {
x: G(_.x, M, A),
y: this.y + i + this.offsetY
};
}
})), this.slider.position({ x: s, y: i }), this.slider.size({ width: o, height: e });
const m = !!this.unpackFunc(this.context.getOptions().bar.move.enabled) && (this.task.isSummary() ? this.context.getOptions().summary.move.enabled : !0);
if (this.slider.draggable(m), this.slider.on("mouseover", (_) => {
m && !this.isDragging && (_.target.getStage().container().style.cursor = "grab"), this.handleBarHighlight({
shadowColor: F(c).alpha(F(c).alpha() + 0.1).toHex(),
shadowBlur: Math.max((g || 1) * 2, 4),
shadowOffsetX: Math.max(h || 1, 2),
shadowOffsetY: Math.max((d || 1) * 1.5, 4)
}), this.context.event.emit(y.SLIDER_HOVER, _.evt, this.task);
}), this.slider.on("mouseout", (_) => {
m && !this.isDragging && (_.target.getStage().container().style.cursor = "default"), this.isDragging || this.handleBarHighlight({
shadowColor: c,
shadowBlur: g,
shadowOffsetX: h,
shadowOffsetY: d
}), this.context.event.emit(y.SLIDER_LEAVE, _.evt, this.task);
}), this.task.isMilestone()) {
this.sliderBar && !this.sliderType.startsWith("milestone") && (this.slider.destroyChildren(), this.sliderBar = null, this.progressGroup = null, this.leftHandleGroup = null, this.rightHandleGroup = null);
const _ = this.unpackFunc(this.context.getOptions().milestone.size), M = Math.min(_ || e, t / 2), A = this.unpackFunc(this.context.getOptions().milestone.color) || r, B = this.unpackFunc(this.context.getOptions().milestone.border.color), $ = this.unpackFunc(this.context.getOptions().milestone.border.width), R = this.unpackFunc(this.context.getOptions().milestone.shape);
if (!this.sliderBar) {
switch (R) {
case "triangle":
this.sliderBar = new v.RegularPolygon({
sides: 3,
radius: M,
rotation: 0,
fill: A,
stroke: B,
strokeWidth: $,
y: M / 3 * 2
// 居中
});
break;
case "circle":
this.sliderBar = new v.Circle({
radius: M,
fill: A,
stroke: B,
strokeWidth: $,
y: M / 2
// 居中
});
break;
case "star":
this.sliderBar = new v.Star({
numPoints: 5,
innerRadius: M / 2,
outerRadius: M,
fill: A,
stroke: B,
strokeWidth: $,
y: M / 2
// 居中
});
break;
case "diamond":
default:
this.sliderBar = new v.RegularPolygon({
sides: 4,
radius: M,
rotation: 0,
fill: A,
stroke: B,
strokeWidth: $,
y: M / 2
// 居中
});
}
if (this.slider.add(this.sliderBar), this.unpackFunc(this.context.getOptions().milestone.label.show)) {
const W = this.unpackFunc(this.context.getOptions().milestone.label.text), P = this.unpackFunc(this.context.getOptions().milestone.label.position), K = this.unpackFunc(this.context.getOptions().milestone.label.fontSize), $t = this.unpackFunc(this.context.getOptions().milestone.label.fontFamily), Ft = this.unpackFunc(this.context.getOptions().milestone.label.color), et = new v.Text({
height: e,
text: W,
fill: Ft || A,
fontSize: K,
fontFamily: $t
}), rt = et.measureSize(W);
et.width(rt.width);
const X = { x: 0, y: 0 };
switch (P) {
case "top-left":
X.x = -(12 + rt.width), X.y = -8;
break;
case "bottom-left":
X.x = -(12 + rt.width), X.y = 10;
break;
case "bottom-right":
X.x = 12, X.y = 10;
break;
case "top-right":
default:
X.x = 12, X.y = -8;
break;
}
et.setAttrs(X), this.slider.add(et);
}
}
this.sliderType = "milestone";
} else if (this.task.isSummary() && (this.context.getOptions().summary.mode === "always" || this.task.expanded)) {
this.sliderBar && this.sliderType !== "summary" && (this.slider.destroyChildren(), this.sliderBar = null, this.progressGroup = null, this.leftHandleGroup = null, this.rightHandleGroup = null);
const _ = this.unpackFunc(this.context.getOptions().summary.color) || r, M = t * 0.2, A = t * 0.3, B = ($) => new v.Shape({
sceneFunc: (R, W) => {
const P = A * 0.5;
R.beginPath(), R.moveTo(0, (t - M) / 2), R.lineTo(P, (t - M) / 2), R.lineTo(P, (t - M) / 2 + M), R.lineTo(0, (t - M) / 2 + M + A), R.lineTo(0, (t - M) / 2), R.rect(P, (t - M) / 2, $ - 2 * P, M), R.moveTo($ - P, (t - M) / 2), R.lineTo($, (t - M) / 2), R.lineTo($, (t - M) / 2 + M + A), R.lineTo($ - P, (t - M) / 2 + M), R.lineTo($ - P, (t - M) / 2), R.fillStrokeShape(W);
},
width: $,
fill: _,
shadowColor: c,
shadowBlur: g,
shadowOffsetX: h,
shadowOffsetY: d,
y: -(A + M) / 2 - i / 2
});
!this.sliderBar || this.sliderBar.width() !== o ? (this.sliderBar && this.sliderBar.destroy(), this.sliderBar = B(o), this.slider.add(this.sliderBar)) : this.sliderBar.setAttrs({
fill: _,
shadowColor: c,
shadowBlur: g,
shadowOffsetX: h,
shadowOffsetY: d
}), this.sliderType = "summary";
} else {
this.sliderBar && this.sliderType !== "bar" && (this.slider.destroyChildren(), this.sliderBar = null), this.sliderBar || (this.sliderBar = new v.Rect({
x: 0,
y: 0
}), this.slider.add(this.sliderBar), this.sliderType = "bar"), this.sliderBar.setAttrs({
width: o,
height: e,
fill: r,
cornerRadius: l
}), this.renderProgress(o, e);
const _ = (p = this.context.getOptions().bar.move.single) == null ? void 0 : p.icon, M = (u = this.context.getOptions().bar.move.single) == null ? void 0 : u.backgroundColor, A = M ? F(M).alpha(((x = this.context.getOptions().bar.move.single) == null ? void 0 : x.opacity) ?? 1).toHex() : F(r).brighten(30 * (this.unpackFunc((w = this.context.getOptions().bar.progress) == null ? void 0 : w.show) ? -1 : 1)).alpha(((E = this.context.getOptions().bar.move.single) == null ? void 0 : E.opacity) ?? 1).toHex();
if (!!this.unpackFunc((T = this.context.getOptions().bar.move.single) == null ? void 0 : T.left)) {
if (!this.leftHandleGroup) {
this.leftHandleGroup = new v.Group({
x: 0,
y: 0,
opacity: 0
}), this.slider.add(this.leftHandleGroup), this.leftHandleGroup.on("mousedown", (W) => {
this.resizeMove(W, "left");
}), this.leftHandleGroup.on("mouseover", (W) => {
setTimeout(() => {
W.target.getStage().container().style.cursor = "ew-resize";
}, 0);
}), this.leftHandleGroup.on("mouseout", (W) => {
this.isDragging || (W.target.getStage().container().style.cursor = "default");
});
const R = new v.Rect({
x: 0,
y: 0
});
this.leftHandleGroup.add(R), _ !== null && xt(_ || vt, this.handlerWidth, e).then((W) => {
var K;
const P = new v.Image({
image: W,
x: 0,
y: (e - this.handlerWidth) / 2,
width: this.handlerWidth,
height: this.handlerWidth
});
(K = this.leftHandleGroup) == null || K.add(P);
});
}
(O = this.leftHandleGroup.findOne("Rect")) == null || O.setAttrs({
width: this.handlerWidth,
height: e,
fill: A,
cornerRadius: [l[0], 0, 0, l[3]]
}), (C = this.leftHandleGroup.findOne("Image")) == null || C.setAttrs({
x: 0,
y: (e - this.handlerWidth) / 2,
width: this.handlerWidth,
height: this.handlerWidth
});
} else this.leftHandleGroup && (this.leftHandleGroup.remove(), this.leftHandleGroup = null);
if (!!this.unpackFunc((k = this.context.getOptions().bar.move.single) == null ? void 0 : k.right)) {
if (!this.rightHandleGroup) {
this.rightHandleGroup = new v.Group({
x: 0,
y: 0,
opacity: 0
}), this.slider.add(this.rightHandleGroup), this.rightHandleGroup.on("mousedown", (W) => {
this.resizeMove(W, "right");
}), this.rightHandleGroup.on("mouseover", (W) => {
setTimeout(() => {
W.target.getStage().container().style.cursor = "ew-resize";
}, 0);
}), this.rightHandleGroup.on("mouseout", (W) => {
this.isDragging || (W.target.getStage().container().style.cursor = "default");
});
const R = new v.Rect({
x: 0,
y: 0
});
this.rightHandleGroup.add(R), _ !== null && xt(_ || vt, this.handlerWidth, e).then((W) => {
var K;
const P = new v.Image({
image: W,
x: o - this.handlerWidth,
y: (e - this.handlerWidth) / 2,
width: this.handlerWidth,
height: this.handlerWidth
});
(K = this.rightHandleGroup) == null || K.add(P);
});
}
(S = this.rightHandleGroup.findOne("Rect")) == null || S.setAttrs({
x: o - this.handlerWidth,
width: this.handlerWidth,
height: e,
fill: A,
cornerRadius: [0, l[1], l[2], 0]
}), (b = this.rightHandleGroup.findOne("Image")) == null || b.setAttrs({
x: o - this.handlerWidth,
y: (e - this.handlerWidth) / 2,
width: this.handlerWidth,
height: this.handlerWidth
});
} else this.rightHandleGroup && (this.rightHandleGroup.remove(), this.rightHandleGroup = null);
this.renderText(o, e), (D = this.leftHandleGroup) == null || D.moveToTop(), (I = this.rightHandleGroup) == null || I.moveToTop();
}
this.isDragging || this.sliderBar.setAttrs({
shadowColor: c,
shadowBlur: g,
shadowOffsetX: h,
shadowOffsetY: d
}), this.sliderGroup.add(this.slider), this.unpackFunc(this.context.getOptions().bar.show) === !1 ? this.sliderGroup.hide() : this.sliderGroup.show();
}
renderText(t, e) {
const i = `chart-slider-text-${this.task.id}`, s = () => {
this.slider.find(`#${i}`) && this.slider.find(`#${i}`).forEach((l) => l.remove());
};
if (!this.context.getOptions().bar.field && !this.context.getOptions().bar.label) {
s();
return;
}
const n = this.context.getOptions().bar.label;
let o = "";
n ? o = this.unpackFunc(n) : this.context.getOptions().bar.field && (o = this.task.getField(this.context.getOptions().bar.field)), s();
const r = t - (this.leftHandleGroup ? this.handlerWidth : 0) - (this.rightHandleGroup ? this.handlerWidth : 0);
if (r > 20) {
const l = new v.Text({
id: i,
x: this.leftHandleGroup ? 10 : 0,
y: 0,
width: r,
height: e,
padding: 10,
text: o,
fill: this.unpackFunc(this.context.getOptions().bar.color) || "#000",
fontSize: this.unpackFunc(this.context.getOptions().bar.fontSize) || 12,
fontFamily: this.unpackFunc(this.context.getOptions().bar.fontFamily) || "Arial",
align: this.unpackFunc(this.context.getOptions().bar.align),
verticalAlign: this.unpackFunc(this.context.getOptions().bar.verticalAlign) || "middle",
ellipsis: !0
});
this.slider.add(l);
}
}
renderProgress(t, e) {
var i, s, n, o, r, l, c, g, h, d, m, p;
if (!this.unpackFunc((i = this.context.getOptions().bar.progress) == null ? void 0 : i.show)) {
this.progressGroup && (this.progressGroup.destroy(), this.progressGroup = null);
return;
}
if (this.task.progress) {
const u = jt(
this.task.progress,
((s = this.context.getOptions().bar.progress) == null ? void 0 : s.targetVal) ?? 100
);
if (u === 0) return;
const x = this.unpackFunc(
this.context.getOptions().bar.backgroundColor
) || this.context.getOptions().primaryColor, w = this.unpackFunc((n = this.context.getOptions().bar.progress) == null ? void 0 : n.backgroundColor) || F(x).brighten(((o = this.context.getOptions().bar.progress) == null ? void 0 : o.amount) || 30).toHex(), E = nt(
this.unpackFunc(this.context.getOptions().bar.radius)
), T = nt(
this.unpackFunc((r = this.context.getOptions().bar.progress) == null ? void 0 : r.radius),
2
// 默认 2
);
T[0] = E[0], T[3] = E[3], u === 1 && (T[1] = E[1], T[2] = E[2]);
const O = t * u;
this.progressGroup ? (this.progressGroup.width(O), this.progressGroup.destroyChildren()) : (this.progressGroup = new v.Group({
x: 0,
y: 0,
width: O,
height: e,
listening: !1
}), this.slider.add(this.progressGroup));
const C = new v.Rect({
x: 0,
y: 0,
width: O,
height: e,
fill: w,
cornerRadius: T,
opacity: this.unpackFunc((l = this.context.getOptions().bar.progress) == null ? void 0 : l.opacity)
});
this.progressGroup.add(C);
const k = `${lt(
u * 100,
(c = this.context.getOptions().bar.progress) == null ? void 0 : c.decimal
)}%`, S = new v.Text().measureSize(k).width, b = this.unpackFunc((g = this.context.getOptions().bar.progress) == null ? void 0 : g.textAlign), D = new v.Text({
x: 0,
y: b === "top" ? -e : 0,
width: b === "right" ? O + S : Math.max(O, S),
height: e,
fill: this.unpackFunc((h = this.context.getOptions().bar.progress) == null ? void 0 : h.color) || F("#000000").mix(w, 50).alpha(0.7).toHex(),
text: k,
fontSize: this.unpackFunc((d = this.context.getOptions().bar.progress) == null ? void 0 : d.fontSize) || 10,
fontStyle: this.unpackFunc((m = this.context.getOptions().bar.progress) == null ? void 0 : m.fontStyle) || "italic",
fontFamily: "Arial",
verticalAlign: b === "top" ? "bottom" : "middle",
align: "right"
});
(p = this.progressGroup) == null || p.add(D);
}
}
// 绑定事件,包括拖拽和边缘检测
bindEvents() {
this.slider && (this.slider.on("dragstart", (t) => this.handleDragStart(t)), this.slider.on("dragend", (t) => this.handleDragEnd(t)), this.slider.on("dragmove", (t) => this.handleDragMove(t)), this.slider.on("mouseover", () => this.handleMouseEnter()), this.slider.on("mouseout", () => this.handleMouseLeave()), this.slider.on("mousedown", (t) => {
if (t.evt.button !== 0) return;
const e = t.target.getStage();
e && this.slider.draggable() && (e.container().style.cursor = "grabbing");
}), this.slider.on("mouseup", (t) => {
if (t.evt.button !== 0) return;
const e = t.target.getStage();
e && this.slider.draggable() && (e.container().style.cursor = "grab");
}), this.slider.on("click", (t) => {
t.evt.button === 0 && (t.cancelBubble = !0, this.isDragging = !1, this.context.event.emit(y.SLIDER_CLICK, t.evt, this.task));
}), this.slider.on("contextmenu", (t) => {
t.cancelBubble = !0, t.evt.stopPropagation(), t.evt.preventDefault(), this.context.event.emit(y.SLIDER_CONTEXTMENU, t.evt, this.task);
}), this.slider.on("dblclick", (t) => {
t.evt.button === 0 && (t.cancelBubble = !0, this.context.event.emit(y.SLIDER_DBL_CLICK, t.evt, this.task));
}));
}
/**
* 移动后更新任务时间
*/
emitUpdate(t) {
let e = this.task.startTime.clone(), i = this.task.endTime.clone();
t !== "right" && (e = this.context.store.getTimeAxis().getTimeByLeft(this.slider.x())), t !== "left" && (i = this.context.store.getTimeAxis().getTimeByLeft(this.slider.x() + this.slider.width())), (!(e != null && e.isSame(this.task.startTime)) || !(i != null && i.isSame(this.task.endTime))) && this.context.store.getDataManager().updateTaskTime(this.task, e, i, t, this.oldTasks);
}
handleDragStart(t) {
const e = t.target.getStage();
e && (this.isDragging = !0, this.oldTasks = [], this.context.event.emit(y.SLIDER_MOVING, !0), e.container().style.cursor = "grabbing", this.handleMove(t, e));
}
handleDragMove(t) {
if (!this.isDragging) return;
if (t.evt.movementX > 0 ? this.draggingDirection = "right" : t.evt.movementX < 0 && (this.draggingDirection = "left"), !!this.context.getOptions().bar.move.byUnit) {
const i = t.target.x(), s = this.context.store.getTimeAxis().getCellWidth(), n = pt(i, s);
t.target.x(n);
}
}
handleDragEnd(t) {
this.stopAutoMove(), this.stopAutoScroll(), this.stopAutoExpand(), this.isDragging = !1, this.draggingDirection = "none", this.oldTasks.length > 0 && (this.context.event.emit(
y.TASK_DRAG_END,
this.task,
this.oldTasks
), this.oldTasks = []);
const e = t.target.getStage();
if (e) {
const i = e.getPointerPosition();
if (i) {
const s = this.context.getOptions().row.height, n = this.y + this.offsetY, o = n + s;
if (i.y < n || i.y > o) {
const r = this.unpackFunc(this.context.getOptions().bar.shadowColor) || "rgba(0, 0, 0, 0.2)", l = this.unpackFunc(this.context.getOptions().bar.shadowBlur) || 0, c = this.unpackFunc(this.context.getOptions().bar.shadowOffsetX) || 0, g = this.unpackFunc(this.context.getOptions().bar.shadowOffsetY) || 0;
this.handleBarHighlight({
shadowColor: r,
shadowBlur: l,
shadowOffsetX: c,
shadowOffsetY: g
}), this.handleResizeHighlight(0), e.container().style.cursor = "default";
}
}
}
this.context.event.emit(y.SLIDER_MOVING, !1);
}
handleMove(t, e) {
const i = e.width(), s = !!this.context.getOptions().bar.move.lock, n = !!this.context.getOptions().bar.move.byUnit, o = this.context.store.getTimeAxis().getCellWidth();
this.autoMoveTimer = window.setInterval(() => {
const r = t.target.width(), l = t.target.x() - this.offsetX, c = l + r, g = -this.offsetX, h = g + i, d = l <= g - this.offsetX + this.EDGE_THRESHOLD, m = c >= h - this.offsetX - this.EDGE_THRESHOLD;
if (d)
if (g <= 0)
t.target.x(0), this.stopAutoScroll(), s || (this.draggingDirection === "left" ? this.startAutoExpand("left") : this.stopAutoExpand());
else if (this.draggingDirection === "left") {
const p = n ? -o : -this.SCROLL_STEP;
this.startAutoScroll(p, n, () => {
t.target.x(t.target.x() + p);
});
} else
this.stopAutoScroll();
else if (m)
if (h >= this.context.store.getTimeAxis().getTotalWidth())
t.target.x(
this.context.store.getTimeAxis().getTotalWidth() - r
), this.stopAutoScroll(), s || (this.draggingDirection === "right" ? this.startAutoExpand("right") : this.stopAutoExpand());
else if (this.draggingDirection === "right") {
const p = n ? o : this.SCROLL_STEP;
this.startAutoScroll(p, n, () => {
t.target.x(t.target.x() + p);
});
} else
this.stopAutoScroll();
else
this.stopAutoExpand(), this.stopAutoScroll();
this.emitUpdate("both");
}, this.MOVE_INTERVAL);
}
// 左右操作拖拽
resizeMove(t, e) {
var x;
t.cancelBubble = !0;
const i = t.target.getStage();
if (!i) return;
this.isDragging = !0, this.context.event.emit(y.SLIDER_MOVING, !0);
let s = ((x = i.getPointerPosition()) == null ? void 0 : x.x) || 0;
const n = !!this.context.getOptions().bar.move.byUnit, o = this.context.store.getTimeAxis().getCellWidth(), r = !!this.context.getOptions().bar.move.lock, l = i.width();
let c = 0, g = 0;
this.autoMoveTimer = window.setInterval(() => {
const w = this.slider.width(), E = this.slider.x(), T = E + w, O = -this.offsetX, C = O + l, k = E <= O + this.EDGE_THRESHOLD, S = T >= C - this.EDGE_THRESHOLD;
if (k && e === "left") {
if (O <= 0)
this.slider.x(0), this.stopAutoScroll(), r || (this.draggingDirection === "left" ? this.startAutoExpand("left") : this.stopAutoExpand());
else if (this.draggingDirection === "left") {
const b = n ? -o : -this.SCROLL_STEP;
this.startAutoScroll(b, n, () => {
c += b, this.slider.x(this.slider.x() + b);
});
} else
this.stopAutoScroll();
this.emitUpdate("left");
} else if (S && e === "right") {
if (C >= this.context.store.getTimeAxis().getTotalWidth())
this.slider.width(
this.context.store.getTimeAxis().getTotalWidth() - this.slider.x()
), this.stopAutoScroll(), r || (this.draggingDirection === "right" ? this.startAutoExpand("right") : this.stopAutoExpand());
else if (this.draggingDirection === "right") {
const b = n ? o : this.SCROLL_STEP;
this.startAutoScroll(b, n, () => {
g += b, this.slider.x(this.slider.x() + b);
});
} else
this.stopAutoScroll();
this.emitUpdate("right");
} else if (e === "right" && E <= O && T <= O + this.EDGE_THRESHOLD + o) {
const b = n ? -o : -this.SCROLL_STEP;
this.startAutoScroll(b, n, () => {
g += b, this.slider.width(Math.max(this.slider.width(), o)), this.slider.width() > o && this.slider.x(this.slider.x() + b), this.emitUpdate("right");
});
} else if (e === "left" && T >= C && E >= C - this.EDGE_THRESHOLD - o) {
const b = n ? o : this.SCROLL_STEP;
this.startAutoScroll(b, n, () => {
c += b, this.slider.width(Math.max(this.slider.width(), o)), this.slider.width() > o && this.slider.x(this.slider.x() + b), this.emitUpdate("left");
});
} else
this.stopAutoExpand(), this.stopAutoScroll();
}, this.MOVE_INTERVAL);
let h;
const d = this.slider.x(), m = this.slider.width(), p = (w) => {
var O;
w.movementX > 0 ? this.draggingDirection = "right" : w.movementX < 0 && (this.draggingDirection = "left");
const E = Math.max(((O = i.getPointerPosition()) == null ? void 0 : O.x) || 0, 0);
let T = E - s;
n && (T = pt(T, o)), (h === void 0 || h !== T) && (e === "left" ? m - T - c >= o && E < l - this.EDGE_THRESHOLD && (this.slider.width(m - T - c), this.slider.x(d + T + c), this.emitUpdate("left")) : m + T + g >= o && E > this.EDGE_THRESHOLD && (this.slider.width(m + T + g), this.emitUpdate("right")), h = T);
}, u = () => {
this.handleDragEnd(t), document.removeEventListener("mousemove", p), document.removeEventListener("mouseup", u);
};
document.addEventListener("mousemove", p), document.addEventListener("mouseup", u);
}
// 开始自动扩展
startAutoExpand(t) {
if (this.autoExpandTimer) return;
const e = this.context.store.getTimeAxis();
this.autoExpandTimer = window.setInterval(() => {
e.expand(t, 1), this.context.event.emit(y.CHART_OFFSET_CHANGE), t === "left" && this.slider.x(0);
}, this.AUTO_EXPAND_INTERVAL);
}
// 开始自动滚动
startAutoScroll(t, e, i) {
if (this.autoScrollTimer) return;
const s = this.context.getScrollbar();
s && (this.autoScrollTimer = window.setInterval(
() => {
const n = s.getScrollPosition();
s.scrollTo({ x: n.x + t, y: n.y }, "drag"), i == null || i();
},
e ? 300 : this.MOVE_INTERVAL
));
}
// 停止自动移动
stopAutoMove() {
this.autoMoveTimer && (clearInterval(this.autoMoveTimer), this.autoMoveTimer = null);
}
// 停止自动滚动
stopAutoScroll() {
this.autoScrollTimer && (clearInterval(this.autoScrollTimer), this.autoScrollTimer = null);
}
// 停止自动扩展
stopAutoExpand() {
this.autoExpandTimer && (clearInterval(this.autoExpandTimer), this.autoExpandTimer = null);
}
// 鼠标进入
handleMouseEnter() {
this.handleResizeHighlight(1);
}
// 鼠标离开
handleMouseLeave() {
this.isDragging || this.handleResizeHighlight(0);
}
// 拖拽块的高亮动画
handleResizeHighlight(t) {
this.leftHandleGroup && new v.Tween({
node: this.leftHandleGroup,
opacity: t,
duration: 0.2
}).play(), this.rightHandleGroup && new v.Tween({
node: this.rightHandleGroup,
opacity: t,
duration: 0.2
}).play();
}
/** 鼠标移入高亮 */
handleBarHighlight(t) {
this.sliderBar && new v.Tween({
...t,
node: this.sliderBar,
duration: 0.2
}).play();
}
}
class Ge {
constructor(t, e, i, s, n, o, r) {
a(this, "row");
a(this, "slider");
a(this, "cacheKey", "");
this.context = t, this.task = e, this.width = o, this.height = r, this.row = new v.Group();
const l = new v.Rect({
x: s,
y: n,
width: o,
height: r,
id: i,
listening: !1
});
this.row.add(l), this.slider = new Ie(this.context, 0, n, this.task, this.width), this.row.add(this.slider.sliderGroup);
}
update(t, e) {
this.slider.update(t, e);
}
setOffset(t, e) {
this.slider.setOffset(t, e);
}
destroy() {
this.row.destroy();
}
}
class Re {
constructor(t, e, i, s) {
a(this, "rowsGroup");
// 包含所有行的容器
a(this, "rowsCache", /* @__PURE__ */ new Map());
a(this, "rowBgGroup");
// 行背景容器
// 状态变量
a(this, "width", 0);
a(this, "height", 0);
a(this, "offsetX", 0);
a(this, "offsetY", 0);
// 高亮相关
a(this, "highlightedRowId", null);
a(this, "highlightRect", null);
// 选中相关
a(this, "selectedRowId", null);
a(this, "selectedRect", null);
this.context = t, this.stage = e, this.layer = i, this.bgLayer = s, this.rowsGroup = new v.Group({ name: "chart-body-rows" }), this.layer.add(this.rowsGroup), this.rowBgGroup = new v.Group({ name: "chart-body-row-bgs" }), this.bgLayer.add(this.rowBgGroup), this.registerEvents(), this.bindEvents();
}
/**
* 调整大小
*/
resize(t, e) {
this.width = t, this.height = e;
}
/**
* 设置偏移量 (响应滚动)
*/
setOffset(t, e) {
const i = e - this.offsetY;
this.offsetX = t, this.offsetY = e, this.rowsGroup.x(t), this.rowsGroup.y(e), this.updateHighlightPosition(i), this.updateSelectedPosition(i);
}
/**
* 渲染主体内容
* @param tasks 任务数据
*/
render(t) {
const e = this.context.getOptions().row.height, i = Z();
this.rowBgGroup.destroyChildren(), t.forEach((s, n) => {
const o = `chart-row-${s.id}`;
let r = this.rowsCache.get(o);
const c = s.flatIndex * e + this.context.getOptions().header.height;
r ? (r.update(0, c), r.setOffset(this.offsetX, this.offsetY)) : (r = new Ge(
this.context,
s,
o,
0,
c,
this.width,
e
), r.setOffset(this.offsetX, this.offsetY), this.rowsGroup.add(r.row), this.rowsCache.set(o, r)), r.cacheKey = i, this.context.store.getDataManager().isTaskSelected(s.id) && this.selectRow(s.id);
const g = new v.Rect({
x: 0,
y: c + this.offsetY,
width: this.width,
height: e,
fill: this.context.store.getOptionManager().getRowBackgroundColor(s),
id: `chart-row-bg-${s.id}`,
listening: !1
// 不需要监听事件
});
this.rowBgGroup.add(g), this.rowBgGroup.moveToBottom();
}), this.rowsCache.forEach((s, n) => {
s.cacheKey !== i && (s.destroy(), this.rowsCache.delete(n));
}), this.layer.batchDraw();
}
/**
* 更新任务
*/
updateTask(t) {
const e = this.rowsCache.get(`chart-row-${t.id}`);
e && e.update(
0,
t.flatIndex * this.context.getOptions().row.height + this.context.getOptions().header.height
);
}
/**
* 添加 body 事件
*/
bindEvents() {
this.stage.on("mousemove", this.handleMouseMove.bind(this)), this.stage.on("mouseleave", this.handleMouseLeave.bind(this)), this.stage.on("click", this.handleClick.bind(this)), this.stage.on("dblclick", this.handleDblClick.bind(this)), this.stage.on("contextmenu", this.handleContextMenu.bind(this));
}
/**
* 注册事件监听
*/
registerEvents() {
this.context.event.on(y.ROW_HIGHLIGHT, (t) => {
this.highlightRow(t);
}), this.context.event.on(y.ROW_UNHIGHLIGHT, (t) => {
this.unhighlightRow(t);
}), this.context.event.on(y.TASK_SELECTED, (t) => {
this.selectRow(t.id);
}), this.context.event.on(y.TASK_UNSELECTED, (t) => {
this.unselectRow(t);
});
}
/**
* 处理鼠标移动
*/
handleMouseMove(t) {
const e = this.stage.getPointerPosition();
if (!e) return;
const i = this.getTaskByPosition(e);
this.highlightedRowId && i && i.id !== this.highlightedRowId && this.context.event.emit(
y.ROW_UNHIGHLIGHT,
this.highlightedRowId
), i && this.context.event.emit(y.ROW_HIGHLIGHT, i.id);
}
/**
* 处理鼠标离开
*/
handleMouseLeave(t) {
this.unhighlightRow();
}
/**
* 处理点击
*/
handleClick(t) {
if (t.evt.button !== 0) return;
const e = this.stage.getPointerPosition();
if (!e) return;
const i = this.getTaskByPosition(e);
if (i) {
if (this.context.store.getDataManager().isTaskSelected(i.id)) return;
this.context.store.getDataManager().selectTask(i.id), this.context.event.emit(y.ROW_CLICK, t.evt, i);
}
}
/**
* 处理双击
*/
handleDblClick(t) {
if (t.evt.button !== 0) return;
const e = this.stage.getPointerPosition();
if (!e) return;
const i = this.getTaskByPosition(e);
i && this.context.event.emit(y.ROW_DBL_CLICK, t.evt, i);
}
/**
* 处理右键菜单
*/
handleContextMenu(t) {
if (t.evt.button !== 2) return;
t.evt.preventDefault(), t.cancelBubble = !0;
const e = this.stage.getPointerPosition();
if (!e) return;
const i = this.getTaskByPosition(e);
i && this.context.event.emit(y.ROW_CONTEXTMENU, t.evt, i);
}
/**
* 按照位置获取任务
*/
getTaskByPosition(t) {
const e = this.context.getOptions().header.height;
if (t.y <= e) return null;
const i = t.y - this.offsetY, s = Math.floor(
(i - e) / this.context.getOptions().row.height
);
return this.context.store.getDataManager().getVisibleTasks()[s] || null;
}
/**
* 高亮指定行
*/
highlightRow(t) {
if (this.highlightedRowId === t) return;
this.highlightedRowId = t;
const e = this.rowsCache.get(`chart-row-${t}`);
if (!e) return;
this.highlightRect && this.highlightRect.destroy();
const s = e.task.flatIndex * this.context.getOptions().row.height + this.context.getOptions().header.height;
this.selectedRowId !== t && (this.highlightRect = new v.Rect({
x: 0,
y: s + this.offsetY,
width: this.width,
height: this.context.getOptions().row.height,
fill: F(this.context.getOptions().row.hover.backgroundColor).alpha(this.context.getOptions().row.hover.opacity).toHex(),
name: "highlight-rect"
}), this.layer.add(this.highlightRect), this.highlightRect.moveToBottom(), this.layer.batchDraw());
}
/**
* 取消行高亮
*/
unhighlightRow(t) {
this.highlightedRowId === t && (this.highlightedRowId = null, this.highlightRect && (this.highlightRect.destroy(), this.highlightRect = null, this.layer.batchDraw()));
}
/**
* 更新高亮矩形的位置
*/
updateHighlightPosition(t) {
if (!this.highlightRect || this.highlightedRowId === null) return;
const e = this.rowsCache.get(`chart-row-${this.highlightedRowId}`);
if (!e) {
this.clearHighlight();
return;
}
if (t)
this.highlightRect.y(this.highlightRect.y() + t);
else {
const s = e.task.flatIndex * this.context.getOptions().row.height + this.context.getOptions().header.height;
this.highlightRect.y(s + this.offsetY);
}
this.layer.batchDraw();
}
/**
* 清除内容
*/
clearHighlight() {
this.highlightRect && (this.highlightRect.destroy(), this.highlightRect = null), this.highlightedRowId = null;
}
/**
* 选中指定行
*/
selectRow(t) {
var n;
this.selectedRowId = t;
const e = this.rowsCache.get(`chart-row-${t}`);
if (!e) return;
this.selectedRect && this.selectedRect.destroy(), this.selectedRowId === this.highlightedRowId && ((n = this.highlightRect) == null || n.fill("transparent"));
const s = e.task.flatIndex * this.context.getOptions().row.height + this.context.getOptions().header.height;
this.selectedRect = new v.Rect({
x: 0,
y: s + this.offsetY,
width: this.width,
height: this.context.getOptions().row.height,
fill: F(this.context.getOptions().row.select.backgroundColor).alpha(this.context.getOptions().row.select.opacity).toHex(),
name: "selected-rect"
}), this.layer.add(this.selectedRect), this.selectedRect.moveToBottom(), this.layer.batchDraw();
}
/**
* 取消选中指定行
*/
unselectRow(t) {
this.selectedRowId === t && (this.selectedRowId = null, this.selectedRect && (this.selectedRect.destroy(), this.selectedRect = null, this.layer.batchDraw()));
}
/**
* 更新选中矩形的位置
*/
updateSelectedPosition(t) {
if (!this.selectedRect || this.selectedRowId === null) return;
const e = this.rowsCache.get(`chart-row-${this.selectedRowId}`);
if (e)
if (this.context.store.getDataManager().isTaskVisible(e.task)) {
const s = e.task.flatIndex * this.context.getOptions().row.height + this.context.getOptions().header.height;
this.selectedRect.y(s + this.offsetY), this.layer.batchDraw();
} else
this.selectedRect.destroy(), this.selectedRect = null, this.selectedRowId = null;
}
/**
* 销毁层
*/
destroy() {
this.rowsCache.clear(), this.rowsGroup.destroy(), this.rowBgGroup.destroy();
}
}
class Wt {
constructor() {
}
static async createPattern(t) {
if (!(t != null && t.pattern)) return null;
const e = t.patternOptions || {};
switch (e.color = e.color || t.backgroundColor, t.pattern) {
case "stripe":
return this.createStripePattern(e);
case "dot":
return this.createDotPattern(e);
case "grid":
return this.createGridPattern(e);
case "custom":
if (e.image) {
const i = new Image();
return i.src = e.image, new Promise((s) => {
i.onload = () => s(i);
});
}
return null;
default:
return null;
}
}
/**
* 创建条纹图案
*/
static createStripePattern(t) {
const {
color: e = (t == null ? void 0 : t.color) || "#c9c9c9",
width: i = (t == null ? void 0 : t.width) || 1,
angle: s = (t == null ? void 0 : t.angle) ?? 30,
spacing: n = (t == null ? void 0 : t.spacing) || 10
} = t || {}, o = s % 180, r = o * Math.PI / 180;
let l, c;
o === 0 ? (l = n, c = i + n) : o === 90 ? (l = i + n, c = n) : (l = Math.abs(Math.ceil((i + n) / Math.sin(r))), c = Math.abs(Math.ceil((i + n) / Math.cos(r))));
const g = new v.Stage({
container: document.createElement("div"),
width: l,
height: c
}), h = new v.Layer();
g.add(h);
const d = new v.Group();
if (o === 0 || o === 90) {
const p = new v.Line({
points: [0, 0, o === 0 ? l : 0, o === 0 ? 0 : c],
stroke: e,
strokeWidth: i,
perfectDrawEnabled: !0
});
d.add(p);
} else
for (let p = -l; p < l * 2; p += l) {
const u = p + i / 2, x = 0, w = p + i / 2 + (Math.cos(r) < 0 ? -l : l), E = c, T = new v.Line({
points: [Math.ceil(u), Math.ceil(x), Math.ceil(w), Math.ceil(E)],
stroke: e,
strokeWidth: i,
perfectDrawEnabled: !0,
lineCap: "square",
lineJoin: "miter"
});
d.add(T);
}
h.add(d), h.draw();
const m = new Image();
return m.src = g.toDataURL(), g.destroy(), m;
}
/**
* 创建圆点图案
*/
static createDotPattern(t) {
const {
color: e = (t == null ? void 0 : t.color) || "#f9f9f9",
width: i = (t == null ? void 0 : t.width) || 2,
spacing: s = (t == null ? void 0 : t.spacing) || 4
} = t || {}, n = i * 2 + s * 2, o = n, r = F(e), l = new v.Stage({
container: document.createElement("div"),
width: n,
height: o
}), c = new v.Layer();
l.add(c), [
{ x: s / 2 + i / 2, y: s / 2 + i / 2 },
{
x: n - s / 2 - i / 2,
y: s / 2 + i / 2
},
{
x: s / 2 + i / 2,
y: o - s / 2 - i / 2
},
{
x: n - s / 2 - i / 2,
y: o - s / 2 - i / 2
}
].forEach((d) => {
const m = new v.Circle({
x: d.x,
y: d.y,
radius: i / 2,
fill: r.toString()
});
c.add(m);
}), c.draw();
const h = new Image();
return h.src = l.toDataURL(), l.destroy(), h;
}
/**
* 创建网格图案
*/
static createGridPattern(t) {
const {
color: e = (t == null ? void 0 : t.color) || "#f9f9f9",
width: i = (t == null ? void 0 : t.width) || 1,
spacing: s = (t == null ? void 0 : t.spacing) || 20
} = t || {}, n = i + s, o = n, r = n, l = new v.Stage({
container: document.createElement("div"),
width: o,
height: r
}), c = new v.Layer();
l.add(c);
const g = new v.Group();
g.add(
new v.Line({
points: [0, 0, o, r],
stroke: e,
strokeWidth: i,
perfectDrawEnabled: !0
})
), g.add(
new v.Line({
points: [0, r, o, 0],
stroke: e,
strokeWidth: i,
perfectDrawEnabled: !0
})
), c.add(g), c.draw();
const h = new Image();
return h.src = l.toDataURL(), l.destroy(), h;
}
}
class We {
constructor(t, e) {
// 状态变量
a(this, "width", 0);
a(this, "height", 0);
a(this, "offsetX", 0);
a(this, "offsetY", 0);
// 保存周末
a(this, "weekendGroup");
a(this, "patternImage", null);
this.context = t, this.layer = e, this.weekendGroup = new v.Group(), this.layer.add(this.weekendGroup);
}
/**
* 检查日期是否为周末
*/
isWeekend(t) {
return t.day() === 6 || t.day() === 0;
}
/**
* 调整周末大小
*/
resize(t, e) {
this.width = t, this.height = e, this.calculateWeekend();
}
/**
* 设置偏移量 (响应滚动)
*/
setOffset(t, e) {
this.offsetX = t, this.offsetY = e, this.weekendGroup.x(t), this.weekendGroup.y(e), this.calculateWeekend();
}
/**
* 渲染周末
*/
render() {
this.layer.batchDraw();
}
/**
* 销毁周末层
*/
destroy() {
this.weekendGroup.destroy(), this.patternImage = null;
}
clearWeekend() {
this.weekendGroup.destroyChildren(), this.patternImage = null;
}
/**
* 计算周末
*/
async calculateWeekend() {
if (this.clearWeekend(), !this.context.getOptions().weekend.show) return;
const t = this.context.store.getTimeAxis().getStartTime(), e = this.context.store.getTimeAxis().getEndTime(), i = this.context.store.getTimeAxis().getCellUnit(), s = this.context.store.getTimeAxis().getCellWidth(), n = this.context.getOptions().header.height, o = this.context.getOptions().row.height, l = this.context.store.getDataManager().getVisibleSize() * o, c = Math.max(0, -this.offsetX), g = c + this.width;
for (let h = t; h <= e; ) {
let d = s;
if (d = s * 2 * (i === "day" ? 1 : 24), this.isWeekend(h)) {
const m = this.context.store.getTimeAxis().getTimeLeft(h), p = n, u = l;
if (m + d < c) {
h = h.add(2, "day");
continue;
}
if (m > g)
break;
!this.patternImage && this.context.getOptions().weekend.pattern && (this.patternImage = await Wt.createPattern(
this.context.getOptions().weekend
));
const w = new v.Rect({
name: "weekend-rect",
x: m,
y: p,
width: d,
height: u,
// 根据模式设置填充
...this.patternImage ? {
fillPatternImage: this.patternImage,
fillPatternRepeat: "repeat",
fillPatternOffset: { x: 0, y: 0 },
fillPatternScale: { x: 1, y: 1 }
} : {
fill: this.context.getOptions().weekend.backgroundColor || "#c9c9c9"
},
opacity: this.context.getOptions().weekend.opacity
});
this.weekendGroup.add(w), h = h.add(2, "day");
} else
h = h.add(1, "day");
}
this.layer.batchDraw();
}
}
class $e {
constructor(t, e, i) {
a(this, "arrowAnimation");
a(this, "todayLine");
a(this, "triangle");
// 状态变量
a(this, "width", 0);
a(this, "height", 0);
a(this, "offsetX", 0);
a(this, "offsetY", 0);
this.context = t, this.bgLayer = e, this.headerLayer = i;
}
/**
* 调整大小
*/
resize(t, e) {
this.width = t, this.height = e, this.render();
}
/**
* 设置偏移量 (响应滚动)
*/
setOffset(t, e) {
t !== this.offsetX && (this.offsetX = t, this.render());
}
/**
* 渲染今日线
*/
render() {
const t = Object.assign(
{
show: !0,
type: "line",
backgroundColor: F("lightblue").toHex(),
opacity: 1,
width: 1
},
this.context.getOptions().today || {}
);
if (!t.show) return;
let e = H();
const i = this.context.store.getTimeAxis().getCellUnit();
t.type === "block" && (e = e.startOf(i));
const s = this.context.store.getTimeAxis().getTimeLeft(e), n = this.context.store.getTimeAxis().getCellWidth(), o = this.context.getOptions().header.height, r = F(t.backgroundColor).alpha(t.opacity).toHex(), l = (t.type === "block" ? s + n / 2 : s) + this.offsetX, c = [l, o, l, this.height], g = t.type === "line" ? t.width : n;
this.todayLine ? (this.todayLine.points(c), this.todayLine.stroke(r), this.todayLine.strokeWidth(g)) : (this.todayLine = new v.Line({
points: c,
stroke: r,
strokeWidth: g
}), this.bgLayer.add(this.todayLine)), t.type === "line" && (this.triangle ? (this.triangle.x(l), this.triangle.fill(r)) : (this.triangle = new v.RegularPolygon({
x: l,
y: o - 8,
sides: 3,
radius: 8,
fill: r,
rotation: 180,
name: "today-triangle"
}), this.arrowAnimation = new v.Animation((h) => {
var m;
const d = Math.sin(h.time * 4 * Math.PI / 2e3) + o - 8;
(m = this.triangle) == null || m.y(d);
}, this.headerLayer), this.headerLayer.add(this.triangle), this.triangle.moveToTop(), this.arrowAnimation.start())), this.bgLayer.batchDraw();
}
/**
* 销毁今日线
*/
destroy() {
var t, e, i;
(t = this.todayLine) == null || t.destroy(), (e = this.triangle) == null || e.destroy(), (i = this.arrowAnimation) == null || i.stop(), this.arrowAnimation = void 0;
}
}
class Fe {
constructor(t, e) {
// 状态变量
a(this, "width", 0);
a(this, "height", 0);
a(this, "offsetX", 0);
a(this, "offsetY", 0);
// 保存假期
a(this, "holidayGroup");
a(this, "patternImage", /* @__PURE__ */ new WeakMap());
this.context = t, this.layer = e, this.holidayGroup = new v.Group(), this.layer.add(this.holidayGroup);
}
/**
* 调整假期大小
*/
resize(t, e) {
this.width = t, this.height = e, this.calculateHoliday();
}
/**
* 设置偏移量 (响应滚动)
*/
setOffset(t, e) {
this.offsetX = t, this.offsetY = e, this.holidayGroup.x(t), this.holidayGroup.y(e), this.calculateHoliday();
}
/**
* 渲染假期
*/
render() {
this.layer.batchDraw();
}
/**
* 销毁假期层
*/
destroy() {
this.holidayGroup.destroy();
}
clearHoliday() {
this.holidayGroup.destroyChildren();
}
/**
* 计算假期
*/
async calculateHoliday() {
if (this.clearHoliday(), !this.context.getOptions().holiday.show) return;
const t = this.context.getOptions().holiday.holidays;
if (!t || t.length === 0) return;
const e = Math.max(0, -this.offsetX), i = e + this.width, s = this.context.store.getTimeAxis().getStartTime(), n = this.context.store.getTimeAxis().getEndTime();
this.context.store.getTimeAxis().getCellUnit();
const o = this.context.store.getTimeAxis().getCellWidth(), r = this.context.getOptions().header.height, l = this.context.getOptions().row.height, g = this.context.store.getDataManager().getVisibleSize() * l;
for (let h = s; h <= n; h = h.add(1, "day")) {
const d = t.find((m) => {
if (V(m.date)) {
if (m.date.some((p) => H(p).isSame(h, "day")))
return m;
} else if (H(m.date).isSame(h, "day"))
return m;
});
if (d) {
const m = this.context.store.getTimeAxis().getTimeLeft(h), p = r, u = g;
if (m + o < e)
continue;
if (m > i)
break;
!this.patternImage.has(d) && (d.pattern || this.context.getOptions().holiday.pattern) && this.patternImage.set(
d,
await Wt.createPattern({
backgroundColor: this.context.getOptions().primaryColor,
...d,
...this.context.getOptions().holiday
})
);
const w = new v.Rect({
name: "holiday-rect",
x: m,
y: p,
width: o,
height: u,
// 根据模式设置填充
...this.patternImage.get(d) ? {
fillPatternImage: this.patternImage.get(d) ?? void 0,
fillPatternRepeat: "repeat",
fillPatternOffset: { x: 0, y: 0 },
fillPatternScale: { x: 1, y: 1 },
opacity: d.opacity || this.context.getOptions().holiday.opacity
} : {
fill: d.backgroundColor || this.context.getOptions().holiday.backgroundColor || this.context.getOptions().primaryColor,
opacity: d.opacity || this.context.getOptions().holiday.opacity
}
});
this.holidayGroup.add(w);
}
}
this.layer.batchDraw();
}
}
class Be {
constructor(t, e, i) {
a(this, "tasks", []);
// 创建点组
a(this, "pointGroup");
// 关联线组
a(this, "linksGroup");
// 临时箭头
a(this, "templateArrow");
a(this, "isDragging", !1);
a(this, "isSliderMoving", !1);
// 选中的连线
a(this, "selectedMap", /* @__PURE__ */ new Map());
// 状态变量
a(this, "width", 0);
a(this, "height", 0);
a(this, "offsetX", 0);
a(this, "offsetY", 0);
this.context = t, this.stage = e, this.layer = i, this.linksGroup = new v.Group({ name: "links-group" }), this.pointGroup = new v.Group({ name: "point-group" }), this.templateArrow = new v.Arrow({
points: [],
stroke: this.context.getOptions().links.color || this.context.getOptions().primaryColor,
strokeWidth: this.context.getOptions().links.width,
pointerLength: this.context.getOptions().links.arrow.height,
// 箭头长度
pointerWidth: this.context.getOptions().links.arrow.width,
// 箭头宽度
fill: this.context.getOptions().links.arrow.color || this.context.getOptions().links.color || this.context.getOptions().primaryColor,
// 箭头填充色
lineJoin: "round",
dash: this.context.getOptions().links.dash,
opacity: 0.4
}), this.templateArrow.visible(!1), this.layer.add(this.linksGroup), this.layer.add(this.pointGroup), this.layer.add(this.templateArrow), this.registerEvents();
}
/**
* 注册事件
*/
registerEvents() {
this.context.event.on(y.ROW_HIGHLIGHT, (t) => {
this.highlightPoint(t);
}), this.context.event.on(y.ROW_UNHIGHLIGHT, (t) => {
this.unhighlightPoint(t);
}), this.context.event.on(y.SLIDER_MOVING, (t) => {
this.isSliderMoving = t;
});
}
/**
* 调整关联线大小
*/
resize(t, e) {
this.width = t, this.height = e, this.calculateLinks(), this.calculatePoints();
}
/**
* 设置偏移量 (响应滚动)
*/
setOffset(t, e) {
this.offsetX = t, this.offsetY = e, this.linksGroup.x(t), this.linksGroup.y(e), this.pointGroup.x(t), this.pointGroup.y(e), this.templateArrow.x(t), this.templateArrow.y(e), this.calculateLinks(), this.calculatePoints();
}
/**
* 更新数据
*/
update() {
this.calculateLinks(), this.calculatePoints();
}
/**
* 渲染关联线
*/
render(t) {
this.tasks = t, this.update();
}
/**
* 销毁关联线
*/
destroy() {
this.linksGroup.destroy(), this.pointGroup.destroy(), this.templateArrow.destroy(), this.selectedMap.clear();
}
/**
* 计算点组位置
*/
calculatePoints() {
if (this.pointGroup.destroyChildren(), !this.context.getOptions().links.create.enabled) return;
const t = this.context.getOptions().header.height, e = this.context.getOptions().row.height, i = e / 2 + t, s = this.context.getOptions().links.create.radius, n = this.context.getOptions().links.create.mode === "always" ? 0.5 : 0, o = this.context.getOptions().links.create.color || this.context.getOptions().primaryColor, r = F(o).alpha(this.context.getOptions().links.create.opacity ?? 1).toHex(), l = this.context.getOptions().links.create.width;
this.tasks.forEach((c) => {
if (this.context.store.getOptionManager().unpackFunc(this.context.getOptions().bar.show, c) && this.context.store.getDataManager().isTaskVisible(c) && c.startTime && c.endTime) {
const g = this.context.store.getTimeAxis().getTimeLeft(c.startTime), h = this.context.store.getTimeAxis().getTimeLeft(c.endTime);
let d = this.context.getOptions().links.gap;
c.isMilestone() && (d += e / 2);
const m = i + e * c.flatIndex;
let p = !0, u = !0, x = this.context.store.getOptionManager().unpackFunc(this.context.getOptions().links.create.from, c);
if (mt(x) ? p = u = x : U(x) && (p = x === "S", u = x === "F"), p) {
const w = new v.Circle({
id: `point-${c.id}-left`,
x: g - d,
y: m,
radius: s,
opacity: n,
stroke: r,
strokeWidth: l
});
this.pointGroup.add(w), w.on("mousedown", (E) => {
this.isDragging = !0, this.createLink(E, "S", o, [g - d, m], c.id);
}), w.on("mouseover", (E) => {
this.isSliderMoving || (this.stage.container().style.cursor = "pointer");
}), w.on("mouseout", (E) => {
this.isDragging || this.isSliderMoving || (this.stage.container().style.cursor = "default");
});
}
if (u) {
const w = new v.Circle({
id: `point-${c.id}-right`,
x: h + d,
y: m,
radius: s,
opacity: n,
stroke: r,
strokeWidth: l
});
this.pointGroup.add(w), w.on("mousedown", (E) => {
this.isDragging = !0, this.createLink(E, "F", o, [h + d, m], c.id);
}), w.on("mouseover", (E) => {
this.isSliderMoving || (this.stage.container().style.cursor = "pointer");
}), w.on("mouseout", (E) => {
this.isDragging || this.isSliderMoving || (this.stage.container().style.cursor = "default");
});
}
}
});
}
/**
* 计算关联线位置
*/
calculateLinks() {
if (this.linksGroup.destroyChildren(), !this.context.getOptions().links.show) return;
const t = this.context.getOptions().links.data, e = [];
t.forEach((i) => {
const s = this.createId(i);
this.selectedMap.has(s) && e.push(s);
}), this.selectedMap.forEach((i, s) => {
e.includes(s) || this.selectedMap.delete(s);
}), t.forEach((i) => {
var o, r, l;
const s = this.context.store.getDataManager().getTaskById(i.from), n = this.context.store.getDataManager().getTaskById(i.to);
if (s || L.warn(
`No corresponding FROM task [${i.from}] was found for the link. Info:`,
i
), n || L.warn(
`No corresponding TO task [${i.to}] was found for the link. Info:`,
i
), s && this.context.store.getOptionManager().unpackFunc(this.context.getOptions().bar.show, s) && this.context.store.getDataManager().isTaskVisible(s) && n && this.context.store.getOptionManager().unpackFunc(this.context.getOptions().bar.show, n) && this.context.store.getDataManager().isTaskVisible(n)) {
const c = this.getPoints(s, n, i);
if (c.length <= 2)
L.warn("The link position has some error.", i);
else {
const g = this.createId(i), h = i.radius ?? this.context.getOptions().links.radius, d = ((o = i.arrow) == null ? void 0 : o.width) ?? this.context.getOptions().links.arrow.width, m = ((r = i.arrow) == null ? void 0 : r.height) ?? this.context.getOptions().links.arrow.height, p = i.width ?? this.context.getOptions().links.width, u = new v.Group({ id: g }), x = new v.Circle({
radius: h,
fill: i.color || this.context.getOptions().links.color || this.context.getOptions().primaryColor,
x: c[0],
y: c[1]
});
u.add(x);
const w = Math.floor(c.length / 2), E = w % 2 === 0 ? w : w - 1, T = c.slice(0, E + 2), O = c.slice(E), C = new v.Line({
points: T,
stroke: i.color || this.context.getOptions().links.color || this.context.getOptions().primaryColor,
strokeWidth: p,
lineCap: "round",
lineJoin: "round",
dash: i.dash || this.context.getOptions().links.dash,
hitStrokeWidth: 10,
// 增加点击区域
draggable: !0,
dragBoundFunc: (S) => ({ x: 0, y: 0 })
});
u.add(C), C.on("dragstart", (S) => {
this.handleDrag(
S,
i,
"S",
[c[c.length - 2], c[c.length - 1]],
g
);
});
const k = new v.Arrow({
points: O,
stroke: i.color || this.context.getOptions().links.color || this.context.getOptions().primaryColor,
strokeWidth: p,
pointerLength: m,
pointerWidth: d,
fill: ((l = i.arrow) == null ? void 0 : l.color) || this.context.getOptions().links.arrow.color || i.color || this.context.getOptions().links.color || this.context.getOptions().primaryColor,
// 箭头填充色
lineJoin: "round",
dash: i.dash || this.context.getOptions().links.dash,
hitStrokeWidth: 10,
// 增加点击区域
draggable: !0,
dragBoundFunc: (S) => ({ x: 0, y: 0 })
});
u.add(k), k.on("dragstart", (S) => {
this.handleDrag(S, i, "F", [c[0], c[1]], g);
}), this.linksGroup.add(u), u.on("mouseover", (S) => {
S.target.moveToTop(), this.context.getOptions().links.move.enabled === !0 && (this.stage.container().style.cursor = "pointer"), this.selectedMap.has(g) || this.handleHighlight(
u,
h,
d,
m,
p,
2
);
}), u.on("mouseout", (S) => {
this.selectedMap.has(g) || this.handleHighlight(
u,
h,
d,
m,
p,
0
), !this.isDragging && (this.stage.container().style.cursor = "default");
}), u.on("mousedown", (S) => {
this.isDragging = !0;
}), u.on("click", (S) => {
S.cancelBubble = !0, this.isDragging = !1, u.moveToTop(), S.evt.button === 0 ? this.selectedMap.has(g) ? (this.selectedMap.delete(g), this.context.event.emit(
y.SELECT_LINK,
null,
i,
this.selectedMap.values().toArray()
)) : (this.selectedMap.set(g, i), this.context.event.emit(
y.SELECT_LINK,
i,
null,
this.selectedMap.values().toArray()
)) : S.evt.button === 2 && this.context.event.emit(y.CONTEXT_LINK, S.evt, i);
}), this.selectedMap.has(g) && this.handleHighlight(
u,
h,
d,
m,
p,
2,
!0
);
}
}
});
}
createId(t) {
return `link-group-${t[this.context.getOptions().links.key]}-${t.from}-${t.to}-${t.type || "FS"}`;
}
getPoints(t, e, i) {
if (t.startTime && t.endTime && e.startTime && e.endTime) {
const s = this.context.getOptions().row.height, n = t.isMilestone() ? s / 2 : 0, o = this.context.store.getTimeAxis().getTimeLeft(t.startTime) - n, r = this.context.store.getTimeAxis().getTimeLeft(t.endTime) + n, l = e.isMilestone() ? s / 2 : 0, c = this.context.store.getTimeAxis().getTimeLeft(e.startTime) - l, g = this.context.store.getTimeAxis().getTimeLeft(e.endTime) + l;
let h = [];
switch (i.type || "FS") {
case "FF":
h = this.createFF(i, t, e, o, r, c, g);
break;
case "SS":
h = this.createSS(i, t, e, o, r, c, g);
break;
case "SF":
h = this.createSF(i, t, e, o, r, c, g);
break;
case "FS":
default:
h = this.createFS(i, t, e, o, r, c, g);
}
return h;
}
return [];
}
/** 生成 FS 连线 */
createFS(t, e, i, s, n, o, r) {
const l = this.context.getOptions().header.height, c = this.context.getOptions().row.height, g = c / 2 + l, h = t.gap || this.context.getOptions().links.gap, d = [
n + h,
0.05 + g + c * e.flatIndex
];
{
const m = t.distance ? parseInt(t.distance) : this.context.getOptions().links.distance;
if (isNaN(m))
L.error("Link's distance must be a Numeric");
else {
const p = n + h + m, u = o - h - m, x = [
Math.max(p, u),
g + c * e.flatIndex
];
d.push(...x);
const w = c * e.flatIndex + l + (e.flatIndex <= i.flatIndex ? c : 0);
d.push(x[0], w), d.push(u, w), d.push(u, g + c * i.flatIndex);
}
}
return d.push(o - h, g + c * i.flatIndex), d;
}
/** 生成 FF 连线 */
createFF(t, e, i, s, n, o, r) {
const l = this.context.getOptions().header.height, c = this.context.getOptions().row.height, g = c / 2 + l, h = t.gap || this.context.getOptions().links.gap, d = [
n + h,
0.05 + g + c * e.flatIndex
];
{
const m = t.distance ? parseInt(t.distance) : this.context.getOptions().links.distance;
if (isNaN(m))
L.error("Link's distance must be a Numeric");
else {
const p = n + h + m, u = r + h + m, x = [
p <= u ? u : p,
g + c * e.flatIndex
];
d.push(...x), d.push(
Math.max(u, p),
g + c * i.flatIndex
);
}
}
return d.push(r + h, g + c * i.flatIndex), d;
}
/** 生成 SS 连线 */
createSS(t, e, i, s, n, o, r) {
const l = this.context.getOptions().header.height, c = this.context.getOptions().row.height, g = c / 2 + l, h = t.gap || this.context.getOptions().links.gap, d = [
s - h,
0.05 + g + c * e.flatIndex
];
{
const m = t.distance ? parseInt(t.distance) : this.context.getOptions().links.distance;
if (isNaN(m))
L.error("Link's distance must be a Numeric");
else {
const p = s - h - m, u = o - h - m;
d.push(
Math.min(u, p),
g + c * e.flatIndex
), d.push(
Math.min(u, p),
g + c * i.flatIndex
);
}
}
return d.push(o - h, g + c * i.flatIndex), d;
}
/** 生成 SF 连线 */
createSF(t, e, i, s, n, o, r) {
const l = this.context.getOptions().header.height, c = this.context.getOptions().row.height, g = c / 2 + l, h = t.gap || this.context.getOptions().links.gap, d = [
s - h,
0.05 + g + c * e.flatIndex
];
{
const m = t.distance ? parseInt(t.distance) : this.context.getOptions().links.distance;
if (isNaN(m))
L.error("Link's distance must be a Numeric");
else {
const p = s - h - m, u = r + h + m, x = [
Math.min(p, u),
g + c * e.flatIndex
];
d.push(...x);
const w = c * e.flatIndex + l + (e.flatIndex <= i.flatIndex ? c : 0);
d.push(x[0], w), d.push(u, w), d.push(u, g + c * i.flatIndex);
}
}
return d.push(r + h, g + c * i.flatIndex), d;
}
/**
* 处理连线被点击后的移动
*/
handleDrag(t, e, i, s, n) {
var x, w, E;
if (!this.isDragging || this.context.getOptions().links.move.enabled !== !0) return;
this.stage.container().style.cursor = "pointer";
const o = this.linksGroup.findOne(`#${n}`);
this.templateArrow.setAttrs({
stroke: e.color || this.context.getOptions().links.color || this.context.getOptions().primaryColor,
strokeWidth: e.width ?? this.context.getOptions().links.width,
pointerLength: ((x = e.arrow) == null ? void 0 : x.height) ?? this.context.getOptions().links.arrow.height,
// 箭头长度
pointerWidth: ((w = e.arrow) == null ? void 0 : w.width) ?? this.context.getOptions().links.arrow.width,
// 箭头宽度
fill: ((E = e.arrow) == null ? void 0 : E.color) || this.context.getOptions().links.arrow.color || e.color || this.context.getOptions().links.color || this.context.getOptions().primaryColor,
// 箭头填充色
lineJoin: "round",
dash: e.data || this.context.getOptions().links.dash
}), this.templateArrow.visible(!1);
let r = null;
const l = this.context.getOptions().header.height, c = this.context.getOptions().row.height, g = c / 2 + l, h = e.gap || this.context.getOptions().links.gap;
let d = null;
const m = () => {
const T = this.stage.getPointerPosition();
if (!T || (d = this.getTaskByPosition(T), !d)) return;
const { allowLeft: O, allowRight: C } = this.isAllowDrop(d, e.from);
if (this.templateArrow.visible(!0), o == null || o.visible(!1), d != null && d.startTime && (d != null && d.endTime)) {
const k = this.context.store.getTimeAxis().getTimeLeft(d.startTime), S = this.context.store.getTimeAxis().getTimeLeft(d.endTime), b = (S + k) / 2 + this.offsetX;
let D = k - h;
T.x <= b ? r = "S" : (r = "F", D = S + h), i === "S" ? (this.templateArrow.points([
D,
g + c * d.flatIndex,
...s
]), C ? this.stage.container().style.cursor = "pointer" : this.stage.container().style.cursor = "not-allowed") : i === "F" && (this.templateArrow.points([
...s,
D,
g + c * d.flatIndex
]), O ? this.stage.container().style.cursor = "pointer" : this.stage.container().style.cursor = "not-allowed");
}
}, p = () => {
var C, k;
let T;
const O = J(e);
if (r && d && (i === "S" ? (T = `${r}${(e.type || "FS")[1]}`, O.from = d.id) : i === "F" && (T = `${(e.type || "FS")[0]}${r}`, O.to = d.id)), T && d && !(O.from === O.to && ["FF", "SS"].includes(T))) {
const { allowLeft: S, allowRight: b } = this.isAllowDrop(d, O.from);
O.type = T, ((C = O.type) == null ? void 0 : C.slice(1)) === "S" && S || ((k = O.type) == null ? void 0 : k.slice(1)) === "F" && b ? this.context.event.emit(y.UPDATE_LINK, O) : this.context.event.emit(y.ERROR, q.LINK_NOT_ALLOWED);
} else
this.context.event.emit(y.ERROR, q.LINK_SAME);
this.templateArrow.visible(!1), this.stage.container().style.cursor = "default", this.isDragging = !1, this.calculateLinks(), document.removeEventListener("mousemove", m), document.removeEventListener("mouseup", p);
}, u = (T) => {
T.key === "Escape" && (this.templateArrow.visible(!1), this.stage.container().style.cursor = "default", this.isDragging = !1, o == null || o.visible(!0), document.removeEventListener("mousemove", m), document.removeEventListener("mouseup", p), document.removeEventListener("keydown", u));
};
document.addEventListener("mousemove", m), document.addEventListener("mouseup", p), document.addEventListener("keydown", u);
}
/**
* 处理连线被点击后的移动
*/
createLink(t, e, i, s, n) {
this.stage.container().style.cursor = "pointer", this.templateArrow.setAttrs({
points: [],
stroke: i,
strokeWidth: this.context.getOptions().links.width,
pointerLength: this.context.getOptions().links.arrow.height,
// 箭头长度
pointerWidth: this.context.getOptions().links.arrow.width,
// 箭头宽度
fill: i,
dash: this.context.getOptions().links.dash
}), this.templateArrow.visible(!1);
let o = null;
const r = this.context.getOptions().header.height, l = this.context.getOptions().row.height, c = l / 2 + r, g = this.context.getOptions().links.gap;
let h = null;
const d = () => {
const u = this.stage.getPointerPosition();
if (!u || (h = this.getTaskByPosition(u), !h)) return;
const { allowLeft: x, allowRight: w } = this.isAllowDrop(h, n);
if (this.templateArrow.visible(!0), h.startTime && h.endTime) {
const E = this.context.store.getTimeAxis().getTimeLeft(h.startTime), T = this.context.store.getTimeAxis().getTimeLeft(h.endTime), O = (T + E) / 2 + this.offsetX;
let C = E - g;
u.x <= O ? o = "S" : (o = "F", C = T + g), this.templateArrow.points([
...s,
C,
c + l * h.flatIndex
]), o === "S" && !x ? this.stage.container().style.cursor = "not-allowed" : o === "F" && !w ? this.stage.container().style.cursor = "not-allowed" : this.stage.container().style.cursor = "pointer";
}
}, m = () => {
let u;
if (o && (u = `${e}${o}`), u && h)
if (this.context.getOptions().links.data.some((x) => x.from === n && x.to === h.id && x.type === u))
this.context.event.emit(y.ERROR, q.LINK_EXIST);
else if (n === h.id && e === o)
this.context.event.emit(y.ERROR, q.LINK_SAME);
else {
const { allowLeft: x, allowRight: w } = this.isAllowDrop(h, n);
o === "S" && x || o === "F" && w ? this.context.event.emit(y.CREATE_LINK, {
from: n,
to: h.id,
type: u,
color: i
}) : this.context.event.emit(
y.ERROR,
q.LINK_NOT_ALLOWED
);
}
this.templateArrow.visible(!1), this.stage.container().style.cursor = "default", this.isDragging = !1, this.calculateLinks(), document.removeEventListener("mousemove", d), document.removeEventListener("mouseup", m);
}, p = (u) => {
u.key === "Escape" && (this.templateArrow.visible(!1), this.stage.container().style.cursor = "default", this.isDragging = !1, document.removeEventListener("mousemove", d), document.removeEventListener("mouseup", m), document.removeEventListener("keydown", p));
};
document.addEventListener("mousemove", d), document.addEventListener("mouseup", m), document.addEventListener("keydown", p);
}
/**
* 按照位置获取任务
*/
getTaskByPosition(t) {
const e = this.context.getOptions().header.height;
if (t.y <= e) return null;
const i = t.y - this.offsetY, s = Math.floor(
(i - e) / this.context.getOptions().row.height
);
return this.context.store.getDataManager().getVisibleTasks()[s] || null;
}
/**
* 检查当前连接点是否可以被创建
*/
isAllowDrop(t, e) {
let i = !0, s = !0, n = this.context.getOptions().links.create.to;
return j(n) && (n = n(
t.getEmitData(),
this.context.store.getDataManager().getTaskById(e).getEmitData()
)), mt(n) ? i = s = n : U(n) && (i = n === "S", s = n === "F"), {
allowLeft: i,
allowRight: s
};
}
/**
* 操作高亮关联线
*/
handleHighlight(t, e, i, s, n, o, r = !1) {
const l = t.findOne("Circle"), c = t.findOne("Arrow"), g = t.findOne("Line");
l && new v.Tween({
node: l,
radius: e + o,
duration: r ? 0 : 0.1
}).play(), c && new v.Tween({
node: c,
pointerWidth: i + o,
pointerLength: s + o,
strokeWidth: n + o,
duration: r ? 0 : 0.1
}).play(), g && new v.Tween({
node: g,
strokeWidth: n + o,
duration: r ? 0 : 0.1
}).play();
}
/** 高亮创建点 */
highlightPoint(t) {
this.handlePointHighlight(t, 1);
}
/** 取消高亮创建点 */
unhighlightPoint(t) {
const e = this.context.getOptions().links.create.mode === "always" ? 0.5 : 0;
this.handlePointHighlight(t, e);
}
/** 操作创建点的高亮 */
handlePointHighlight(t, e) {
const i = this.pointGroup.findOne(`#point-${t}-left`), s = this.pointGroup.findOne(`#point-${t}-right`);
i && new v.Tween({
node: i,
opacity: e,
duration: 0.1
}).play(), s && new v.Tween({
node: s,
opacity: e,
duration: 0.1
}).play();
}
}
class ze {
constructor(t, e, i) {
a(this, "tasks", []);
a(this, "chartBaselineGroup");
a(this, "indicatorGroup");
a(this, "baselineGroup");
// 状态变量
a(this, "width", 0);
a(this, "height", 0);
a(this, "offsetX", 0);
a(this, "offsetY", 0);
this.context = t, this.stage = e, this.layer = i, this.chartBaselineGroup = new v.Group({ name: "chart-baseline-group" }), this.baselineGroup = new v.Group({ name: "baseline-group" }), this.chartBaselineGroup.add(this.baselineGroup), this.indicatorGroup = new v.Group({ name: "baseline-indicator-group" }), this.chartBaselineGroup.add(this.indicatorGroup), this.layer.add(this.chartBaselineGroup), this.registerEvents();
}
/**
* 注册事件
*/
registerEvents() {
}
/**
* 调整基线大小
*/
resize(t, e) {
this.width = t, this.height = e, this.calculateBaselines();
}
/**
* 设置偏移量 (响应滚动)
*/
setOffset(t, e) {
this.offsetX = t, this.offsetY = e, this.chartBaselineGroup.x(t), this.chartBaselineGroup.y(e), this.calculateBaselines();
}
/**
* 更新数据
*/
update() {
this.calculateBaselines();
}
/**
* 渲染基线
*/
render(t) {
this.tasks = t, this.update();
}
/**
* 销毁关联线
*/
destroy() {
this.baselineGroup.destroy(), this.indicatorGroup.destroy(), this.chartBaselineGroup.destroy();
}
/**
* 计算并渲染基线
*/
calculateBaselines() {
if (this.baselineGroup.destroyChildren(), this.indicatorGroup.destroyChildren(), !this.context.getOptions().baselines.show) return;
const t = this.context.getOptions().header.height, e = this.context.getOptions().row.height, i = e / 2 + t, s = nt(
this.context.getOptions().baselines.radius
), n = this.context.getOptions().baselines.opacity, o = this.context.getOptions().baselines.backgroundColor;
this.tasks.forEach((r) => {
if (this.context.store.getOptionManager().unpackFunc(this.context.getOptions().bar.show, r) && this.context.store.getDataManager().isTaskVisible(r)) {
const l = this.context.store.getDataManager().getBaselinesByTaskId(r.id), c = st(
this.context.getOptions().baselines.height || this.context.store.getOptionManager().unpackFunc(this.context.getOptions().bar.height, r),
e
), g = this.context.getOptions().baselines.offset ?? 0;
l.forEach((h, d) => {
if (!h.validate()) return;
const m = this.context.store.getTimeAxis().getTimeLeft(h.startTime), p = this.context.store.getTimeAxis().getTimeLeft(h.endTime), u = new v.Group({ id: `baseline-group-${h.id}` });
this.renderBaselineBar(u, r, h, m, p, i, e, c, t, o, n, s, g);
const x = this.context.getOptions().baselines.compare, w = h.getTimeDiff();
if (!x.enabled || !w) return;
const E = x.mode;
h.highlight && (E === "highlight" || E === "both") && this.renderCompareHighlight(u, r, h, w), d === 0 && (E === "indicator" || E === "both") && this.renderCompareIndicator(r, h, w), this.bindEvents(u, r, h), this.baselineGroup.add(u);
});
}
});
}
renderBaselineBar(t, e, i, s, n, o, r, l, c, g, h, d, m) {
if (this.context.getOptions().baselines.mode === "shadow") {
const p = o + r * e.flatIndex - l / 2 + m, u = new v.Rect({
id: `baseline-item-${i.id}`,
x: s,
y: p,
width: n - s,
height: l,
cornerRadius: d,
fill: g,
opacity: h
});
t.add(u), this.renderText(t, e, i, s, n, p, l);
} else if (this.context.getOptions().baselines.mode === "line") {
const p = st(this.context.getOptions().baselines.height ?? 5, r);
let u = c + r * e.flatIndex + m;
const x = this.context.getOptions().baselines.position;
let w = "";
x === "top" ? (u += +p / 2, w = "line_top") : x === "center" ? (u += r / 2, w = "line_center") : (u += r - p / 2, w = "line_bottom");
const E = new v.Line({
id: `baseline-item-${i.id}`,
points: [s, u, n, u],
stroke: g,
opacity: h,
strokeWidth: p,
lineCap: "butt",
lineJoin: "round"
});
t.add(E), this.renderText(t, e, i, s, n, u, p, w);
}
}
renderText(t, e, i, s, n, o, r, l) {
const c = `chart-baseline-text-${i.id}`;
if ((() => {
this.baselineGroup.find(`#${c}`) && this.baselineGroup.find(`#${c}`).forEach((w) => w.remove());
})(), !this.context.getOptions().baselines.label.show) return;
const h = this.context.getOptions().baselines.label.field, d = h ? i.getField(h) : i.name;
if (!d || d === "") return;
const m = n - s - 10, p = Math.max(this.context.getOptions().baselines.label.fontSize, r), u = new v.Text({
text: d,
id: c,
x: s + 5,
y: o,
width: m,
height: p,
fill: this.context.getOptions().baselines.label.color,
fontSize: this.context.getOptions().baselines.label.fontSize,
fontFamily: this.context.getOptions().baselines.label.fontFamily || "Arial",
align: this.context.getOptions().baselines.label.position,
verticalAlign: "bottom"
});
l === "line_bottom" ? u.setAttrs({
y: o - p / 2,
verticalAlign: "top"
}) : l === "line_center" ? u.setAttrs({
y: o - p / 2,
verticalAlign: "middle"
}) : l === "line_top" && u.setAttrs({
y: o - r / 2,
verticalAlign: "bottom"
}), r >= p && u.setAttrs({
verticalAlign: "middle"
});
const x = u.measureSize(d);
(this.context.getOptions().baselines.label.forceDisplay || m > x.width) && t.add(u);
}
renderCompareHighlight(t, e, i, s) {
const n = s[`${this.context.getOptions().baselines.compare.target}Status`];
if (!n || n === "ontime") return;
const o = t.findOne(`#baseline-item-${i.id}`);
if (!o) return;
const r = this.context.getOptions().baselines.compare, l = this.context.getOptions().baselines.mode, c = { fill: "", stroke: "", opacity: r[n].opacity };
if (l === "shadow")
c.fill = r[n].backgroundColor;
else if (l === "line")
c.stroke = r[n].backgroundColor;
else
return;
o.setAttrs(c);
}
renderCompareIndicator(t, e, i) {
const s = this.context.getOptions().baselines, n = s.compare.indicator;
if (!n || !n.show) return;
const o = this.context.getOptions().header.height, r = this.context.getOptions().row.height, l = st(
this.context.store.getOptionManager().unpackFunc(this.context.getOptions().bar.height, t),
r
);
let c = s.backgroundColor;
const g = this.context.store.getTimeAxis().getTimeLeft(t.startTime), h = this.context.store.getTimeAxis().getTimeLeft(t.endTime);
let d = (r - l) / 2 + r * t.flatIndex + o;
if (n.position === "bottom" && (d += l), n.show === "start" || n.show === "both" || n.show === !0) {
const m = i.startStatus;
if (m && s.compare.indicator[m].show) {
c = F(s.compare.indicator[m].color).alpha(s.compare.indicator[m].opacity).toHex();
const p = new v.Circle({
x: g - n.size,
y: d,
fill: c,
radius: n.size / 2
});
this.indicatorGroup.add(p);
let u = `${lt(i.startDiff)}${i.unit} ${m}`;
const x = s.compare.indicator[m].text;
j(x) ? u = x(i.startDiff, { ...t.getEmitData(), baseline: e }) : U(x) && (u = x);
const w = new v.Text({
y: d - n.fontSize / 2,
text: u,
fill: c,
fontSize: n.fontSize,
fontFamily: n.fontFamily || "Arial"
}), E = w.measureSize(u);
w.x(g - n.size - E.width - 5), this.indicatorGroup.add(w);
}
}
if (n.show === "end" || n.show === "both" || n.show === !0) {
const m = i.endStatus;
if (m && s.compare.indicator[m].show) {
c = F(s.compare.indicator[m].color).alpha(s.compare.indicator[m].opacity).toHex();
const p = new v.Circle({
x: h + n.size,
y: d,
fill: c,
radius: n.size / 2
});
this.indicatorGroup.add(p);
let u = `${lt(i.endDiff)}${i.unit} ${m}`;
const x = s.compare.indicator[m].text;
j(x) ? u = x(i.endDiff, { ...t.getEmitData(), baseline: e }) : U(x) && (u = x);
const w = new v.Text({
x: h + n.size + 5,
y: d - n.fontSize / 2,
text: u,
fill: c,
fontSize: n.fontSize,
fontFamily: n.fontFamily || "Arial"
});
this.indicatorGroup.add(w);
}
}
}
bindEvents(t, e, i) {
t.on("mouseover", (s) => {
this.context.event.emit(y.BASELINE_MOUSEOVER, s.evt, e, i);
}), t.on("mouseout", (s) => {
this.context.event.emit(y.BASELINE_MOUSEOUT, s.evt, e, i);
}), t.on("click", (s) => {
s.cancelBubble = !0, s.evt.button === 0 ? this.context.event.emit(y.BASELINE_CLICK, s.evt, e, i) : s.evt.button === 2 && this.context.event.emit(y.BASELINE_CONTEXTMENU, s.evt, e, i);
});
}
}
class Pe {
constructor(t, e) {
// Konva 元素
a(this, "stage");
a(this, "headerLayer");
a(this, "bodyGroup");
a(this, "gridGroup");
a(this, "weekendGroup");
a(this, "holidayGroup");
a(this, "todayLayer");
a(this, "linkGroup");
a(this, "baselineGroup");
a(this, "bgLayer");
a(this, "bodyLayer");
a(this, "width", 0);
a(this, "height", 0);
this.context = t, this.container = e, this.stage = new v.Stage({
container: this.container,
width: this.container.clientWidth,
height: this.container.clientHeight
}), this.bgLayer = new v.Layer(), this.weekendGroup = new We(this.context, this.bgLayer), this.holidayGroup = new Fe(this.context, this.bgLayer), this.gridGroup = new Ae(this.context, this.bgLayer), this.stage.add(this.bgLayer), this.headerLayer = new He(this.context, this.stage), this.todayLayer = new $e(
this.context,
this.bgLayer,
this.headerLayer.layer
), this.bodyLayer = new v.Layer(), this.linkGroup = new Be(this.context, this.stage, this.bodyLayer), this.baselineGroup = new ze(this.context, this.stage, this.bodyLayer), this.bodyGroup = new Re(
this.context,
this.stage,
this.bodyLayer,
this.bgLayer
), this.stage.add(this.bodyLayer);
}
/**
* 调整大小
*/
resize(t, e) {
this.width = t, this.height = e, this.context.store.getTimeAxis().setAllWidth(t), this.stage.width(t), this.stage.height(e), this.headerLayer.resize(t), this.gridGroup.resize(t, e), this.linkGroup.resize(t, e), this.baselineGroup.resize(t, e), this.holidayGroup.resize(t, e), this.weekendGroup.resize(t, e), this.bodyGroup.resize(t, e), this.todayLayer.resize(t, e);
}
render(t, e, i) {
this.headerLayer.setOffset(-t, 0), this.gridGroup.setOffset(-t, -e), this.linkGroup.setOffset(-t, -e), this.baselineGroup.setOffset(-t, -e), this.weekendGroup.setOffset(-t, -e), this.holidayGroup.setOffset(-t, -e), this.bodyGroup.setOffset(-t, -e), this.todayLayer.setOffset(-t, -e), this.gridGroup.render(), this.holidayGroup.render(), this.weekendGroup.render(), this.linkGroup.render(i), this.baselineGroup.render(i), this.bodyGroup.render(i), this.headerLayer.render(), this.todayLayer.render();
}
/**
* 刷新图表(用于滚动或局部更新时的高效渲染)
*/
refresh(t, e, i) {
this.render(t, e, i);
}
/**
* 更新任务
*/
updateTask(t) {
this.bodyGroup.updateTask(t), this.linkGroup.update(), this.baselineGroup.update();
}
destroy() {
this.headerLayer.destroy(), this.gridGroup.destroy(), this.bodyLayer.destroy(), this.todayLayer.destroy(), this.holidayGroup.destroy(), this.weekendGroup.destroy(), this.linkGroup.destroy(), this.baselineGroup.destroy(), this.bgLayer.destroy(), this.stage.destroy();
}
}
const Ye = '<svg style="transition: all 0.3s" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="currentColor" d="M8.293 12.707a1 1 0 0 1 0-1.414l5.657-5.657a1 1 0 1 1 1.414 1.414L10.414 12l4.95 4.95a1 1 0 0 1-1.414 1.414z"/></g></svg>';
class Ne {
constructor(t, e) {
a(this, "line");
a(this, "initialX", 0);
a(this, "initialWidth", 0);
a(this, "collapseButton", null);
this.root = t, this.container = e, this.line = document.createElement("div"), this.line.className = "x-gantt-middle-resize-line", this.line.style.position = "absolute", this.line.style.zIndex = "99", this.line.style.width = "5px", this.line.style.height = "100%", this.line.style.borderLeft = "2px solid", this.line.style.setProperty(
"border-left-color",
this.root.store.getOptionManager().getOptions().border.color,
"important"
), this.line.style.cursor = "col-resize", this.collapseButton = document.createElement("div"), this.collapseButton.className = "x-gantt-collapse-button", this.collapseButton.style.position = "absolute", this.collapseButton.style.top = "50%", this.collapseButton.style.left = "0", this.collapseButton.style.transform = "translateY(-50%)", this.collapseButton.style.cursor = "pointer", this.collapseButton.style.width = "16px", this.collapseButton.style.height = "30px", this.collapseButton.style.backgroundColor = "#fff", this.collapseButton.style.borderRadius = "0 6px 6px 0", this.collapseButton.style.boxShadow = "0 0 2px rgba(0, 0, 0, 0.2)", this.collapseButton.style.display = "flex", this.collapseButton.style.alignItems = "center", this.collapseButton.style.justifyContent = "center", this.collapseButton.innerHTML = Ye, this.collapseButton.addEventListener("click", (i) => {
i.stopPropagation(), this.root.store.getColumnManager().collapse();
}), this.line.appendChild(this.collapseButton), this.container.appendChild(this.line), this.addDragEvents();
}
setOffset(t) {
this.line.style.left = `${t - 2}px`, this.initialX = t, this.collapseButton && (this.root.store.getColumnManager().isCollapsed() ? this.collapseButton.querySelector("svg").style.transform = "rotate(180deg)" : this.collapseButton.querySelector("svg").style.transform = "rotate(0deg)");
}
/**
* 添加拖拽事件
*/
addDragEvents() {
let t = 0, e = null;
const i = this.root.store.getColumnManager(), s = i.getLeafColumns(), n = (l) => {
l.preventDefault(), l.stopPropagation(), t = l.clientX, e = this.container.getBoundingClientRect();
const c = s[s.length - 1].key;
this.initialWidth = i.getColumnWidth(c);
const g = parseInt(this.line.style.left) + 2;
this.root.event.emit(y.SHOW_GUIDELINE, g);
const h = (m) => o(m), d = (m) => r(m, h, d);
document.addEventListener("mousemove", h), document.addEventListener("mouseup", d);
}, o = (l) => {
if (l.preventDefault(), !e) return;
const c = l.clientX - t;
s[s.length - 1].key;
const g = 50 - this.initialWidth, d = e.width - 20 - this.initialX, m = Math.max(g, Math.min(d, c)), p = this.initialX + m;
this.root.event.emit(y.MOVE_GUIDELINE, p);
}, r = (l, c, g) => {
document.removeEventListener("mousemove", c), document.removeEventListener("mouseup", g), this.root.event.emit(y.HIDE_GUIDELINE);
const h = l.clientX - t, d = s[s.length - 1].key, m = Math.max(50, this.initialWidth + h);
i.setColumnWidth(d, m), this.root.event.emit(y.UPDATE_TABLE_HEADER);
};
this.line.addEventListener("mousedown", n);
}
}
class Ue {
/**
* @param container 指示线的容器元素
*/
constructor(t, e) {
a(this, "element");
a(this, "container");
a(this, "visible", !1);
if (this.context = t, !e)
throw new Error("Container is required for GuideLine instance");
this.container = e, this.element = document.createElement("div"), this.initElement(), this.initEvents();
}
/**
* 初始化指示线元素
*/
initElement() {
this.element.className = "x-gantt-guide-line", this.element.style.position = "absolute", this.element.style.top = "0", this.element.style.left = "0", this.element.style.width = "0", this.element.style.height = "100%", this.element.style.setProperty(
"border-left",
`1px dashed ${this.context.getOptions().border.color}`,
"important"
), this.element.style.zIndex = "9999", this.element.style.pointerEvents = "none", this.element.style.display = "none", this.element.style.transform = "translateX(-0.5px)", getComputedStyle(this.container).position === "static" && (this.container.style.position = "relative"), this.container.appendChild(this.element);
}
/**
* 初始化事件监听
*/
initEvents() {
this.context.event.on(y.SHOW_GUIDELINE, (t) => {
this.show(t);
}), this.context.event.on(y.HIDE_GUIDELINE, () => {
this.hide();
}), this.context.event.on(y.MOVE_GUIDELINE, (t) => {
this.setLeft(t);
});
}
/**
* 设置指示线容器
* @param container 新的容器元素
*/
setContainer(t) {
this.element.parentElement && this.element.parentElement.removeChild(this.element), this.container = t, getComputedStyle(this.container).position === "static" && (this.container.style.position = "relative"), this.container.appendChild(this.element);
}
/**
* 设置指示线左侧位置
* @param left 左侧位置值,单位px
*/
setLeft(t) {
const e = this.container.clientWidth, i = Math.max(0, Math.min(e - 20, t));
this.element.style.left = `${i}px`;
}
/**
* 显示指示线
* @param left 可选参数,显示时设置的左侧位置
*/
show(t) {
t !== void 0 && this.setLeft(t), this.element.style.display = "block", this.visible = !0;
}
/**
* 隐藏指示线
*/
hide() {
this.element.style.display = "none", this.visible = !1;
}
/**
* 检查指示线是否可见
*/
isVisible() {
return this.visible;
}
/**
* 获取当前位置
*/
getLeft() {
return this.element.offsetLeft;
}
}
class Xe {
constructor(t = 16) {
a(this, "taskQueue", /* @__PURE__ */ new Map());
// 使用 Map 避免同类型重复任务
a(this, "taskHandlers", /* @__PURE__ */ new Map());
// 任务类型处理器映射
a(this, "isScheduled", !1);
a(this, "delay");
// 使用 debounce 来延迟执行,避免短时间内多次触发
a(this, "debouncedFlush");
this.delay = t, this.debouncedFlush = Yt(() => {
this.flushTaskQueue();
}, t);
}
/**
* 注册任务处理器
* @param taskType 任务类型
* @param handler 处理器配置
*/
registerHandler(t, e) {
this.taskHandlers.set(t, e), L.debug(`RenderScheduler: 注册任务处理器 ${t}`);
}
/**
* 注册任务处理器(简化版本,只传回调函数)
* @param taskType 任务类型
* @param callback 回调函数
* @param immediate 是否总是立即执行
*/
registerSimpleHandler(t, e, i = !1) {
this.registerHandler(t, { callback: e, immediate: i });
}
/**
* 调度任务执行
* @param taskType 任务类型
* @param args 传递给处理器的参数
* @param options 任务选项
*/
scheduleTask(t, e = [], i = {}) {
const s = this.taskHandlers.get(t);
if (!s) {
L.warn(`RenderScheduler: 未找到任务类型 ${t} 的处理器`);
return;
}
const n = {
type: t,
refresh: i.refresh,
callback: s.callback,
args: e,
immediate: i.immediate ?? s.immediate ?? !1
};
if (n.immediate) {
L.debug(`RenderScheduler: 立即执行任务 ${t}`), this.executeTask(n);
return;
}
this.taskQueue.set(t, n), L.debug(`RenderScheduler: 添加任务到队列 ${t}`), this.debouncedFlush();
}
/**
* 立即执行指定类型的任务(跳过队列)
* @param taskType 任务类型
* @param args 传递给处理器的参数
* @param refresh 是否强制刷新
*/
immediateExecuteTask(t, e = [], i = !1) {
const s = this.taskHandlers.get(t);
if (!s) {
L.warn(`RenderScheduler: 未找到任务类型 ${t} 的处理器`);
return;
}
L.debug(`RenderScheduler: 立即执行任务 ${t}`);
const n = {
type: t,
refresh: i,
callback: s.callback,
args: e,
immediate: !0
};
this.executeTask(n);
}
/**
* 立即执行所有队列中的任务
*/
immediateFlushAll() {
L.debug("RenderScheduler: 立即执行所有队列任务"), this.cancelScheduled(), this.flushTaskQueue();
}
/**
* 执行单个任务
* @param task 任务对象
*/
executeTask(t) {
try {
t.callback(...t.args || []);
} catch (e) {
L.error(`RenderScheduler: 执行任务 ${t.type} 时出错:`, e);
}
}
/**
* 清空并执行任务队列
*/
flushTaskQueue() {
if (this.taskQueue.size === 0)
return;
L.debug(
`RenderScheduler: 执行任务队列,任务数量: ${this.taskQueue.size}`
);
const t = Array.from(this.taskQueue.values()).sort((e, i) => e.immediate !== i.immediate ? e.immediate ? -1 : 1 : e.refresh !== i.refresh ? e.refresh ? -1 : 1 : 0);
this.taskQueue.clear(), this.isScheduled = !1;
for (const e of t)
this.executeTask(e);
}
/**
* 取消已调度的任务执行
*/
cancelScheduled() {
this.debouncedFlush.cancel(), this.taskQueue.clear(), this.isScheduled = !1;
}
/**
* 移除指定类型的任务处理器
* @param taskType 任务类型
*/
unregisterHandler(t) {
this.taskHandlers.delete(t), this.taskQueue.delete(t), L.debug(`RenderScheduler: 移除任务处理器 ${t}`);
}
/**
* 获取当前队列中的任务数量
*/
getQueueSize() {
return this.taskQueue.size;
}
/**
* 获取已注册的处理器类型列表
*/
getRegisteredHandlers() {
return Array.from(this.taskHandlers.keys());
}
/**
* 销毁调度器
*/
destroy() {
this.cancelScheduled(), this.taskHandlers.clear(), L.debug("RenderScheduler: 已销毁");
}
}
class Ve {
constructor(t, e) {
a(this, "scrollbar");
a(this, "rootElement");
// 根容器
a(this, "tableContainer");
// 表格容器
a(this, "chartContainer");
// 用于放置右侧图表内容(Konva Stage)并作为滚动内容的容器
a(this, "table");
a(this, "chart");
a(this, "middleLine");
a(this, "renderScheduler");
// 渲染调度器
a(this, "_id", Z());
// 尺寸和状态
a(this, "width", 0);
a(this, "height", 0);
a(this, "isInitialized", !0);
// 更新尺寸
a(this, "updateSize", () => {
this.width = this.context.store.getOptionManager().getOptions().width || this.container.clientWidth, this.height = this.context.store.getOptionManager().getOptions().height || this.container.clientHeight, this.rootElement.style.width = this.width ? `${this.width}px` : "100%", this.rootElement.style.height = this.height ? `${this.height}px` : "100%";
const t = this.context.store.getColumnManager().getTotalWidth();
this.tableContainer.style.width = `${t}px`, this.tableContainer.style.height = this.height ? `${this.height}px` : "100%";
const e = this.width - t;
this.chartContainer.style.width = `${e}px`, this.chartContainer.style.height = this.height ? `${this.height}px` : "100%", this.chart.resize(e, this.height), this.middleLine.setOffset(t);
const i = this.context.store.getTimeAxis().getTotalWidth();
this.scrollbar.updateSize(
e,
this.height,
i,
// 滚动区域宽度
this.context.store.getDataManager().getVisibleSize() * this.context.store.getOptionManager().getOptions().row.height + this.context.store.getOptionManager().getOptions().header.height,
t
);
});
/**
* 设置样式值
*/
a(this, "setStyleValue", () => {
const t = this.context.store.getOptionManager().getOptions();
this.rootElement.style.setProperty(
"--x-gantt-primary-color",
`${t.primaryColor}`
), this.rootElement.style.setProperty(
"--x-gantt-border-color",
`${t.border.color}`
), this.rootElement.style.setProperty(
"--x-gantt-row-hover-color",
`${F(t.row.hover.backgroundColor).alpha(
t.row.hover.opacity
)}`
), this.rootElement.style.setProperty(
"--x-gantt-row-selected-color",
`${F(t.row.select.backgroundColor).alpha(
t.row.select.opacity
)}`
), this.rootElement.style.setProperty(
"--x-gantt-header-font-weight",
`${t.header.fontWeight}`
);
});
a(this, "handleUpdateTask", (t) => {
this.table.updateTask(t), this.chart.updateTask(t);
});
a(this, "handleColumnWidthChange", () => {
this.table.updateWidth(), this.updateSize();
});
this.context = t, this.container = e, this.rootElement = document.createElement("div"), this.rootElement.id = `x-gantt-${this._id}`, this.rootElement.className = "x-gantt", this.rootElement.style.overflow = "hidden", this.rootElement.style.display = "flex", this.rootElement.style.position = "relative", this.container.appendChild(this.rootElement), this.tableContainer = document.createElement("div"), this.tableContainer.className = "x-gantt-table", this.rootElement.appendChild(this.tableContainer), new Ue(this.context, this.container), this.middleLine = new Ne(this.context, this.rootElement), this.chartContainer = document.createElement("div"), this.chartContainer.className = "x-gantt-chart", this.rootElement.appendChild(this.chartContainer), this.table = new _e(this.context, this.tableContainer), this.chart = new Pe(this.context, this.chartContainer), this.scrollbar = new Le(
this.context,
this.rootElement,
this.context.store.getOptionManager().getOptions().scrollbar || {}
// 传入配置项
), this.renderScheduler = new Xe(16), this.setupTaskHandlers(), this.updateSize(), this.setupEventListeners();
}
getScrollbar() {
return this.scrollbar;
}
/**
* 设置任务处理器
*/
setupTaskHandlers() {
this.renderScheduler.registerSimpleHandler(
"DATA_UPDATE",
(t = !0) => this.performRender(t)
), this.renderScheduler.registerSimpleHandler(
"VIEW_UPDATE",
(t = !0) => this.performRender(t)
), this.renderScheduler.registerSimpleHandler(
"MANUAL_RENDER",
(t = !1) => this.performRender(t)
), this.renderScheduler.registerSimpleHandler(
"SCROLL",
(t = !0) => this.performRender(t),
!0
// 滚动需要立即响应
), this.renderScheduler.registerSimpleHandler(
"UPDATE_TASK",
(t) => this.handleUpdateTask(t)
), this.renderScheduler.registerSimpleHandler(
"COLUMN_WIDTH_CHANGE",
() => this.handleColumnWidthChange()
), this.renderScheduler.registerSimpleHandler(
"CHART_OFFSET_CHANGE",
(t = !1) => this.performRender(t)
);
}
/**
* 设置事件监听器
*/
setupEventListeners() {
this.context.event.on(y.DATA_UPDATE, () => {
this.renderScheduler.scheduleTask("DATA_UPDATE", [!0]);
}), this.context.event.on(y.SCROLL, () => {
this.renderScheduler.scheduleTask("SCROLL", [!0], { immediate: !0 });
}), this.context.event.on(y.COLUMN_WIDTH_CHANGE, () => {
this.renderScheduler.scheduleTask("COLUMN_WIDTH_CHANGE");
}), this.context.event.on(y.VIEW_UPDATE, () => {
this.renderScheduler.scheduleTask("VIEW_UPDATE", [!0]);
}), this.context.event.on(y.UPDATE_TASK, (t) => {
this.renderScheduler.scheduleTask("UPDATE_TASK", [t], {
immediate: !0
});
}), this.context.event.on(y.CHART_OFFSET_CHANGE, () => {
this.renderScheduler.scheduleTask("CHART_OFFSET_CHANGE", [!1]);
}), this.context.event.on(y.TOGGLE_COLLAPSE, () => {
this.renderScheduler.scheduleTask("CHART_OFFSET_CHANGE", [!1]);
});
}
/**
* 实际执行渲染的方法
* @param refresh 是否强制刷新
*/
performRender(t = !1) {
this.setStyleValue();
const { x: e, y: i } = this.scrollbar.getScrollPosition(), s = this.context.store.getOptionManager().getOptions().row.height, n = this.context.store.getOptionManager().getOptions().header.height, o = Math.floor(i / s), r = Math.ceil((this.height - n) / s), l = 2, c = Math.max(0, o), g = r + l, h = this.context.store.getDataManager().getVisibleTasks().slice(c, c + g);
this.updateSize(), t ? (this.table.refresh(i, h), this.chart.refresh(e, i, h)) : (this.table.render(i, h), this.chart.render(e, i, h)), this.isInitialized && (this.context.event.emit(y.LOADED), this.isInitialized = !1), L.debug("execute render");
}
/**
* 公共渲染方法,向后兼容
* @param refresh 是否强制刷新
*/
render(t = !1) {
this.renderScheduler.scheduleTask("MANUAL_RENDER", [t]);
}
/**
* 立即执行渲染,不经过调度器
* @param refresh 是否强制刷新
*/
immediateRender(t = !1) {
this.renderScheduler.immediateExecuteTask(
"MANUAL_RENDER",
[t],
t
);
}
destroy() {
L.debug("Renderer destroy"), this.renderScheduler.destroy(), this.scrollbar.destroy(), this.context.event.offAll();
}
}
class Ke {
constructor(t, e, i) {
a(this, "_id", Z());
a(this, "store");
a(this, "event", new Xt());
a(this, "renderer");
this.container = t, this.events = e, this.container.innerHTML = "", this.store = new Me(this, i), this.renderer = new Ve(this, this.container), this.render(), this.registerEvents(), L.debug(
"----Gantt initialized for element:",
this._id,
this.container
);
}
getScrollbar() {
var t;
return (t = this.renderer) == null ? void 0 : t.getScrollbar();
}
getOptions() {
return this.store.getOptionManager().getOptions();
}
setOptions(t, e) {
this.store.setOption(t, e);
}
// *** Public API Methods ***/
render() {
this.renderer.render();
}
updateOptions(t, e) {
this.setOptions(t, e), L.debug("GanttChart options updated"), this.render();
}
destroy() {
L.debug("Gantt destroying..."), this.event.offAll(), this.renderer.destroy(), this.container.innerHTML = "";
}
/**
* 跳转到指定日期。默认为今天
*
* @return {boolean} 是否成功跳转
*/
jumpTo(t) {
const e = H(t);
if (!this.store.getTimeAxis().isInTimeAxis(e)) return !1;
const i = this.store.getTimeAxis().getTimeLeft(e) - 100;
return this.renderer.getScrollbar().scrollTo({ x: Math.max(i, 0) }), !0;
}
// ***** 私有事件 ***** /
/**
* 触发事件
* @param event 事件名称
* @param args 参数列表
*/
_emit(t, ...e) {
var i;
this.events.has(t) && ((i = this.events.get(t)) == null || i.forEach((s) => s(...e)));
}
// 注册对外事件
registerEvents() {
this.event.on(y.ERROR, (t) => {
this._emit("error", t);
}), this.event.on(y.LOADED, () => {
this._emit("loaded");
}), this.event.on(y.TASK_DRAG_END, (t, e) => {
this._emit(
"move",
e.map((i) => {
var s;
return {
row: (s = this.store.getDataManager().getTaskById(i.id)) == null ? void 0 : s.data,
old: i.data
};
})
);
}), this.event.on(y.CHECK_TASK, (t, e) => {
this._emit(
"select",
t.map((i) => i.data),
e,
this.store.getDataManager().getCheckedList().map((i) => i.data)
);
}), this.event.on(y.UPDATE_LINK, (t) => {
this._emit("update:link", t);
}), this.event.on(y.CREATE_LINK, (t) => {
this._emit("create:link", t);
}), this.event.on(
y.SELECT_LINK,
(t, e, i) => {
this._emit("select:link", t, e, i);
}
), this.event.on(y.CONTEXT_LINK, (t, e) => {
this._emit("contextmenu:link", t, e);
}), this.event.on(y.ROW_CLICK, (t, e) => {
this._emit("click:row", t, e.data);
}), this.event.on(y.ROW_DBL_CLICK, (t, e) => {
this._emit("dblclick:row", t, e.data);
}), this.event.on(y.ROW_CONTEXTMENU, (t, e) => {
this._emit("contextmenu:row", t, e.data);
}), this.event.on(y.SLIDER_CLICK, (t, e) => {
this._emit("click:slider", t, e.data);
}), this.event.on(y.SLIDER_DBL_CLICK, (t, e) => {
this._emit("dblclick:slider", t, e.data);
}), this.event.on(y.SLIDER_CONTEXTMENU, (t, e) => {
this._emit("contextmenu:slider", t, e.data);
}), this.event.on(y.SLIDER_HOVER, (t, e) => {
this._emit("hover:slider", t, e.data);
}), this.event.on(y.SLIDER_LEAVE, (t, e) => {
this._emit("leave:slider", t, e.data);
}), this.event.on(y.BASELINE_CLICK, (t, e, i) => {
this._emit("click:baseline", t, e.data, i.data);
}), this.event.on(y.BASELINE_CONTEXTMENU, (t, e, i) => {
this._emit("contextmenu:baseline", t, e.data, i.data);
}), this.event.on(y.BASELINE_MOUSEOVER, (t, e, i) => {
this._emit("hover:baseline", t, e.data, i.data);
}), this.event.on(y.BASELINE_MOUSEOUT, (t, e, i) => {
this._emit("leave:baseline", t, e.data, i.data);
});
}
}
class Ze {
constructor(t, e) {
a(this, "context");
// 管理对外事件
a(this, "events", /* @__PURE__ */ new Map());
e != null && e.logLevel && L.setOptions({
showTimestamp: e.logLevel === "debug",
level: {
debug: 1,
info: 2,
warn: 3,
error: 4,
none: 5
}[e.logLevel] || 2
});
const i = typeof t == "string" ? document.querySelector(t) : t;
if (!i)
throw L.exception(`Container ${t} not found or invalid.`);
i.innerHTML = "", i.classList.add("x-gantt-container"), this.context = new Ke(i, this.events, e);
}
// *** Public API Methods ***/
/**
* 更新 XGantt 的配置选项
*
* @param options - 新的配置选项,支持部分更新
* @param config - 配置更新参数的方式
*
* @description 此方法允许在运行时动态更新甘特图的配置。
* 只需要传入需要更改的配置项,其他配置项将保持不变。
* 更新后会自动重新渲染相关部分以反映新的配置。
*
* @example
* ```typescript
* // 更新数据源。数据会被完全替换,除非原数据的 key 一致
* gantt.update({
* data: newTaskData
* });
*
* // 更新显示单位
* gantt.update({
* unit: 'month'
* });
*
* // 更新主题色
* gantt.update({
* primaryColor: '#ff6b6b'
* });
*
* // 批量更新多个配置
* gantt.update({
* unit: 'week',
* primaryColor: '#4ecdc4',
* dateFormat: 'YYYY-MM-DD',
* row: {
* height: 40
* }
* });
*
* // 完全替换配置(不合并)
* gantt.update(newOptions, { merge: false });
* ```
*
*/
update(t, e = { merge: !0 }) {
this.context.updateOptions(t, e);
}
/**
* 渲染甘特图视图
*
* @description 此方法通常不需要主动调用,初始化以及 `update` 中都会自动更新。 如果你需要强制刷新页面,可以在合适的时候调用此方法
*/
render() {
this.context.render(), L.info("Gantt rendered successfully.");
}
/**
* 销毁甘特图实例,清理所有资源
*
* @description 完全销毁甘特图实例并清理所有相关资源,包括:
* - 移除所有事件监听器
* - 清理 DOM 元素和事件绑定
* - 释放内存中的数据引用
* - 停止所有动画和定时器
* - 清理渲染上下文
*
* 调用此方法后,甘特图实例将不再可用,需要重新创建新实例。
* 这对于防止内存泄漏和确保组件的正确生命周期管理非常重要。
*
* @example
* ```typescript
* const gantt = new XGantt('#container', options);
* gantt.render();
*
* // 在组件卸载或页面离开时销毁
* gantt.destroy();
*
* // React 组件中的使用示例
* useEffect(() => {
* const gantt = new XGantt('#gantt-container', options);
* gantt.render();
*
* return () => {
* gantt.destroy(); // 组件卸载时清理
* };
* }, []);
* ```
*
* @warning 销毁后的实例不能再次使用,调用任何方法都可能导致错误
*/
destroy() {
L.info("Gantt destroying..."), this.events.clear(), this.context.destroy(), L.info("Gantt destroyed successfully.");
}
/**
* 跳转到指定日期
*
* @param date - 要跳转到的日期,支持多种格式:
* - Date 对象
* - ISO 日期字符串 (如 '2023-06-01')
* - 时间戳数字
* - 其他可被 Date 构造函数解析的格式
* - 如果不传入参数或传入 undefined,则跳转到今天
*
* @returns 是否成功跳转到指定日期
* - `true`: 成功跳转,视图已更新到指定日期
* - `false`: 跳转失败,可能是日期无效或超出数据范围
*
* @description 此方法将甘特图的视图定位到指定日期,使该日期在当前视窗中可见。
* 具体行为取决于当前的显示单位和视图范围:
* - 如果指定日期在当前视图范围内,视图会滚动到该日期
* - 如果指定日期超出当前数据范围,可能会扩展时间轴或返回 false
* - 跳转会触发相应的滚动动画(如果启用)
*
* @example
* ```typescript
* // 跳转到今天(默认行为)
* const success1 = gantt.jumpTo();
* const success2 = gantt.jumpTo(undefined);
*
* // 跳转到指定日期
* const success3 = gantt.jumpTo('2023-06-01');
* const success4 = gantt.jumpTo(new Date('2023-06-01'));
* const success5 = gantt.jumpTo(1685577600000); // 时间戳
*
* // 检查跳转结果
* if (gantt.jumpTo('2023-12-25')) {
* console.log('成功跳转到圣诞节');
* } else {
* console.log('跳转失败,日期可能超出范围');
* }
*
* // 跳转到项目开始日期
* const projectStartDate = data[0]?.startTime;
* if (projectStartDate) {
* gantt.jumpTo(projectStartDate);
* }
* ```
*/
jumpTo(t) {
return this.context.jumpTo(t);
}
/**
* 注册事件监听器
*
* @template K - 事件名称的类型
* @param event - 要监听的事件名称
* @param cb - 事件回调函数
*
* @description 为甘特图注册事件监听器,支持监听各种用户交互和状态变化事件。
* 同一个事件注册多个,只会执行最后一个监听器。
*
* 支持的事件类型包括:
* - `loaded`: 加载完成事件,组件初始化完成后触发
* - `error`: 错误事件,当组件发生错误时触发
* - `update:link`: 关联线更新事件
* - `create:link`: 关联线创建事件
* - `select:link`: 关联线选择事件
* - `select`: 任务选择事件
* - `click:row`: 行点击事件
* - `dblclick:row`: 行双击事件
* - `contextmenu:row`: 行右键菜单事件
* - `click:slider`: 任务条点击事件
* - `dblclick:slider`: 任务条双击事件
* - `contextmenu:slider`: 任务条右键菜单事件
* - `move`: 任务移动事件
*
* @example
* ```typescript
* // 监听任务选择事件
* gantt.on('select', (selectedData, isChecked, allSelectedData) => {
* console.log('选择状态:', isChecked);
* console.log('当前选择的数据:', selectedData);
* console.log('所有选择的数据:', allSelectedData);
* });
*
* // 监听行点击事件
* gantt.on('click:row', (event, rowData) => {
* console.log('点击了行:', rowData.name);
* console.log('鼠标事件:', event);
* });
*
* // 监听任务条双击事件
* gantt.on('dblclick:slider', (event, taskData) => {
* console.log('双击了任务条:', taskData.name);
* // 可以打开任务详情弹窗
* openTaskDetailModal(taskData);
* });
*
* // 监听任务移动事件
* gantt.on('move', (moveData) => {
* moveData.forEach(item => {
* console.log(`任务 ${item.row.name} 从 ${item.old.startTime} 移动到 ${item.row.startTime}`);
* });
* });
*
* // 监听关联线创建事件
* gantt.on('create:link', (link) => {
* console.log('创建了新的关联线:', link);
* // 可以保存到后端
* saveLinkToServer(link);
* });
*
* // 监听错误事件
* gantt.on('error', (error) => {
* console.error('甘特图发生错误:', error);
* // 可以上报错误或显示用户友好的错误信息
* showErrorNotification(error.message);
* });
* ```
*
* @see {@link EventMap} 查看所有可用事件及其参数类型
*/
on(t, e) {
var i;
this.events.has(t) || this.events.set(t, []), (i = this.events.get(t)) == null || i.push(e);
}
}
Nt();
const ti = St;
export {
Ze as XGantt,
F as colorjs,
si as dayjs,
Z as generateId,
ti as version
};