纯HTML+CSS 实现甘特图

先看效果

左侧为任务列表,是树形结构。右侧是渲染的甘特图,可以用鼠标滚轮滚动来缩放时间线宽度。

实现思路


树形列表维护一个AST,类似以下结构:

declare interface TaskNode {
  name: string, //任务名称
  start_time: string, //假定日期都是以xxxx-xx-xxTxx:xx:xx格式
  end_time: string, //假定日期都是以xxxx-xx-xxTxx:xx:xx格式
  list_order: number,
  par_id?: string,
  children?: TaskNode[], //子任务列表
  color?: string, //颜色
  expanded?: boolean, //是否展开
}

然后就可以通过解析该AST渲染出甘特图,每当列表数据发生修改、删除、增加操作时立即再次渲染保证左右同步。

主要难点


1. 需要知道甘特图的显示算法,摸清它的规律。

2. 如何实现鼠标滚轮滚动时,甘特图相应缩放?

3. 如何渲染任务块?


甘特图的显示规律:从上往下,从左往右,越早的任务在越左上的位置,越晚的任务在越偏右下的位置,子任务呈阶梯状在父任务下方显示。来看project的甘特图

project 甘特图

当然本文没有实现类似的箭头效果 


如何实现鼠标滚轮滚动时,甘特图相应缩放?

需要对dom的了解比较好,目前浏览器支持对DOM的鼠标滚轮事件

handleMouseWheel(e : any){
      e.preventDefault();
      // console.log(e);
      if(e.deltaY < 0){
        // 向上滚动 
        
      }else{
        // 向下滚动 
        
      }
      
    },

我实现的甘特图主要是有两个部分,一个是时间线,二是任务块。

如果保证时间线和任务块缩放同步,使得甘特图收放自如,需要一个统一的"指挥"。

 

scaleX: 1,  //当前缩放倍率
dayColDomWidth: 1200, // "天"列宽
hourColDomWidth: 50, //"时"列宽
taskBlockHeight: 40, //"任务块"默认高度

 鼠标滚轮事件改变的只是scaleX,就这么简单。通过获取dom动态修改宽度即可,任务块的修改稍有不同

    handleScale(scaleX){
      // 时间线
      var doms = document.getElementsByClassName('day-col');
      // console.log(doms);
      
      for(var i=0;i<doms.length;i++){
        const ele : any = doms.item(i);
        ele.style.width = scaleX * this.dayColDomWidth + 'px';
        var hourDoms = ele.getElementsByClassName('hour-col');
        for(var j=0;j<hourDoms.length;j++){
          const hourEle : any = hourDoms.item(j);
          hourEle.style.width = scaleX * this.hourColDomWidth + 'px';
        }
      }
      // 任务块
      var doms = document.getElementsByClassName('task-block');
      for(var i=0;i<doms.length;i++){
        const ele : any = doms.item(i);
        // 任务块宽度的修改 稍有不同
        ele.style.left = parseFloat(ele.dataset.left) * scaleX  + 'px';
        ele.style.width = parseFloat(ele.dataset.width) * scaleX + 'px';
      }
    },

由于JS存在浮点数计算误差的问题,缩放过程会让甘特图产生一定的偏差,当然,这非常小。

 任务块不像"天"列和"小时"列有在scaleX为1时的固定宽度,它本身的宽度是不固定的,所以它的缩放处理稍微麻烦。那么,我们只需要给它找一个"固定宽度"即可:

任务块的宽度与它的时长有关,距离左边的偏移量与他的起始时间和“最小时间”有关,那么不管它处于什么scaleX时渲染,我们都可以计算出它的"固定宽度",即 实际宽度 / scaleX。左侧偏移量同理。

    var width = (this.hourColDomWidth * this.scaleX * totalHour) + (this.hourColDomWidth *           this.scaleX * restSecond / 3600);
    taskBlockDom.setAttribute('data-width',`${width / this.scaleX}`);

对于时间线的渲染,无非就是递归下AST,找到最小日期和最大日期,得出天数,剩下的就是DOM的一些遍历操作,这里不再赘述。


任务块的渲染

主要是递归AST,伪代码如下

    /**
     * 渲染任务块
     * @param {TaskNode} taskNode 任务节点
     * @param {*} params 参数
     * @param {Date} minDate 最小日期
     */
    renderTaskBlock(treeNode : TaskNode, params : any, minDate : Date){
      if(该节点有开始时间和结束世间){
       
  
        // 得到当前任务的开始时间和结束时间,注意时区处理

        // 得到当前任务的开始时间和结束时间的之间总的秒数差值
        
        // 得到整除小时后的余秒数
        
        // 得到小时数(取整)

        // 得到左侧偏移小时数
        
        
        // 创建 dom 任务块, 设置类名和大小和位置

        
        // 任务块的Y坐标系数
        params.index = params.index + 1;
      }

      // 如果有子任务,递归渲染子任务
      
     
      
    },
