Twproject Gantt开源甘特图功能扩展
1、Twproject Gantt甘特图介绍
Twproject Gantt 是一款基于 jQuery 开发的甘特图组件,也可以创建其它图表,例如任务树(Task Trees)。内置编辑、缩放和 CSS 皮肤等功能。更重要的是,它是免费开源的。
官网地址是:https://gantt.twproject.com/ 源码可以从github下载:

2、扩展功能一:code自动层级编码,满足wbs编码要求
工作分解结构 (WBS) 代码是项目的识别您的分级显示结构中的每个任务的唯一位置的字母数字代码。WBS 代码可用于报告日程和跟踪成本。在工程系统中,应用非常广泛,相关的编码还有OBS\RBS\PBS等等。
在Microsoft Office Project中的WBS代码有两种:大纲数字和自定义WBS代码。大纲数字是最简单的 WBS 编码类型。Microsoft Office Project 将自动计算每项任务大纲数字基础上的任务列表的大纲结构编号。例如,您的任务列表中的第一个任务的编号的 1。如果该任务具有三个子任务,子任务是编号 1.1、1.2 和 1.3。大纲数字只包含数字 (无号) 和不能对其进行编辑。他们执行操作,但是,自动移动时更改任务向上或向下在任务列表中,当降级或升级任务。例如,如果子任务当前具有的大纲数字为 3.5.4,并且移列表中的一行,大纲数字将自动更新为 3.5.3。如果然后升级该相同的子任务,大纲数字将自动更新到 3.6。
理解WBS编码的概念,扩展Twproject Gantt的code编码,采用大纲数字。如下图:

对ganttMaster.js进行扩展,增加属性:isLevelCode(bool类型),是否自动对code进行编码。增加扩展方法levelCode:
GanttMaster.prototype.levelCode = function () {
if (this.tasks && this.tasks.length > 0) {
var curCodeExt = 1;
for (var i = 0; i < this.tasks.length; i++) {
var tsk = this.tasks[i];
if (tsk.level == 0) {
tsk.code = curCodeExt;
levelChildCode(tsk.getChildren(), tsk.code);
curCodeExt++;
}
}
}
function levelChildCode(cTasks, prefix) {
if (cTasks && cTasks.length > 0) {
var curCodeExt = 1;
for (var i = 0; i < cTasks.length; i++) {
var tsk = cTasks[i];
tsk.code = prefix + "." + curCodeExt;
levelChildCode(tsk.getChildren(), tsk.code);
curCodeExt++;
}
}
}
}
本函数采用递归实现:

调用步骤:
定义甘特图:var ge; //this is the hugly but very friendly global var for the gantt editor
加载甘特图模板: $("#ganttemplates").loadTemplates();
初始化甘特图:
// here starts gantt initialization
ge = new GanttMaster();
//TODO:是否自动显示bar
ge.isBrowserTaskBar = true;
//TODO:设置code是否自动编码
ge.isLevelCode = true;
var workSpace = $("#workSpace");
workSpace.css({
width: $(window).width() - 20,
height: $(window).height() - 100
});
ge.init(workSpace)
加载数据并调用层级方法:
function loadFromLocalStorage() {
var ret;
if (localStorage) {
if (localStorage.getObject("teamworkGantDemo")) {
ret = localStorage.getObject("teamworkGantDemo");
}
} else {
$("#taZone").show();
}
if (!ret || !ret.tasks || ret.tasks.length == 0) {
ret = JSON.parse($("#ta").val());
//actualiza data
var offset = new Date().getTime() - ret.tasks[0].start;
for (var i = 0; i < ret.tasks.length; i++)
ret.tasks[i].start = ret.tasks[i].start + offset;
//debugger;
}
ge.loadProject(ret);
ge.checkpoint(); //empty the undo stack
ge.levelCode();
}
可查看gantt213.html页面。
3、扩展功能二:让选择的task出现在显示窗口
3.1 效果图
选择task对应的gantt bar显示出来,且在滑动窗口居中显示,效果如下图:

3.2 ganttMaster修订
经过dom之间关系分析,找到其中的内在联系,主要增加如下方法:
GanttMaster.prototype.browserTaskBar = function (tsk) {
if (tsk && tsk instanceof Task) {
var id = tsk.id;
//找到taskBar
var taskBar = $("svg[taskid=\"" + id + "\"]");
var taskBarX = parseInt($(taskBar).attr("x"));
var taskBarWidth = parseInt($(taskBar).attr("width"));
//获取svg最外层画布canvas
var canvas = $(taskBar).parent().parent().parent();
var canvasWidth = $(canvas).width();
//获取滚动区域
var scroll = $(taskBar).parent().parent().parent().parent();
var scrollWidth = $(scroll).width();
var scrollScrollWidth = canvasWidth - scrollWidth + 17;
//获取水平滚动条要移动的位置
var centerLeft = (taskBarX + taskBarWidth / 2);
var scrollLeft = (centerLeft – scrollWidth/2) / canvasWidth * scrollScrollWidth;
console.log("-------------------------------------------------------");
console.log("canvas width:" + canvasWidth); //画布区域大小
console.log("scroll width:" + scrollWidth); //滚动区域大小
console.log("scroll scroll max width:" + scrollScrollWidth); //滚动区域最大滑动区域
console.log("scroll left position(old):" + $(scroll).scrollLeft()); //滚动区域滑块位置(旧)
$(scroll).scrollLeft(scrollLeft); //设置滑块位置
console.log("scroll left position(new):" + $(scroll).scrollLeft()); //滚动区域滑块位置(新)
console.log("-------------------------------------------------------");
}
};
方法讲解:根据taskid找到bar,获取对应的div层与滚动窗口,设置滚动窗口的scrollLeft。
注意:红色底纹17,是如何得到的呢?这个是滚动条宽度,3.4中有详细分析。
3.3 思路与模型
设置bar在滚动区域的中心位置,就是如何设置滚动区域的scrollLeft值,这是解决问题的关键。原甘特图如下:

画布区域(灰色部分)

滚动区域(灰色部分)
对应的dom层级结构如下:

从Bar到展示区域,总共是4层嵌套。找到对应的bar,分析上层的节点间的依赖关系,从以下4个问题入手:
- (1)如何找到Bar?
- (2)上层节点哪些起决定作用?
- (3)画布区域与滚动区域的关系如何?
- (4)滚动区域的最大scrollLeft是多少?
问题一:如何找到Bar?
Bar与任务项是联动的,两者是通过taskid进行关联的,比如找到taskid=-6的甘特图形:
var id = -6;
//找到taskBar
var taskBar = $("svg[taskid=\"" + id + "\"]")
问题二:上层节点哪些起到决定作用?
上层节点只有画布区域与滚动区域起到作用,bar在这两个区域的位置是如何的?通过分析dom结构,建立以下模型:

模型示意图1
注意事项:(1)垂直滚动条暂不考虑。(2)task bar相对于画布区域的坐标x是不变的。
问题三:画布区域与滚动区域的关系如何?
从模型示意图来看,滚动区域必须而且正好可以查看画布区域,要保证这点,canvasWidth与scrollScrollWidth是一定的比例关系,则比例系数为scale=canvasWidth/scrollScrollWidth,表示滑动区域的比例,例如滑动区域向左滑动1,则画布区域则向右滑动scale。
(1)当出现滚动条时,canvasWidth>scrollScrollWidth>scrollWidth,而scale>1
(2)当滚动区域宽度增加时,scrollScrollWidth是在逐渐变小
(3)未出现滚动条时,scrollScrollWidth = 0
解惑,从模型来看,scrollWidth应该是大于scrollScrollWidth的吧?如何把比自己更大的画布区域包括进来,就是依靠滚动区域,这里可看作scrollScrollWidth是对scrollWidth的放大,其放到比例就是scale。
问题四:滚动区域最大scrollLeft是多少
如何获取某一时刻,最大scollLeft。解决办法,通过chrome浏览器打开甘特图,将滚动区域的滑块拉到最左边,在console窗口输入$("div[class='splitElement splitBox2']").scrollLeft();可得到。如下图:

3.4 数字分析确定依赖关系
根据chrome调试器,可获取canvasWidth、scrollWidth、scrollScrollWidth,甘特图原始状态下,使用两个浏览器记测试,数据记录如下:

Excel分析图表1
对canvasWidth-scrollWidth与scrollScrollWidth比较,绝对值都为17,得到结果为:
var scrollScrollWidth = canvasWidth - scrollWidth + 17
如果甘特图处于放到、缩小状态,是否成立呢?再次测试结果如下:

Excel分析图表2
无论甘特图如何缩放,公式依然成立。这就找到了滚动窗口最大滑动区域scrollScrollWidth,bar的显示位置,对应的值就是scrollScrollWidth的一部分。把模型中的bar至于中心位置,如下图:

模型示意图2
上图清晰的给出以下结论:left=centerLeft - scrollWidth/2,计算滑块的位置,也就是找到left在滑块上的映射scrollLeft,结合scale系数,可计算出scrollLeft = left * scale。
这样就实现了定位scrollLeft,真的是这样吗?经过测试,发现bar在滚动区域,并不在中心位置。从分析方法来看,比较臃肿、复杂,要简化处理,如何做呢?下面将继续进行分销模型并优化。
3.5 模型深入分析与优化
在模型分析中,没有对遮挡区域进行解析,分析图表如下:

模型示意图3
遮挡区域宽度maskWidth(maskWidth1+maskWidth2)=canvasWidth – scrollWidth,与scrollScrollWidth相差17,也就是scrollScrollWidth≈maskWidth。而滚动条的存在,正是滑动遮挡区域,scrollLeft≈left,这样就非常简单化了。考虑17呢?为什么是固定值?而不是变量值呢?
为了弄懂这个问题,我们使用QQ截图滚动区域的垂直滚动条,如下图:

推测17是垂直滚动条的宽度,对此可忽略不计,则scrollScrollWidth=maskWidth,可以看作scrollLeft=left=maskWidth1,实施也的确如此。
修订后的js代码如下(也包括获取svg相关属性的修订):
GanttMaster.prototype.browserTaskBar = function (tsk) {
if (tsk && tsk instanceof Task) {
var id = tsk.id;
//找到taskBar
var taskBar = $("svg[taskid=\"" + id + "\"]");
//var taskBarX = $(taskBar)[0].getBoundingClientRect().left;
var taskBarX = parseFloat($(taskBar)[0].getAttribute("x"));
var taskBarWidth = parseFloat($(taskBar)[0].getBoundingClientRect().width);
//获取svg最外层画布canvas
var canvas = $(taskBar).parent().parent().parent();
var canvasWidth = parseFloat($(canvas).width());
//获取滚动区域
var scroll = $(taskBar).parent().parent().parent().parent();
var scrollWidth = parseFloat($(scroll).width());
//获取水平滚动条要移动的位置
var centerLeft = (taskBarX + taskBarWidth / 2.0);
var scrollLeft = (centerLeft - scrollWidth / 2.0);
var oldScrollLeft = $(scroll).scrollLeft();
if (Math.abs(oldScrollLeft - scrollLeft) >= 1.0) {
$(scroll).scrollLeft(scrollLeft); //设置滑块位置
} else {
return;
}
console.log("-------------------------------------------------------");
console.log("task left:" + taskBarX);
console.log("task width:" + taskBarWidth);
console.log("canvas width:" + canvasWidth); //画布区域大小
console.log("scroll width:" + scrollWidth); //滚动区域大小
console.log("scroll left position(old):" + oldScrollLeft); //滚动区域滑块位置(旧)
console.log("scroll left position(new):" + scrollLeft); //滚动区域滑块位置(新)
console.log("-------------------------------------------------------");
}
};
运行后的效果图如下:

最终优化后的代码:http://files.cnblogs.com/files/zsy/gantt.rar
温馨提示,如对您有帮助,麻烦赞一下。~~~~~~~~~~
Twproject Gantt开源甘特图功能扩展的更多相关文章
- 【转载】 JQuery.Gantt(甘特图) 开发指南
转载来自: http://www.cnblogs.com/liusuqi/archive/2013/06/09/3129293.html JQuery.Gantt是一个开源的基于JQuery库的用于实 ...
- JQuery.Gantt(甘特图)开发
一.简介 JQuery.Gantt是一个开源的基于JQuery库的用于实现甘特图效果的可扩展功能的JS组件库. 二.前端页面 2.1 资源引用 首先需要将下载到的源码中的CSS.IMG.JS等资源放入 ...
- Twproject Gantt – 开源的 JavaScript 甘特图组件
Twproject Gantt 是一款基于 jQuery 开发的甘特图组件,也可以创建其它图表,例如任务树(Task Trees).内置编辑.缩放和 CSS 皮肤等功能.更重要的是,它是免费开源的. ...
- jquery 甘特图开发指南
JQuery.Gantt是一个开源的基于JQuery库的用于实现甘特图效果的可扩展功能的JS组件库. <link rel="stylesheet" href="cs ...
- 免费JS甘特图组件dhtmlxgantt
安装 参考:https://docs.dhtmlx.com/gantt/desktop__install_with_bower.html 可使用NuGet.Bower.npm包管理器安装(应用在asp ...
- 一款开源且功能强大的C#甘特图控件.NET Winforms Gantt Chart Control
甘特图在项目管理中非常重要,甘特图的思想比较简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间.它直观地表明任务计划在什么时候进行,及实际进展与计划要求的对比.管理 ...
- MVC使用Gantt Chart实现甘特图,管理事情进度
借助"甘特图",可以直观地了解任务.活动.工作的进度.dhtmlxGantt是一个开源的Javacirpt库,能帮助我们快速创建"甘特图",本篇体验在MVC中的 ...
- gantt甘特图可拖拽、编辑(vue、react都可用 highcharts)
前言 Excel功能强大,应用广泛.随着web应用的兴起和完善,用户的要求也越来越高.很多Excel的功能都搬到了sass里面.恨不得给他们做个Excel出来...程序员太难了... 去年我遇到了 ...
- 甘特图 (Gantt )的优缺点
时间管理 - 甘特图 (Gantt ) 优点:甘特图直观.简单.容易制作,便于理解,能很清晰地标识出直到每一项任务的起始与结束时间,一般适用比较简单的小型项目,可用于WBS的任何层次.进度控制.资源优 ...
随机推荐
- 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念
一.前言 DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...
- 代码的坏味道(20)——过度耦合的消息链(Message Chains)
坏味道--过度耦合的消息链(Message Chains) 特征 消息链的形式类似于:obj.getA().getB().getC(). 问题原因 如果你看到用户向一个对象请求另一个对象,然后再向后者 ...
- 基于SOA架构的TDD测试驱动开发模式
以需求用例为基,Case&Coding两条线并行,服务(M)&消费(VC)分离,单元.接口.功能.集成四层质量管理,自动化集成.测试.交付全程支持. 3个大阶段(需求分析阶段.研发准备 ...
- [BOT]自己动手实现android 饼状图,PieGraphView,附源码解析
本文要介绍的是一个参照手机支付宝app里面记账本功能里的"饼状图"实现的控件.通常app中可能的数据展示控件有柱状图,折线图,饼状图等,如果需要一个包含多种View控件的库,那么 ...
- Mono 3.2.3 TCP吞吐性能测试报告
在前几天简单地测试了一下Mono 3.2.3 TCP处理的稳定性,有同学问Mono 3.2.3的TCP处理性有怎样,以下是针对Mono 3.2.3TCP在吞吐方面的性能测试.主要测试分两种场分别是连接 ...
- 解决托管在Windows上的Stash的Pull request无法合并的问题
最近尝试合并一个托管在Windows的Stash系统中的pull request时,发现合并按钮被禁用,显示有冲突不能合并,但是在diff页面中没有现实冲突,而且代码实际上并没有任何冲突. 后来在这篇 ...
- 【转】ofbiz数据库表结构设计
真心不错的文章,可以加深对企业信息化的设计理解:) http://blog.sina.com.cn/s/blog_a2ca5d8c01017fa0.html http://blog.sina.com. ...
- 按照Enterprise Integration Pattern搭建服务系统
在前一篇文章中,我们已经对Enterprise Integration Pattern中所包含的各个组成进行了简单地介绍.限于篇幅(20页Word以内),我并没有深入地讨论各个组成.但是如果要真正地按 ...
- C#将Word转换成PDF方法总结(基于Office和WPS两种方案)
有时候,我们需要在线上预览word文档,当然我们可以用NPOI抽出Word中的文字和表格,然后显示到网页上面,但是这样会丢失掉Word中原有的格式和图片.一个比较好的办法就是将word转换成pdf,然 ...
- useful commands for Kubernetes beginners
Get pod ip and their coordinating NODE $ kubectl get pods -o wide If you want to get detailed inform ...