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

温馨提示,如对您有帮助,麻烦赞一下。~~~~~~~~~~

时间: 2024-08-21 07:03:04

Twproject Gantt开源甘特图功能扩展的相关文章

JQuery.Gantt(甘特图)开发

一.简介 JQuery.Gantt是一个开源的基于JQuery库的用于实现甘特图效果的可扩展功能的JS组件库. 二.前端页面 2.1 资源引用 首先需要将下载到的源码中的CSS.IMG.JS等资源放入我们自己的项目中,然后在我们自己的页面中引用需要的资源文件. CSS样式文件 <link rel="stylesheet" href="css/style.css" /> JS脚本文件 <script src="js/jquery-1.8.2

XMind甘特图功能使用教程

XMind甘特图被广泛的应用于项目管理,任务跟进,它的直观.简洁.灵活成为用户选择的首要理由.XMind甘特图图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间,让我们能够对任务项目进行一手掌握.那我们又该如何使用XMind甘特图功能呢. 打开XMind思维导图后,创建导图,罗列信息. 点击[视图]中的"甘特图"选项,或者直接点击工具栏中的甘特图图标. XMind甘特图中将会按顺序展现主题任务.每一个横向任务条则为一个完整的任务信息. 如果先前导图设有关于任务

图表推荐:甘特图与框架图,大数据流向地图重磅来袭!

帆软图表(新特性)最新版本的图表插件新增了甘特图与框架图两种图表类型,大大方便了生产管理所需,同时支持流向地图的大数据模式. 一.甘特图 甘特图又称任务计划进度图,其通常用来表示项目进展随着时间进度的变化.甘特图被广泛的应用在各行业的项目管理中,因此帆软在最新的图表插件中,新增了该图表类型,以满足任务进度可视化的需求. FineReport新甘特图功能扩展十分强大,能够满足多层级项目所需以及多系列任务:支持各个任务的里程碑设置.进度管理等:包含四种任务关联线 (开始-完成,开始-开始,完成-开始

jquery 甘特图开发指南

JQuery.Gantt是一个开源的基于JQuery库的用于实现甘特图效果的可扩展功能的JS组件库. <link rel="stylesheet" href="css/style.css" /><script src="js/jquery-1.7.min.js"></script><script src="js/jquery.fn.gantt.js" charset ="GB

JS甘特图 JQuery.Ganttyy

JQuery.Gantt是一个开源的基于JQuery库的用于实现甘特图效果的可扩展功能的JS组件库.它既可以图形化行程安排,也可以展示数据分布. 本人在原有基础上,修改了部分代码,较原有功能外,主要改进为: 1.修正"某一条数据为空时原有的代码js会报错的问题". 2.修正"ie显示时进度条会闪烁的问题". 3.json的数据不再为new Date(时间戳)的形式,直接为时间戳 下载地址为:待定 页面展示为: 其中,框1为上下翻页,框2表示滚动到当前时间,框3为滚动

依赖关系助力XMind 6中的甘特图

在XMind 6思维导图中,用户可以利用甘特图功能来进行项目管理,在项目实施过程中,您可能会经常需要为某两个任务之间建立一种依赖关系.现在,我们可以很方便地在XMind 6甘特图里面轻松做到这点. 在XMind 6甘特图中建立依赖关系步骤: 步骤一 选择某一任务主题. 步骤二 进入任务信息视图,从菜单选择[视图],点击"任务信息"选项. 步骤三 滚动到视图的底部,在任务关联对象一栏点击加号添加. 步骤四 在对话框中选择关联的任务主题. 步骤五 确定依赖关系的类型. ?截止日期-至-开始

Mindmanager 甘特图杠上Mindmanager 鱼骨图

MindManager中文版作为一种优秀的思维导图工具,加入甘特图功能后,使其功能更加强大,应用范围更广泛.而推荐用MindManager甘特图来作为项目管理,原因有一下几点: 1.MindManager甘特图通过将任务管理图形化,将复杂的规划简洁化,已与理解. 2.能够很好的掌控中小型项目的任务进程和情况. 3.在MindManager 15中文版的软件支持下,无须担心复杂的计算和分析. 4.可以通过建立关联.依赖关系将各项目任务间紧密联系,使得更为系统. 在MindManager 中文版中,

如何绘制项目管理甘特图

在工作效率和时间管理领域,甘特图是元老级别的存在,它起源于第一次世界大战期间,但却没有被用于项目管理和工作计划,而是作为一种计划批量生产的生产规划工具而成熟.它最初通过将时间序列的生产要求与各个项目部分相连接,进一步确定每日生产量.甘特图的简单和易理解让他在战争年代非常受欢迎,直到现在依然会有很多知名企业都在用甘特图做工作计划. 用甘特图可以给你的工作带来什么? “我知道我的任务是晚了,但我不知道,这对整个过程有如此大的影响.”人们面对甘特图的时候是很难说出这样的话的.因为通过甘特图的可视化规划

如何绘制项目进度计划甘特图

在工作效率和时间管理领域,甘特图是元老级别的存在,它起源于第一次世界大战期间,但却没有被用于项目管理和工作计划,而是作为一种计划批量生产的生产规划工具而成熟.它最初通过将时间序列的生产要求与各个项目部分相连接,进一步确定每日生产量.甘特图的简单和易理解让他在战争年代非常受欢迎,直到现在依然会有很多知名企业都在用甘特图做工作计划. 用甘特图可以给你的工作带来什么? “我知道我的任务是晚了,但我不知道,这对整个过程有如此大的影响.”人们面对甘特图的时候是很难说出这样的话的.因为通过甘特图的可视化规划