甘特图控件DHTMLX Gantt入门使用教程【引入】:dhtmlxGantt 与Node.js(上)

news/2024/11/6 9:42:37/

DHTMLX Gantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表。可满足项目管理应用程序的大部分开发需求,具备完善的甘特图图表库,功能强大,价格便宜,提供丰富而灵活的JavaScript API接口,与各种服务器端技术(PHP,ASP.NET,Java等)简单集成,满足多种定制开发需求。

DHTMLX JavaScript UI 库所开发的 JavaScript 组件易于使用且功能丰富,非常适合任何领域和任何复杂性的解决方案,能够节省创建和维护业务应用程序的时间,提高生产力。

DHTMLX Gantt 最新下载(qun:764148812)icon-default.png?t=N3I4https://www.evget.com/product/4213/download

我们用Node.js实现Gantt将基于REST API,用于与服务器通信。Node.js有一套现成的解决方案,所以我们不必从一开始就编写所有的代码。我们还将使用MySQL作为数据存储。

第1步:创建项目

首先,我们将创建一个项目文件夹,然后添加所需的依赖项。我们将使用以下模块:

  • Express - 一个用于 Node 的微型框架.js
  • 正文解析器 - 节点.js解析工具

因此,让我们创建一个项目文件夹并将其命名为“dhx-gantt-app”:

mkdir dhx-gantt-app
cd dhx-gantt-app

添加依赖项

现在我们将创建 package.json 文件。我们将使用以下命令在其中指定依赖项:

npm init -y

文件准备就绪后,打开它并将上面列出的依赖项放入其中。结果将类似于这个:

