|
@@ -1,5 +1,4 @@
|
|
|
import moment from 'moment';
|
|
|
-// import './g.js';
|
|
|
/**
|
|
|
* 数据定义区域
|
|
|
*
|
|
@@ -10,7 +9,7 @@ import moment from 'moment';
|
|
|
*/
|
|
|
export function GanttChart(options) {
|
|
|
// 任务列表
|
|
|
- this.tasks = [];
|
|
|
+ this.tasks = options.tasks || [];
|
|
|
// AntVG Canvas
|
|
|
this.gCanvas = null;
|
|
|
// 视口宽度 800,可视区域
|
|
@@ -35,22 +34,28 @@ export function GanttChart(options) {
|
|
|
// 每天的间隔宽度
|
|
|
this.dayStep = 40;
|
|
|
// 分组标题高度
|
|
|
- this.groupTitleHeight = 30;
|
|
|
+ this.groupTitleHeight = 38;
|
|
|
// 任务矩形高度
|
|
|
this.taskRowHeight = 16;
|
|
|
+ // 每行任务的纵向间距
|
|
|
+ this.rowSpanDis = 22;
|
|
|
// 总天数
|
|
|
this.daysCount = options['daysCount'] || 60;
|
|
|
+ // 任务图距离顶部高度
|
|
|
+ this.graphTopDis = 20
|
|
|
|
|
|
// 每像素代表的小时数
|
|
|
this.timePerPix = this.cWidth/this.daysCount/24/3600
|
|
|
// 当前视图开始时间,向前推N天
|
|
|
this.startAt = moment().subtract(this.daysCount / 3, 'days');
|
|
|
this.endAt = moment(this.startAt).add(this.daysCount, 'days');
|
|
|
- this.graphDiv = document.getElementById('graphDiv');
|
|
|
+ this.graphDiv = document.getElementById(options['chartContainer']);
|
|
|
// 图形容器组
|
|
|
this.graphGroup = null;
|
|
|
// 上一次拖动的事件
|
|
|
this.lastDragEv = null;
|
|
|
+ // 回调事件
|
|
|
+ this.callback = options.callback || null;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -66,14 +71,14 @@ GanttChart.prototype.changeTasks = function(_tasks){
|
|
|
* 打开关闭分组
|
|
|
*/
|
|
|
|
|
|
-GanttChart.prototype.toggle = function(no) {
|
|
|
- if (tasks[no].open) {
|
|
|
- tasks[no].open = false;
|
|
|
+GanttChart.prototype.toggle = function(index) {
|
|
|
+ if (this.tasks[index].open) {
|
|
|
+ this.tasks[index].open = false;
|
|
|
} else {
|
|
|
- tasks[no].open = true;
|
|
|
+ this.tasks[index].open = true;
|
|
|
}
|
|
|
- processData();
|
|
|
- drawTasks();
|
|
|
+ this.processData();
|
|
|
+ this.drawTasks();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -86,15 +91,15 @@ GanttChart.prototype.processData = function() {
|
|
|
currentTopTask.renderOptions = {};
|
|
|
if (i != 0) {
|
|
|
// 非0个,要补上前面的数据
|
|
|
- lastTopTask = tasks[i - 1];
|
|
|
+ lastTopTask = this.tasks[i - 1];
|
|
|
currentTopTask.renderOptions.startY = lastTopTask.renderOptions.endY + 20;
|
|
|
} else {
|
|
|
// 第一个
|
|
|
- currentTopTask.renderOptions.startY = 120;
|
|
|
+ currentTopTask.renderOptions.startY = this.graphTopDis;
|
|
|
}
|
|
|
if (currentTopTask.open) {
|
|
|
currentTopTask.renderOptions.endY =
|
|
|
- currentTopTask.renderOptions.startY + this.groupTitleHeight + currentTopTask.dataList.length * this.taskRowHeight;
|
|
|
+ currentTopTask.renderOptions.startY + this.rowSpanDis + this.groupTitleHeight + currentTopTask.dataList.length * this.taskRowHeight;
|
|
|
} else {
|
|
|
currentTopTask.renderOptions.endY = currentTopTask.renderOptions.startY + this.groupTitleHeight;
|
|
|
}
|
|
@@ -135,10 +140,10 @@ GanttChart.prototype.pageTo = function(dir = 'next') {
|
|
|
} else {
|
|
|
// 向前翻页
|
|
|
this.startAt = this.startAt.subtract(this.daysCount, 'days');
|
|
|
- this.offsetDis = 1800 //2*viewWidth
|
|
|
+ this.offsetDis = 2*this.viewWidth
|
|
|
}
|
|
|
this.endAt = moment(this.startAt).add(this.daysCount, 'days');
|
|
|
- console.log('已翻页', this.startAt.format('YYYY-MM-DD'),this.endAt.format('YYYY-MM-DD'));
|
|
|
+ console.log('已翻页', this.startAt.format('YYYY-MM-DD'),this.endAt.format('YYYY-MM-DD'), this.offsetDis);
|
|
|
// offsetDis = viewWidth;
|
|
|
this.forceRefreshGraph();
|
|
|
}
|
|
@@ -153,7 +158,7 @@ GanttChart.prototype.doDrag = function(sEvent, eEvent) {
|
|
|
if (sEvent == null) {
|
|
|
sEvent = this.startEvent;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
let sPos = sEvent.clientX;
|
|
|
let cPos = eEvent.clientX;
|
|
|
// 滚动距离
|
|
@@ -164,16 +169,16 @@ GanttChart.prototype.doDrag = function(sEvent, eEvent) {
|
|
|
// console.log('draging...',tempDis, this.offsetDis, dis)
|
|
|
if (this.offsetDis <= -20) {
|
|
|
// 向前滑动,向前翻页
|
|
|
- console.log('此处应该向前翻页', this.startAt.format('YYYY-MM-DD'),this.endAt.format('YYYY-MM-DD'));
|
|
|
+ console.log('此处应该向前翻页', this.startAt.format('YYYY-MM-DD'),this.endAt.format('YYYY-MM-DD'),this.offsetDis);
|
|
|
this.offsetDis = this.viewWidth;
|
|
|
this.pageTo('prev');
|
|
|
}
|
|
|
- if (this.offsetDis - 20 >= 1800 ){ //cWidth - viewWidth) {
|
|
|
+ if (this.offsetDis - 20 >= 2964 ){ //cWidth - viewWidth) {
|
|
|
// 向后滑动,向后翻页
|
|
|
- console.log('此处应该向后翻页', this.startAt.format('YYYY-MM-DD'),this.endAt.format('YYYY-MM-DD'));
|
|
|
+ console.log('此处应该向后翻页', this.startAt.format('YYYY-MM-DD'),this.endAt.format('YYYY-MM-DD'),this.offsetDis);
|
|
|
this.offsetDis = this.viewWidth;
|
|
|
this.pageTo('next');
|
|
|
- }
|
|
|
+ }
|
|
|
this.graphDiv.scrollLeft = this.offsetDis;
|
|
|
}
|
|
|
|
|
@@ -183,7 +188,7 @@ GanttChart.prototype.doDrag = function(sEvent, eEvent) {
|
|
|
|
|
|
GanttChart.prototype.initDragHandler = function() {
|
|
|
this.graphDiv.scrollLeft = this.offsetDis;
|
|
|
- let _canvas = document.getElementsByTagName('canvas')[0];
|
|
|
+ let _canvas = document.getElementsByTagName('canvas')[1];
|
|
|
_canvas.addEventListener('mousedown', (ev) => {
|
|
|
this.draging = true;
|
|
|
this.startEvent = ev;
|
|
@@ -200,6 +205,7 @@ GanttChart.prototype.initDragHandler = function() {
|
|
|
});
|
|
|
|
|
|
_canvas.addEventListener('mousemove', (ev) => {
|
|
|
+ // console.log('this over', this)
|
|
|
if (this.draging) {
|
|
|
if (new Date() - this.lastClickAt < 20) {
|
|
|
return false;
|
|
@@ -209,6 +215,11 @@ GanttChart.prototype.initDragHandler = function() {
|
|
|
this.lastDragEv = ev;
|
|
|
}
|
|
|
});
|
|
|
+ _canvas.addEventListener('mouseleave', (ev) => {
|
|
|
+ console.log('leave...恢复')
|
|
|
+ this.draging = false;
|
|
|
+ this.endEvent = ev;
|
|
|
+ });
|
|
|
}
|
|
|
/**
|
|
|
* 初始化画布
|
|
@@ -218,7 +229,7 @@ GanttChart.prototype.initDragHandler = function() {
|
|
|
GanttChart.prototype.initCanvas = function() {
|
|
|
this.gCanvas = new G.Canvas({
|
|
|
container: 'ganttContainer',
|
|
|
- width: 2400,
|
|
|
+ width: this.cWidth,
|
|
|
height: 800,
|
|
|
});
|
|
|
}
|
|
@@ -240,7 +251,7 @@ GanttChart.prototype.drawTimeZone = function() {
|
|
|
fontSize: 12,
|
|
|
text: start.format('YYYY-MM'),
|
|
|
lineDash: [10, 10],
|
|
|
- fill: 'red',
|
|
|
+ fill: '#8D9399',
|
|
|
},
|
|
|
});
|
|
|
timeGroup.addShape('text', {
|
|
@@ -250,7 +261,7 @@ GanttChart.prototype.drawTimeZone = function() {
|
|
|
fontSize: 12,
|
|
|
text: start.add(this.daysCount / 3, 'days').format('YYYY-MM'),
|
|
|
lineDash: [10, 10],
|
|
|
- fill: 'red',
|
|
|
+ fill: '#8D9399',
|
|
|
},
|
|
|
});
|
|
|
timeGroup.addShape('text', {
|
|
@@ -260,13 +271,13 @@ GanttChart.prototype.drawTimeZone = function() {
|
|
|
fontSize: 12,
|
|
|
text: start.add(this.daysCount / 3, 'days').format('YYYY-MM'),
|
|
|
lineDash: [10, 10],
|
|
|
- fill: 'red',
|
|
|
+ fill: '#8D9399',
|
|
|
},
|
|
|
});
|
|
|
let startSecond = moment(this.startAt);
|
|
|
// 绘制第二级
|
|
|
for (let i = 0; i < this.daysCount; i++) {
|
|
|
- let timeText = startSecond.add(1, 'days').format('MM-DD');
|
|
|
+ let timeText = startSecond.add(1, 'days').format('DD');
|
|
|
timeGroup.addShape('text', {
|
|
|
attrs: {
|
|
|
x: 40 * i,
|
|
@@ -274,7 +285,7 @@ GanttChart.prototype.drawTimeZone = function() {
|
|
|
fontSize: 10,
|
|
|
text: timeText,
|
|
|
lineDash: [10, 10],
|
|
|
- fill: 'red',
|
|
|
+ fill: '#8D9399',
|
|
|
},
|
|
|
});
|
|
|
}
|
|
@@ -284,19 +295,22 @@ GanttChart.prototype.drawTimeZone = function() {
|
|
|
* 处理点击
|
|
|
*/
|
|
|
GanttChart.prototype.handleClick = function(task, flag, ev) {
|
|
|
- let detailDiv = document.getElementById('detailDiv')
|
|
|
+ // let detailDiv = document.getElementById('detailDiv')
|
|
|
if(flag == 'enter'){
|
|
|
- detailDiv.style.display = 'block'
|
|
|
- detailDiv.style.left = ev.clientX+'px';
|
|
|
- detailDiv.style.top = ev.clientY+'px';
|
|
|
- document.getElementById('detailTaskName').textContent = task._pdata.description
|
|
|
- document.getElementById('detailTaskStatus').textContent = task._pdata.status
|
|
|
- document.getElementById('detailTaskStartDate').textContent = task._pdata.startDate
|
|
|
- document.getElementById('detailTaskEndDate').textContent = task._pdata.endDate
|
|
|
+ // detailDiv.style.display = 'block'
|
|
|
+ // detailDiv.style.left = ev.clientX+'px';
|
|
|
+ // detailDiv.style.top = ev.clientY+'px';
|
|
|
+ // document.getElementById('detailTaskName').textContent = task._pdata.description
|
|
|
+ // document.getElementById('detailTaskStatus').textContent = task._pdata.status
|
|
|
+ // document.getElementById('detailTaskStartDate').textContent = task._pdata.startDate
|
|
|
+ // document.getElementById('detailTaskEndDate').textContent = task._pdata.endDate
|
|
|
console.log('show:', task);
|
|
|
- }else{
|
|
|
- detailDiv.style.display = 'none'
|
|
|
+ } else if (flag === 'leave'){
|
|
|
+ // detailDiv.style.display = 'none'
|
|
|
console.log('hide:', task);
|
|
|
+ } else {
|
|
|
+ this.callback(task);
|
|
|
+ console.log('click:', task);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -343,25 +357,28 @@ GanttChart.prototype.drawTasks = function() {
|
|
|
this.graphGroup = this.gCanvas.addGroup();
|
|
|
this.graphGroup._tname = 'graphGroup';
|
|
|
}
|
|
|
+ // 第一层循环,用于分组,例如,维保--xxxx
|
|
|
this.tasks.forEach((topTask, topIndex) => {
|
|
|
if (topTask.open) {
|
|
|
let taskGroup = null;
|
|
|
taskGroup = this.graphGroup.addGroup();
|
|
|
taskGroup._tname = 'TaskGroup_' + topTask.id;
|
|
|
- topTask.gGroup = taskGroup;
|
|
|
+ topTask.gGroup = taskGroup;
|
|
|
+ // 第二层循环,用于 区分具体多少任务,例如,维保-商管1/商管2...
|
|
|
topTask.dataList.forEach((taskP, index) => {
|
|
|
- // 在视图中才显示
|
|
|
let taskPGroup = taskGroup.addGroup();
|
|
|
taskGroup.addGroup(taskPGroup);
|
|
|
+ // 第三层循环,用户区分每个子任务的执行时间段,例如:维保-商管1-2020.05-2020.06 / 2020.08- 2020.09
|
|
|
taskP.tasks.forEach((_taskItem, _index) => {
|
|
|
let _isInView = this.isInView(_taskItem)
|
|
|
+ // 在视图中才显示
|
|
|
if(_isInView){
|
|
|
let pos = this.calRectPos(_taskItem);
|
|
|
// console.log('render rect:', _taskItem, pos, topTask.renderOptions.startY + index * taskRowHeight);
|
|
|
let rectEl = taskPGroup.addShape('rect', {
|
|
|
attrs: {
|
|
|
x: pos.x,
|
|
|
- y: topTask.renderOptions.startY + (index* this.taskRowHeight),
|
|
|
+ y: topTask.renderOptions.startY + (index* (this.taskRowHeight + this.rowSpanDis)),
|
|
|
width: pos.width,
|
|
|
height: this.taskRowHeight,
|
|
|
fill: this.statusColor(_taskItem),
|
|
@@ -376,6 +393,9 @@ GanttChart.prototype.drawTasks = function() {
|
|
|
rectEl.on('mouseleave', (ev) => {
|
|
|
this.handleClick(ev.target, 'leave', ev);
|
|
|
});
|
|
|
+ rectEl.on('click', (ev) => {
|
|
|
+ this.handleClick(ev.target, 'click', ev);
|
|
|
+ });
|
|
|
}
|
|
|
});
|
|
|
});
|
|
@@ -398,7 +418,7 @@ GanttChart.prototype.calRectPos = function(taskItem) {
|
|
|
let duraStartAt = new Date(taskItem.startDate) - new Date(this.startAt.format('YYYY-MM-DD'));
|
|
|
let secondsStartAt = duraStartAt/1000
|
|
|
|
|
|
- let duraEndAt = new Date(taskItem.endDate) - new Date(this.startAt.format('YYYY-MM-DD'));
|
|
|
+ let duraEndAt = new Date(taskItem.endDate) - new Date(taskItem.startDate);
|
|
|
let secondsEndAt = duraEndAt/1000
|
|
|
return {
|
|
|
x: secondsStartAt * this.timePerPix,
|