### 回答1: 以下是一个简单的甘特图HTML代码示例: ``` <!DOCTYPE html> <html> <head> <title>Gantt Chart</title> <style> table { border-collapse: collapse; width: 100%; } th, td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; } th { background-color: #f2f2f2; } .task { background-color: #4CAF50; color: white; position: relative; height: 40px; margin-bottom: 5px; } .task::before { content: ""; position: absolute; top: 0; left: 0; width: 0; height: 0; border-top: 20px solid transparent; border-bottom: 20px solid transparent; border-right: 20px solid #4CAF50; } .task span { position: absolute; left: 25px; top: 10px; } </style> </head> <body> <table> <tr> <th>Task</th> <th>Start Date</th> <th>End Date</th> </tr> <tr> <td> <div class="task"> <span>Task 1</span> </div> </td> <td>2023-02-18</td> <td>2023-02-21</td> </tr> <tr> <td> <div class="task"> <span>Task 2</span> </div> </td> <td>2023-02-22</td> <td>2023-02-26</td> </tr> <tr> <td> <div class="task"> <span>Task 3</span> </div> </td> <td>2023-02-27</td> <td>2023-03-01</td> </tr> </table> </body> </html> ``` 该示例使用了一个HTML表格来创建甘特图,其中每个任务都表示为一个具有样式的`div`元素。`::before`伪元素用于绘制表示任务时间范围的三角形,任务的名称通过一个`<span>`元素放置在任务条上。 注意,这只是一个简单的示例,并且可以进一步自定义和优化。 ### 回答2: 甘特图是一种用于展示项目进程、任务时间安排等的图表形式。在前端实现甘特图HTML代码中,可以利用HTMLCSSJavaScript技术进行实现。 首先,可以使用HTML来创建甘特图所需的基本结构。通过创建一个HTML容器元素,如<div>或者<canvas>,来容纳整个甘特图的内容。 接下来,可以使用CSS来定义甘特图内各个元素的样式。可以为容器元素设置宽度、高度以及背景颜色等基本样式,并使用CSS选择器为甘特图中的任务条目、任务名称、时间轴等元素设置样式。 在实现甘特图的任务条目时,可以通过使用HTML的<div>元素来表示每一个任务,并通过CSS样式设置宽度、高度和颜色等属性,以及定位每一个任务的位置。 在定位任务的不同起止时间上,可以使用CSS属性如left和right来控制任务条目的位置。定位可以使用百分比值或者像素值进行。 另外,在甘特图中,可以为每个任务元素添加一些交互特性。可以使用JavaScript来为任务元素添加事件监听器,如鼠标悬浮、点击等事件,以增强交互体验。 此外,还可以使用JavaScript来动态生成甘特图的数据。可以从后端获取项目的任务信息,并生成相应的HTML元素来表示任务条目。 总结起来,前端实现甘特图HTML代码的关键是通过HTMLCSSJavaScript实现甘特图的基本结构、样式和交互功能。通过灵活运用这些技术,可以创建出美观、功能强大的甘特图。 ### 回答3: 甘特图是项目管理中常用的一种图表,用来展示项目在时间轴上的进度安排。要实现甘特图HTML代码,可以按照以下步骤进行: 1. 创建一个HTML文件,并使用DOCTYPE声明,以及html、head和body标签。 2. 在head标签中,添加一个style标签,用于定义甘特图的样式。可以设置甘特图容器的宽度、高度,以及背景色等样式。 3. 在body标签中,使用div标签创建一个容器,用于放置甘特图。 4. 在style标签中,定义甘特图容器的样式。可以设置宽度和高度,以及其他样式。例如: ``` .gantt-container { width: 800px; height: 500px; background-color: #f2f2f2; } ``` 5. 使用JavaScript或jQuery等前端框架,获取需要展示的项目数据。可以使用数组对象来表示每个任务的开始时间、结束时间、持续时间等信息。 6. 根据获取的任务数据,使用div标签创建每个任务的条形表示,放置在甘特图容器中。可以根据任务的开始时间和持续时间计算出任务的位置和宽度,并设置对应的样式。 7. 设置每个任务条的样式,可以使用不同的颜色来表示不同的任务,也可以使用不同的状态来表示任务的进度。 8. 如果需要添加任务的标签或说明文字,可以使用span标签,并设置对应的样式。 9. 在页面加载完成时,将甘特图容器添加到body标签中,并显示出来。 以上就是实现甘特图HTML代码的基本步骤。通过设置样式和使用任务数据,可以灵活地展示不同的甘特图,并方便地进行项目管理和进度监控。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值