vue框架下实现甘特图(dhtmlxGantt)

项目中要用到甘特图,最开始研究了echart,实现的样式如下:


echart实现甘特图.png

对比下面的原型图,发觉相差甚大且通过echart不好复现。

原型图-甘特图.png

百度搜索找到了dhtmlxGantt,查看官网demo后足够实现原型效果。随即查看了官方文档,实现了如下效果:


dhtmlxGantt实现甘特图.png

下面说一下dhtmlxGantt的使用:

引入 dhtmlx-gantt模块 版本:@6.3.7
npm install dhtmlx-gantt
创建dhtmlx-gantt组件
 <template>
  <div class="app-container">
    <div ref="gantt" class="left-container"/>
  </div>
</template>
<script>
  import gantt from 'dhtmlx-gantt'  // 引入模块
  //import 'dhtmlx-gantt/codebase/dhtmlxgantt.css'
  import 'dhtmlx-gantt/codebase/skins/dhtmlxgantt_terrace.css' //皮肤
  import 'dhtmlx-gantt/codebase/locale/locale_cn'  // 本地化
  import 'dhtmlx-gantt/codebase/ext/dhtmlxgantt_tooltip.js' //任务条悬浮提示

  export default {
    name: 'gantt',
    data() {
      return {
        tasks: {
          data: []
        }
      }
    },
    methods: {
      //开始时间-结束时间参数
      DateDifference: function(strDateStart, strDateEnd) {
        var begintime_ms = Date.parse(new Date(strDateStart.replace(/-/g, '/'))) //begintime 为开始时间
        var endtime_ms = Date.parse(new Date(strDateEnd.replace(/-/g, '/')))   // endtime 为结束时间
        var date3 = endtime_ms - begintime_ms //时间差的毫秒数
        var days = Math.floor(date3 / (24 * 3600 * 1000))
        return days
      },
      initData: function() {
        this.tasks.data = [
          {
            id: 1,
            text: '计划时间',
            start_date: '2020-04-08',
            duration: 10,
            open: true, //默认打开,
            toolTipsTxt: 'xxxxxxxxxxxxxxxxx'
          },
          {
            toolTipsTxt: 'xxxxxxxxxxxxxxxxx父任务01-001',
            text: '冒烟阶段', // 任务名
            start_date: '2020-04-08', // 开始时间
            id: 11, // 任务id
            duration: 3, // 任务时长,从start_date开始计算
            parent: 1, // 父任务ID
            type: 1
          },
          {
            toolTipsTxt: '',
            text: '单元测试', // 任务名
            start_date: '2020-04-11', // 开始时间
            id: 12, // 任务id
            duration: 2, // 任务时长,从start_date开始计算
            parent: 1, // 父任务ID
            type: 2

          },
          {
            toolTipsTxt: '',
            text: '回归测试', // 任务名
            start_date: '2020-04-13', // 开始时间
            id: 13, // 任务id
            duration: 4, // 任务时长,从start_date开始计算
            parent: 1, // 父任务ID
            type: 3

          }, {
            toolTipsTxt: '',
            text: '阶段四', // 任务名
            start_date: '2020-04-13', // 开始时间
            id: 14, // 任务id
            duration: 4, // 任务时长,从start_date开始计算
            parent: 1, // 父任务ID
            type: 4

          },
          //========================
          {
            id: 2,
            text: '实际时间',
            start_date: '2020-04-08',
            duration: 8,
            open: true, //默认打开,才可隐藏左侧表格
            toolTipsTxt: 'xxxxxxxxxxxxxxxxx',
            state: 'default'
            // color:"#409EFF",
            //progress: 0.6
          },
          {
            toolTipsTxt: 'xxxxxxxxxxxxxxxxx父任务01-001',
            text: '冒烟阶段', // 任务名
            start_date: '2020-04-08', // 开始时间
            id: 21, // 任务id
            duration: 2, // 任务时长,从start_date开始计算
            parent: 2, // 父任务ID
            type: 1
          },
          {
            toolTipsTxt: '',
            text: '单元测试', // 任务名
            start_date: '2020-04-09', // 开始时间
            id: 22, // 任务id
            duration: 2, // 任务时长,从start_date开始计算
            parent: 2, // 父任务ID
            type: 2
          },
          {
            toolTipsTxt: '',
            text: '回归测试', // 任务名
            start_date: '2020-04-11', // 开始时间
            id: 23, // 任务id
            duration: 2, // 任务时长,从start_date开始计算
            parent: 2, // 父任务ID
            type: 3
          }

        ].map(function(current, ind, arry) {
          var newObj = {}
          if (current.type) { //存在type字段 说明非一级菜单,判断阶段的具体类型 设置不同颜色
            if (current.type == 1) { //冒烟
              newObj = Object.assign({}, current, { 'color': '#fcca02' })
            } else if (current.type == 2) { //单元
              newObj = Object.assign({}, current, { 'color': '#fec0dc' })
            } else if (current.type == 3) { //回归
              newObj = Object.assign({}, current, { 'color': '#62ddd4' })
            } else if (current.type == 4){
              newObj = Object.assign({}, current, { 'color': '#d1a6ff' })
            }
          } else { //一级菜单是蓝色的
            newObj = Object.assign({}, current, { 'color': '#5692f0' })
          }

          return newObj
        })
      }
    },
    mounted() {
      this.initData()
      /*
      * 冒烟:fcca02    单元:fec0dc     回归:62ddd4   阶段:d1a6ff
      * */
      //设置图表区域的日期坐标最大值 var date = new Date(dateString.replace(/-/,"/"))
      //  gantt.config.start_date = new Date("2020-04-08".replace(/-/,"/")) ;
      //gantt.config.end_date = new Date("2020-04-18".replace(/-/,"/")) ; //结束时间需要+1天

      //自适应甘特图的尺寸大小, 使得在不出现滚动条的情况下, 显示全部任务
      gantt.config.autosize = true
      //只读模式
      gantt.config.readonly = true
      //是否显示左侧树表格
      gantt.config.show_grid = false
      //表格列设置
      gantt.config.columns = [
        { name: 'text', label: '阶段名字', tree: true, width: '120' },
        {
          name: 'duration', label: '时长', align: 'center', template: function(obj) {
            return obj.duration + '天'
          }
        }
        /*{name:"start_date", label:"开始时间", align: "center" },

        {name:"end_date",   label:"结束时间",   align: "center" },*/
      ]
      //时间轴图表中,如果不设置,只有行边框,区分上下的任务,设置之后带有列的边框,整个时间轴变成格子状。
      gantt.config.show_task_cells = true

      //设置x轴日期
      gantt.config.scale_unit = 'day'
      gantt.config.step = 1
      gantt.config.date_scale = '星期' + '%D'

      //当task的长度改变时,自动调整图表坐标轴区间用于适配task的长度
      gantt.config.fit_tasks = true
      // 在时间线上增加一行显示星期
      gantt.config.subscales = [
        //{unit:"day",  step:1, date:"星期"+"%D" },
        { unit: 'day', step: 1, date: '%M' + '%d' + '日' }
      ]
      //时间轴图表中,任务条形图的高度
      gantt.config.task_height = 28
      //时间轴图表中,甘特图的高度
      gantt.config.row_height = 36
      //从后端过来的数据格式化
      gantt.config.xml_date = '%Y-%m-%d'
      //任务条显示内容
      gantt.templates.task_text = function(start, end, task) {
        return task.text + '(' + task.duration + '天)'
      }
      // gantt.templates.task_class = function(start, end, task){return "xx";};
      //悬浮
      gantt.templates.tooltip_text = function(start, end, task) {
        //return "<b>任务名称:</b> "+task.text+"<br/><b>时长:</b> " + task.duration+"<br/><b>说明:</b>" +task.toolTipsTxt;
        return '<span style=\'font-size: 14px\'>' + task.toolTipsTxt + '</span>'
      }

      gantt.templates.scale_cell_class = function(date) {
        /*if(date.getDay()== 0 || date.getDay()== 6){
          return "weekend";
        }*/
        return 'weekend'
      }
      //任务栏周末亮色
      /*gantt.templates.task_cell_class = function(item,date){
        if(date.getDay()== 0 || date.getDay()== 6){
          return "weekend";
        }
      };*/
      //任务条上的文字大小 以及取消border自带样式
      gantt.templates.task_class = function(start, end, item) {
        return item.$level == 0 ? 'firstLevelTask' : 'secondLevelTask'
      }
      // 初始化
      gantt.init(this.$refs.gantt)
      // 数据解析
      gantt.parse(this.tasks)
    }
  }
