js实现阿甘图可拖拽
实现阿甘图(Gantt Chart)可拖拽功能
使用JavaScript实现可拖拽的阿甘图需要结合HTML、CSS和JavaScript技术。以下是实现步骤:
HTML结构
<div id="gantt-container">
<div class="gantt-task" data-task-id="1" style="left: 50px; width: 200px;">
<div class="gantt-task-bar"></div>
<div class="gantt-task-handle left"></div>
<div class="gantt-task-handle right"></div>
</div>
</div>
CSS样式
#gantt-container {
position: relative;
height: 500px;
border: 1px solid #ccc;
overflow-x: scroll;
}
.gantt-task {
position: absolute;
height: 30px;
cursor: move;
}
.gantt-task-bar {
height: 100%;
background-color: #4CAF50;
border-radius: 3px;
}
.gantt-task-handle {
position: absolute;
width: 8px;
height: 100%;
background-color: #333;
cursor: ew-resize;
}
.gantt-task-handle.left {
left: -4px;
}
.gantt-task-handle.right {
right: -4px;
}
JavaScript实现
document.addEventListener('DOMContentLoaded', function() {
const tasks = document.querySelectorAll('.gantt-task');
tasks.forEach(task => {
const bar = task.querySelector('.gantt-task-bar');
const leftHandle = task.querySelector('.gantt-task-handle.left');
const rightHandle = task.querySelector('.gantt-task-handle.right');
let isDragging = false;
let isResizingLeft = false;
let isResizingRight = false;
let startX, startLeft, startWidth;
// 任务条拖动
bar.addEventListener('mousedown', function(e) {
isDragging = true;
startX = e.clientX;
startLeft = parseInt(task.style.left) || 0;
e.preventDefault();
});
// 左侧调整大小
leftHandle.addEventListener('mousedown', function(e) {
isResizingLeft = true;
startX = e.clientX;
startLeft = parseInt(task.style.left) || 0;
startWidth = parseInt(task.style.width) || 0;
e.preventDefault();
});
// 右侧调整大小
rightHandle.addEventListener('mousedown', function(e) {
isResizingRight = true;
startX = e.clientX;
startWidth = parseInt(task.style.width) || 0;
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!isDragging && !isResizingLeft && !isResizingRight) return;
const dx = e.clientX - startX;
if (isDragging) {
const newLeft = startLeft + dx;
task.style.left = `${newLeft}px`;
}
if (isResizingLeft) {
const newLeft = startLeft + dx;
const newWidth = startWidth - dx;
if (newWidth > 30) { // 最小宽度限制
task.style.left = `${newLeft}px`;
task.style.width = `${newWidth}px`;
}
}
if (isResizingRight) {
const newWidth = startWidth + dx;
if (newWidth > 30) { // 最小宽度限制
task.style.width = `${newWidth}px`;
}
}
});
document.addEventListener('mouseup', function() {
isDragging = false;
isResizingLeft = false;
isResizingRight = false;
});
});
});
功能扩展建议
-
时间轴同步 添加时间轴标尺并与任务位置同步,便于直观了解任务时间跨度。
-
数据绑定 将任务位置和尺寸与后台数据绑定,实现持久化存储:
function saveTaskData(taskId, left, width) { // 保存到数据库或本地存储 } -
限制范围 添加容器边界检测,防止任务被拖出可视区域:
const container = document.getElementById('gantt-container'); const containerWidth = container.offsetWidth; // 在拖动和调整大小逻辑中添加边界检查 if (newLeft < 0) newLeft = 0; if (newLeft + newWidth > containerWidth) newWidth = containerWidth - newLeft; -
依赖关系 实现任务间的依赖关系连线,使用SVG或Canvas绘制连线。
-
性能优化 对于大量任务,考虑使用虚拟滚动技术只渲染可视区域内的任务。
使用现成库的替代方案
如果需要更完整的解决方案,可以考虑以下专门用于阿甘图的JavaScript库:
-
dhtmlxGantt
gantt.init("gantt_container"); gantt.config.drag_move = true; gantt.config.drag_resize = true; -
Frappe Gantt
const gantt = new Gantt("#gantt", tasks, { draggable: true, on_click: function(task) { ... }, on_date_change: function(task, start, end) { ... } }); -
jQuery Gantt
$("#gantt").gantt({ source: tasks, itemsPerPage: 10, draggable: true });
这些库提供了更丰富的功能,包括任务分组、关键路径分析、资源分配等高级特性。







