甘特图的数据结构分为两部分,任务的数据和任务依赖关系的数据。这种设计大幅度的降低了数据之间的耦合关系,也更加接近于我们平时的数据库设计,降低了和数据库接口之间的难度。
先看一个任务的数据结构简单的XML的例子。
1. <Tasks>
2. <Task>
3. <Id>1</Id>
4. <Name>Planning</Name>
5. <StartDate>2010-01-18T00:00:00-08:00</StartDate>
6. <EndDate>2010-02-02T00:00:00-08:00</EndDate>
7. <PercentDone>40</PercentDone>
8. <ParentId>null</ParentId>
9. <IsLeaf>false</IsLeaf>
10. <Responsible></Responsible>
11. </Task><Task>
12. <Id>11</Id>
13. <Name>Investigate</Name>
14. <StartDate>2010-01-18T00:00:00-08:00</StartDate>
15. <EndDate>2010-01-28T00:00:00-08:00</EndDate>
16. <PercentDone>30</PercentDone>
17. <ParentId>1</ParentId>
18. <IsLeaf>true</IsLeaf>
19. <Responsible></Responsible>
20. </Task>
21. </Tasks>
一个任务可以有很多属性,但是必须包括以下的数据,甘特图才能够显示出来。
l 'Id', 任务Id
l 'Name', 任务名称
l 'StartDate', 开始时间
l 'EndDate', 结束时间
l 'PercentDone',完成的百分比
l 'ParentId', 父任务
l 'IsLeaf', 是否是叶节点
任务跟任务之间的可以有四种关系:完成-完成(FF) 0,完成-开始(FS) 1,开始-完成(SF) 2,开始-开始(SS) 3。当有前置任务时,根据不同的任务相关性类型,将会显示四种不同的任务箭头连线。
依赖关系的数据结构非常简单,只包括三个属性
l From,前置任务的ID
l To,任务的ID
l Type,任务跟任务之间的可以有四种关系:完成-完成(FF) 0,完成-开始(FS) 1,开始-完成(SF) 2,开始-开始(SS) 3。
以下是一个任务的数据结构简单的XML的例子。
1. <Links>
2. <Link>
3. <From>12</From>
4. <To>17</To>
5. <Type>2</Type>
6. </Link>
7. <Link>
8. <From>20</From>
9. <To>19</To>
10. <Type>2</Type>
11. </Link>
12. </Links>
以上的例子都是基于XML的。 也就是说,甘特图可以读取静态的XML,或者是ASP.NET、Java等后端程序生成的XML。除了XML,Extjs甘特图也支持更多的数据结构和数据格式。事实上,用户可以任意组织存储自己的项目数据,无论是服务端是.NET还是JAVA,无论数据库是ORACLE还是MYSQL,无论数据传输方式是JSON 还是XML, Web Service,Rest等等。Extjs自身提供的强大Datareader,可以满足各种不同的需求。
加载数据
我们在来看看我们的DataStore是如何写的。除了定义数据结构以外,我们还定义了一个叫做Proxy的对象。
1. var taskStore = new Ext.ux.maximgb.tg.AdjacencyListStore({
2. proxy : new Ext.data.HttpProxy({
3. url : 'tasks.xml',
4. method:'GET'
5. }),
6. ...
7. });
在以上的例子中我们定义了一个HttpProxy, DataProxy 字面解释就是数据代理,也可以理解为数据源,也即从哪儿或如何得到需要交给DataReader 解析的数据。数据代理(源)基类由Ext.data.DataProxy 定义,在DataProxy的基础,ExtJS 提供了Ext.data.MemoryProxy、Ext.data.HttpProxy、Ext.data.ScriptTagProxy等三个分别用于从客户端内存数据、Ajax 读取服务器端的数据及从跨域服务器中读取数据等三种实现。
在proxy的url,我们配置了tasks.xml,也可以是一个任意的url地址,例如http://localhost/text.jsp 或者http://localhost/text.aspx 等等。而method则可以配置为get或者post等等。
DependencyStore的配置和这里的类似,我们就不再敖述。只给出一个简单的代码片段。
上一节我们讲述了如何显示甘特图,当用户增加删除了一些任务,或者改变了任务之间的依赖关系,我们如何将改动后的数据提交到服务器,在服务器中保存到数据库或文件系统中呢?
答案非常简单,只要实现Data Store的四个接口(增删改查)就可以了。我们先来看一段代码。
1. proxy : new Ext.data.HttpProxy({
2. disableCaching : false,
3. api: {
4. read : 'webservices/Tasks.asmx/Get',
5. create: 'webservices/Tasks.asmx/Create',
6. destroy: 'webservices/Tasks.asmx/Delete',
7. update: 'webservices/Tasks.asmx/Update'
8. }
9. }),
在以上的代码中,分别定义了四个不同的url,分别对应着增删改查四个操作的URL地址。例如,用户修改了一个任务,甘特图控件就会将修改后的数据提交到webservices/Tasks.asmx/Update。 其他的操作同理。下面我们以修改为例,看看在ASP.NET的服务器端是如何获取修改后的数据的。
1. [WebMethod]
2. [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
3. public Object Update(Task[] jsonData)
4. {
5. DataClasses1DataContext _db = new DataClasses1DataContext();
6. try
7. {
8. foreach (Task data in jsonData)
9. {
10. Task t = _db.Tasks.SingleOrDefault(b => b.Id == data.Id);
11. if (t != null)
12. {
13. t.Name = data.Name;
14. t.IsLeaf = data.IsLeaf;
15. t.ParentId = data.ParentId;
16. t.PercentDone = data.PercentDone;
17. t.StartDate = data.StartDate;
18. t.EndDate = data.EndDate;
19. t.Priority = data.Priority;
20. }
21. }
22. _db.SubmitChanges(ConflictMode.ContinueOnConflict);
23. }
24. catch (Exception ex)
25. {
26. int a = 0;
27. }
28. return new { success = true };
29. }
在以上的例子中,我们建立一个Web Service来实现增删改查,这个Web Servic里面有一个Update的方法。请注意在该方法的前面,有[ScriptMethod(ResponseFormat = ResponseFormat.Json)]这样一个申明。他说明这个Web Service提交的数据是一个JSON数据。
函数Update的参数是一个Task的数组,我们只需要遍历这个数组,就可以将所有的被修改的任务数据提取出来,然后根据不同的业务逻辑,更新数据库或文件系统。