</script>
<style lang="scss">
  .firstLevelTask {
    border: none;
    .gantt_task_content{
      // font-weight: bold;
      font-size: 13px;
    }
  }

  .secondLevelTask {
    border: none;
  }

  .thirdLevelTask {
    border: 2px solid #da645d;
    color: #da645d;
    background: #da645d;
  }

  .milestone-default {
    border: none;
    background: rgba(0, 0, 0, 0.45);
  }

  .milestone-unfinished {
    border: none;
    background: #5692f0;
  }

  .milestone-finished {
    border: none;
    background: #84bd54;
  }

  .milestone-canceled {
    border: none;
    background: #da645d;
  }

  html, body {
    margin: 0px;
    padding: 0px;
    height: 100%;
    overflow: hidden;
  }

  .container {
    height: 900px;
    .left-container {
      height: 100%;
    }
  }

  .left-container {
    height: 600px;
  }

  .gantt_scale_line {
    border-top: 0;
  }

  .weekend {
    //background:#f4f7f4!important;
    color: #000000 !important;
  }

  .gantt_selected .weekend {
    background: #f7eb91 !important;;
  }

  .gantt_task_content {
    text-align: left;
    padding-left: 10px;
  }

  //上面任务条样式
  .gantt_task_scale {
    height: 45px !important;
  }

  .gantt_task .gantt_task_scale .gantt_scale_cell {
    line-height: 30px !important;
    height: 28px !important;
  }
</style>

参考的具体官方文档

具体的属性可以在API中查找:https://docs.dhtmlx.com/gantt/api__refs__gantt.html
开发使用说明:https://docs.dhtmlx.com/gantt/index.html
在Vue.js框架中使用步骤:https://dhtmlx.com/blog/use-dhtmlxgantt-vue-js-framework-demo/

欢迎一起交流呀~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 学习资料 vue github (里面包含了vue, vuex, vue-cli等源码) vue-cli 官网 v...
    pauljun阅读 6,002评论 2 17
  • PS:转载请注明出处作者: TigerChain地址: https://www.jianshu.com/p/218...
    TigerChain阅读 26,170评论 5 70
  • 前端知识结构https://github.com/JacksonTian/fks Web前端开发大系概览https...
    柴东啊阅读 981评论 0 10
  • ## 框架和库的区别?> 框架(framework):一套完整的软件设计架构和**解决方案**。> > 库(lib...
    Rui_bdad阅读 2,889评论 1 4
  • 文/羽商三少 每一个多愁善感的人背后可能隐藏着一双脆弱的翅膀。 01 "你这样肯定过得很累吧!"坐在对面的心理辅导...
    羽商三少阅读 153评论 0 0