{
"name": "dhx-gantt-app",
"version": "1.0.2",
"description": "",
"main": "server.js",
"dependencies": {
"body-parser": "^1.19.1",
"express": "^4.17.2"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"keywords": [],
"author": "",
"license": "MIT"
}

最后,我们需要使用以下命令安装添加的依赖项:

npm install

准备后端

我们将遵循一个基本的快速设置:我们将为我们的应用程序后端提供一个 js 文件(我们称之为“server.js”), 静态文件(名为“公共”)和单个 HTML 页面的文件夹。

整个项目结构如下:

dhx-gantt-app
├── node_modules
├── server.js
├── package.json
└── public
└── index.html

创建一个名为 server 的新文件.js并将以下代码添加到其中:

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');const port = 1337;
const app = express();app.use(express.static(path.join(__dirname, "public")));
app.use(bodyParser.urlencoded({ extended: true }));app.listen(port, () =>{
console.log("Server is running on port "+port+"...");
});

我们在此代码中所做的:

  • 定义了静态文件将从“公共”文件夹提供
  • 将应用程序附加到本地主机的 1337 端口

在下一步中,我们将创建“公共”文件夹。此文件夹将包含我们应用程序的主页 - index.html

第2步:将甘特图添加到页面

让我们创建公用文件夹并向其中添加一个索引.html文件。然后打开 index.html 文件并填充以下内容:

<!DOCTYPE html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"><script src="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.js"></script>
<link href="https://cdn.dhtmlx.com/gantt/edge/dhtmlxgantt.css" rel="stylesheet"><style type="text/css">
html, body{
height:100%;
padding:0px;
margin:0px;
overflow: hidden;
}</style>
</head>
<body>
<div id="gantt_here" style='width:100%; height:100%;'></div>
<script type="text/javascript">
gantt.init("gantt_here");
</script>
</body>

让我们检查一下我们目前得到了什么。转到项目文件夹并从命令行运行以下命令:

node server.js

然后在浏览器中打开 http://127.0.0.1:1337。您应该会看到一个带有空甘特图的页面,如下所示:

第 3 步:准备数据库

下一步是创建数据库。我们将创建一个简单的数据库,其中包含两个用于任务和链接的表:

CREATE TABLE `gantt_links` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`source` int(11) NOT NULL,
`target` int(11) NOT NULL,
`type` varchar(1) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `gantt_tasks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`text` varchar(255) NOT NULL,
`start_date` datetime NOT NULL,
`duration` int(11) NOT NULL,
`progress` float NOT NULL,
`parent` int(11) NOT NULL,
PRIMARY KEY (`id`)
);

并添加一些测试数据:

INSERT INTO `gantt_tasks` VALUES ('1', 'Project #1', '2017-04-01 00:00:00',
'5', '0.8', '0');
INSERT INTO `gantt_tasks` VALUES ('2', 'Task #1', '2017-04-06 00:00:00',
'4', '0.5', '1');
INSERT INTO `gantt_tasks` VALUES ('3', 'Task #2', '2017-04-05 00:00:00',
'6', '0.7', '1');
INSERT INTO `gantt_tasks` VALUES ('4', 'Task #3', '2017-04-07 00:00:00',
'2', '0', '1');
INSERT INTO `gantt_tasks` VALUES ('5', 'Task #1.1', '2017-04-05 00:00:00',
'5', '0.34', '2');
INSERT INTO `gantt_tasks` VALUES ('6', 'Task #1.2', '2017-04-11 13:22:17',
'4', '0.5', '2');
INSERT INTO `gantt_tasks` VALUES ('7', 'Task #2.1', '2017-04-07 00:00:00',
'5', '0.2', '3');
INSERT INTO `gantt_tasks` VALUES ('8', 'Task #2.2', '2017-04-06 00:00:00',
'4', '0.9', '3');

第 4 步:加载数据

现在我们需要实现数据加载。

由于我们使用MySQL,因此我们需要安装可用于访问它的必要模块。在本教程中,CRUD 操作将基于承诺方法实现。 因此,我们将使用 promise-mysql - 一个 Node.js 包,用于使用 promise 和 蓝鸟承诺图书馆。

要安装它们,我们可以使用控制台。我们需要指定以下组件版本,因为较新的组件版本彼此不兼容或没有旧函数:

npm install bluebird@3.7.2 --save
npm install promise-mysql@5.1.0 --save
npm install date-format-lite@17.7.0 --save

您可以选择任何其他适当的模块。代码相当简单,您可以使用一组不同的工具实现相同的逻辑。

客户端需要 JSON 格式的数据。因此,我们将创建一个返回此类数据的路由。

正如您可能已经提到的,数据中有“start_date”属性,该属性保留为日期对象。因此,它应该在 格式正确。为此,我们将使用另一个模块 - date-format-lite。

npm install date-format-lite --save

现在,您应该打开 server.js 文件并使用以下内容更新其代码:

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');const port = 1337;
const app = express();app.use(express.static(path.join(__dirname, "public")));
app.use(bodyParser.urlencoded({ extended: true }));app.listen(port, () =>{
console.log("Server is running on port "+port+"...");
});const Promise = require('bluebird');
require("date-format-lite");const mysql = require('promise-mysql');
async function serverСonfig() {
const db = await mysql.createPool({
host: 'localhost',
user: 'root',
password: '',
database: 'gantt_howto_node'
});
app.get("/data", (req, res) => {
Promise.all([
db.query("SELECT * FROM gantt_tasks"),
db.query("SELECT * FROM gantt_links")
]).then(results => {
let tasks = results[0],
links = results[1];for (let i = 0; i < tasks.length; i++) {
tasks[i].start_date = tasks[i].start_date.format("YYYY-MM-DD hh:mm:ss");
tasks[i].open = true;
}res.send({
data: tasks,
collections: { links: links }
});}).catch(error => {
sendResponse(res, "error", null, error);
});
});function sendResponse(res, action, tid, error) {if (action == "error")
console.log(error);let result = {
action: action
};
if (tid !== undefined && tid !== null)
result.tid = tid;res.send(result);
}
};

我们在此代码中所做的:

  • 打开了与我们的数据库的 MySql 连接
  • 定义在 GET /data 请求中,我们将从任务和链接表中读取数据并格式化它们,以便它们可以在客户端上解析

请注意,我们还添加了 open 属性,以确保任务树最初将展开。

现在,我们可以从客户端调用此路由:

gantt.config.date_format = "%Y-%m-%d %H:%i:%s";gantt.init("gantt_here");gantt.load("/data");

请注意,date_format配置指定来自服务器的日期(任务start_date)的格式。

现在让我们通过打开 http://127.0.0.1:1337 来运行应用程序。甘特图将加载我们之前添加到数据库中的测试数据。

第5步:保存更改

我们应该实现的最后一件事是数据保存。 为此,我们需要一个代码,它将客户端发生的更新发送回服务器。 转到 public/index.html 并将gantt.dataProcessor添加到页面:

public/index.html
gantt.config.date_format = "%Y-%m-%d %H:%i:%s";gantt.init("gantt_here");gantt.load("/data");const dp = new gantt.dataProcessor("/data");
dp.init(gantt);
dp.setTransactionMode("REST");

让我们更深入地看看它扮演什么角色。

请求和响应

在每个用户操作上:添加、更改或删除新任务或链接,DataProcessor 将通过向 AJAX 发送请求来做出反应 相应的网址。该请求将包含将更改保存在数据库中所需的所有参数。

由于DataProcessor是在REST模式下初始化的,因此它将对每种类型的操作使用不同的HTTP动词。 服务器端集成一文中提供了 HTTP 谓词列表以及请求和响应详细信息。

好吧,我们现在需要做的是添加所需的路由和处理程序,这会将对客户端所做的更改放入数据库,放入服务器.js文件中。 生成的代码将相当宽敞:

// add a new task
app.post("/data/task", (req, res) => {
let task = getTask(req.body);db.query("INSERT INTO gantt_tasks(text, start_date, duration, progress, parent)"
+ " VALUES (?,?,?,?,?)",
[task.text, task.start_date, task.duration, task.progress, task.parent])
.then(result => {
sendResponse(res, "inserted", result.insertId);
})
.catch(error => {
sendResponse(res, "error", null, error);
});
});// update a task
app.put("/data/task/:id", (req, res) => {
let sid = req.params.id,
task = getTask(req.body);db.query("UPDATE gantt_tasks SET text = ?, start_date = ?, "
+ "duration = ?, progress = ?, parent = ? WHERE id = ?",
[task.text, task.start_date, task.duration, task.progress, task.parent, sid])
.then(result => {
sendResponse(res, "updated");
})
.catch(error => {
sendResponse(res, "error", null, error);
});
});// delete a task
app.delete("/data/task/:id", (req, res) => {
let sid = req.params.id;
db.query("DELETE FROM gantt_tasks WHERE id = ?", [sid])
.then(result => {
sendResponse(res, "deleted");
})
.catch(error => {
sendResponse(res, "error", null, error);
});
});// add a link
app.post("/data/link", (req, res) => {
let link = getLink(req.body);db.query("INSERT INTO gantt_links(source, target, type) VALUES (?,?,?)",
[link.source, link.target, link.type])
.then(result => {
sendResponse(res, "inserted", result.insertId);
})
.catch(error => {
sendResponse(res, "error", null, error);
});
});// update a link
app.put("/data/link/:id", (req, res) => {
let sid = req.params.id,
link = getLink(req.body);db.query("UPDATE gantt_links SET source = ?, target = ?, type = ? WHERE id = ?",
[link.source, link.target, link.type, sid])
.then(result => {
sendResponse(res, "updated");
})
.catch(error => {
sendResponse(res, "error", null, error);
});
});// delete a link
app.delete("/data/link/:id", (req, res) => {
let sid = req.params.id;
db.query("DELETE FROM gantt_links WHERE id = ?", [sid])
.then(result => {
sendResponse(res, "deleted");
})
.catch(error => {
sendResponse(res, "error", null, error);
});
});function getTask(data) {
return {
text: data.text,
start_date: data.start_date.date("YYYY-MM-DD"),
duration: data.duration,
progress: data.progress || 0,
parent: data.parent
};
}function getLink(data) {
return {
source: data.source,
target: data.target,
type: data.type
};
}

我们创建了两组路由:一组用于任务实体,另一组用于链接实体。 相应地,“/data/task”URL 将用于与 到具有任务的操作,并且“/data/link”URL将用于处理包含带有链接的操作的数据的请求。

请求类型非常简单:

  • POST - 将新项目插入数据库
  • PUT - 更新现有记录
  • 删除 - 删除项目

响应将是一个 JSON 对象,具有执行的操作类型或“错误”,以防代码失败。

POST 请求的响应还将包含新记录的数据库 ID。 它将应用于客户端,因此可以将新项映射到数据库实体。

就这样。打开 http://127.0.0.1:1337,您将看到一个完全可操作的甘特图。

DHTMLX Gantt享有超十年声誉,支持跨浏览器和跨平台,性价比高,可满足项目管理控件应用的所有需求,是较为完善的甘特图图表库。


http://www.ppmy.cn/news/68093.html

相关文章

(动态规划,分治)leetcode53. 最大子数组和

文章目录 一、题目1、题目描述2、基础框架3、原题链接 二、解题报告1、思路分析2、时间复杂度3、代码详解 三、本题小知识 一、题目 1、题目描述 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&…

android room数据库简单使用

Room来源 Android采用Sqlite作为数据库存储。由于Sqlite代码写起来繁琐且容易出错&#xff0c;因此&#xff0c;开源社区逐渐出现了各种ORM&#xff08;Object Relational Mapping&#xff09;库。常见的有ORMLite, GreenDAO等。Google也意识到推出自家ORM库的必要性&#xff0…

什么是VLAN?为什么要划分VLAN?

VLAN(Virtual Local Area Network)即虚拟局域网&#xff0c;是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。每个VLAN是一个广播域&#xff0c;VLAN内的主机间可以直接通信&#xff0c;而VLAN间则不能直接互通。这样&#xff0c;广播报文就被限制在一个VLAN内。 一、为…

蓝桥杯模块学习3——蜂鸣器与继电器

第一章 硬件部分 1.1 电路的组成部分 1.1.1 译码器和锁存器 具体可回顾之前LED灯的文章&#xff1a; https://blog.csdn.net/weixin_63568691/article/details/130660096 1.1.2 ULN2003达林顿管 原理图&#xff1a; 功能&#xff1a; &#xff08;1&#xff09;改变电路特性…

栈和队列的实现

栈 栈的概念 栈也是线性表的一种&#xff0c;但是栈只允许在固定的一端进行插入与删除数据&#xff0c;而进行插入与删除的一端同意称为栈顶&#xff0c;而另一端就称为栈底。简称&#xff1a;后进先出。 压栈&#xff08;push&#xff09;&#xff1a;将数据插入栈顶。 出…

ANR实战案例 2 - 不同线程状态ANR示例

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、Blocked状态示例1.启动初始化阻塞案例trace1.tx 2.ConcurrentHashMap分段锁优…

SwiftUI 4.0 中 List 显示层级数据的子视图在展开和收起操作时无动画的解决

问题现象 在 SwiftUI 4.0(iOS 16+)中,一个超简单 List 视图层级子视图的收放操作竟然没有动画,这着实有点让人不爽: 从上图可以看到:我们在点击 List 子项时不仅毫无收放动画可言,而且在展开时还有卡顿,显得非常生硬。 以上代码在目前最新的 iOS 16.4.1(a) 系统中测试…

非常提效的7款原型工具推荐

原型图工具允许在开发前进行测试和迭代过程&#xff0c;可以帮助节省大量的开发时间和成本。在本文中&#xff0c;我们盘点了7个易于使用的原型图工具&#xff0c;以提高您的生产力&#xff01; 1.即时设计 即时设计是一款免费的在线 UI 设计工具&#xff0c;无系统限制&…