欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解gantt甘特圖可拖拽、編輯(vue、react都可用?highcharts)

 更新時間:2021年11月27日 08:59:31   作者:Mr.聶  
去年我遇到了一個甘特圖的需求,做了很多工作,最終還是不完美,今天使用一個新包,給大家重新學(xué)習(xí)下vue?甘特圖gantt的相關(guān)知識,感興趣的朋友一起看看吧

前言

 Excel功能強(qiáng)大,應(yīng)用廣泛。隨著web應(yīng)用的興起和完善,用戶的要求也越來越高。很多Excel的功能都搬到了sass里面。恨不得給他們做個Excel出來。。。程序員太難了。。。

  去年我遇到了一個甘特圖的需求,做了很多工作,也寫了兩篇博客。一篇是用 GSTC 這個包做的甘特圖,另一篇是自己手寫了一個簡易的甘特圖。兩個的效果都不理想,特別是GSTC,問題很多,好多道友看了博客遇到了問題,慚愧,沒能幫大家解決這個問題。之前太忙了,這個甘特圖就再沒搞,直到今天發(fā)現(xiàn)了新的包,幾乎是完全符合我們的需求。

  首先,我們用的是 highcharts;其次,大團(tuán)隊(duì)的產(chǎn)品,后期維護(hù)有保障,文檔也齊全。

  我用 Vue3 寫的,但是highcharts不區(qū)分他,是js包,所以無論 vue react 還是原生多頁面都沒問題。

  接下來先看一下我們的需求,也是最基本的,需要實(shí)現(xiàn)的功能,然后會有效果圖的gif,最后就是源代碼,我放在了Git上,覺得好用,麻煩給個star。

需求

1、橫軸左側(cè)是表格數(shù)據(jù),可以展示基本信息
2、橫軸右側(cè)是時間軸,可以切換不同精度的時間展示
3、橫向數(shù)據(jù)塊有多個,最好可以疊加
4、數(shù)據(jù)塊可以拖拽、點(diǎn)擊等,修改任務(wù)的時間和其他信息

效果圖

  這個highcharts,不僅實(shí)現(xiàn)了左邊表格,右邊圖標(biāo),而且數(shù)據(jù)是聯(lián)動的;右邊橫軸是時間軸,可以自定義格式;數(shù)據(jù)允許疊加,不沖突;數(shù)據(jù)有點(diǎn)擊等各種事件,可以選中編輯單個數(shù)據(jù)塊;數(shù)據(jù)可以拖拽,比如上下?lián)Q列拖拽、水平拖拽,還可以單邊拖拽,而且事件都有回調(diào)函數(shù)。這些功能基本可以滿足我們的需求。比如對時間段、時間長度、數(shù)據(jù)信息的修改和展示。

源碼地址、代碼解析

  先貼一下代碼的Git地址,點(diǎn)擊GitHub源代碼 下載源代碼。建議直接下源碼,跑項(xiàng)目,另外,這個項(xiàng)目是vue3的,不過對于這種包,寫法差別不大,主要是參數(shù)。

  我貼一下代碼,對功能實(shí)現(xiàn)做一個講解,當(dāng)然注釋寫的也是很詳細(xì)的。

  首先,highcharts-gantt.js 是專門用來實(shí)現(xiàn)甘特圖的文件,draggable-points.js 是實(shí)現(xiàn)點(diǎn)事件綁定的文件。因?yàn)関ue直接引入有找不到變量的報(bào)錯,我將draggable-points的兩個module直接添加到了highcharts-gantt里面,然后重新壓縮,沒有混淆,所以最終的包只有160K+,小了很多,大家可以直接用。壓縮之后的源代碼放心使用就行,我只是合并了2個文件的功能函數(shù),但是也要格外提醒,不是官方的源文件了,感興趣的同學(xué)可以去看官方源代碼, .src 的文件是未壓縮混淆的,注釋也很詳細(xì)。這是我合并文件時的版本Highcharts Gantt JS v9.3.1 (2021-11-05),這個也是當(dāng)前的穩(wěn)定版本。

  功能有點(diǎn)簡單,好像代碼沒什么好說的。關(guān)鍵的地方我都做了注釋,還有不明白的可以留言或者評論。

  最后,還存在一個問題,我沒仔細(xì)研究源碼,這個示例還存在一個問題,就是拖拽事件沒有中斷,而且直接修改了圖表的數(shù)據(jù)展示。比如,縱向拖動換行時,左側(cè)表格的數(shù)據(jù)會變化。暫時我還沒有找到滿意解決的方法。目前,我在拖拽結(jié)束的回調(diào) drop 函數(shù)中,對數(shù)據(jù)做了處理,然后將我們希望的數(shù)據(jù)回寫,更新圖表,同樣你也可以做 不能拖拽或者時間沖突等各種校驗(yàn),達(dá)到上面我所說的需求。但是還有一點(diǎn)瑕疵,就是拖拽過程中的數(shù)據(jù)變化,左側(cè)表格的數(shù)據(jù)拖拽過程中我也不希望他變化,暫時沒能解決掉。如果您有好的案例、好的使用、好的建議,都希望可以提出來,共同進(jìn)步。

<div class="hightChart-gantt">
    <div id="container"></div>
    <button @click="getData">打印當(dāng)前數(shù)據(jù)</button>
  </div>
</template>

<script>
import { defineComponent, onMounted, ref } from 'vue';
import * as Highcharts from '@jsModule/highcharts/highcharts-gantt.src.js'
import dayjs from 'dayjs'
import{ WEEKS } from './constants'

// api文檔:  https://api.Highcharts.com.cn/gantt/index.html
// 社區(qū)地址: https://forum.jianshukeji.com/tags/c/Highcharts/35/Highcharts-gantt
// 官方示例: https://www.highcharts.com.cn/demo/gantt/interactive-gantt

// 待解決問題
// 1、拖拽中斷: 用戶操作應(yīng)該需要校驗(yàn),但是現(xiàn)在對中斷用戶操作這塊還沒搞明白。
//    解決方案: 目前的做法是,在 drop 里面做判斷,根據(jù)業(yè)務(wù)邏輯,做出提示,重新渲染數(shù)據(jù)。能實(shí)現(xiàn),不夠友好。


export default defineComponent({
  name: 'hightCharts-gantt',
  components: {},
  setup () {
    const gantt = ref({});
    // 官方建議用UTC的時間,鑒于業(yè)務(wù)需要,我們需要和數(shù)據(jù)庫時間保持統(tǒng)一,得看數(shù)據(jù)庫的存儲格式
    const data = [
      {start: '2021-6-1 0',end: '2021-6-1 18',factory: '華為',material: 'P50', uid: 1, y: 0, completed: 0.35}, 
      {start: '2021-6-2 8',end: '2021-6-2 16',factory: '華為',material: 'P50', uid: 2, y: 0}, 
      {start: '2021-6-3 8',end: '2021-6-4 24',factory: '華為',material: 'P50', uid: 3, y: 0}, 
      {start: '2021-6-4 12',end: '2021-6-5 15',factory: '華為',material: 'P50', uid: 4, y: 0}, 

      {start: '2021-6-1 8',end: '2021-6-1 12',factory: '小米',material: '紅米3', uid: 5, y: 1}, 
      {start: '2021-6-3 3',end: '2021-6-3 9',factory: '小米',material: '紅米3', uid: 6, y: 1}, 

      {start: '2021-6-1 6',end: '2021-6-1 16',factory: '蘋果',material: 'iPhone13', uid: 7, y: 2}, 
      {start: '2021-6-2 3',end: '2021-6-2 19',factory: '蘋果',material: 'iPhone13', uid: 8, y: 2}, 
      {start: '2021-6-3 8',end: '2021-6-3 17',factory: '蘋果',material: 'iPhone13', uid: 9, y: 2}, 

      {start: '2021-6-1 12',end: '2021-6-1 24',factory: 'OPPO',material: 'Reno7', uid: 10, y: 3},
      {start: '2021-6-2 5',end: '2021-6-2 18',factory: 'OPPO',material: 'Reno7', uid: 11, y: 3},
      {start: '2021-6-3 1',end: '2021-6-5 12',factory: 'OPPO',material: 'Reno7', uid: 12, y: 3},
    ];
    let newData = data.map(item => {
      item.start = dayjs(item.start).valueOf();
      item.end = dayjs(item.end).valueOf();
      return item
    });
    
    // 全局配置,需要在圖標(biāo)初始化之前配置
    Highcharts.setOptions({
      global: {
        useUTC: false  // 不使用utc時間
      },    // 默認(rèn)都是英文的,這里做了部分中文翻譯
      lang: {
        noData: '暫無數(shù)據(jù)',
        weekdays: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
        months: ['一月', '兒月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月']
      },
    });
    const dragStart = (e) => {
    }
    const drag = (e) => {
    }
    const drop = (e) => {
      const { newPoint = {}, target = {} } = e;
      if(newPoint.y || newPoint.y === 0) {
        let list = [], tar = newData.find(item => item.y === newPoint.y && item.uid !== target.uid);
        list = newData.map(item => {
          // 當(dāng)前拖拽數(shù)據(jù)
          if(item.uid === target.uid) {
            return {
              ...item,
              factory: tar.factory,
              material: tar.material, 
              ...newPoint
            }
          } else {
            return item
          }
        })
        gantt.value.update({
          series: [{
            data: list
          }]
        })
      }
    }
    // 選中,可以彈窗,編輯一些業(yè)務(wù)數(shù)據(jù)
    const handleSelect = (e) => {
      console.log('選中')
    }
    // 獲取最終數(shù)據(jù)
    const getData = () => {
      let data = gantt.value.series[0].data.map(item => {
        return {
          uid: item.uid,
          factory: item.factory,
          material: item.material,
          start: item.start,
          end: item.end
        }
      })
      console.log(data)
    }


    onMounted(() => {
      try {
        gantt.value = Highcharts.ganttChart('container', {
          title: {
            text: 'hightCharts甘特圖示例'
          },
          xAxis: [{
            currentDateIndicator: true,
            tickPixelInterval: 70,
            grid: {
              borderWidth: 1, // 右側(cè)表頭邊框?qū)挾?
              cellHeight: 35, // 右側(cè)日期表頭高度
            },
            labels: {
              align: 'center',
              formatter: function() {
                return `${dayjs(this.value).format('M月D')}  ${WEEKS[dayjs(this.value).day()]}`;
              }
            },
          }, {
            labels: {
              align: 'center',
              formatter: function() {
                return `${dayjs(this.value).format('YYYY年M月')}`;
              }
            },
          }],
          yAxis: {
            type: 'category',
            grid: {
              enabled: true,
              borderColor: 'rgba(0,0,0,0.3)',
              borderWidth: 1,
              columns: [
                { title: { text: '工廠' }, labels: { format: '{point.factory}' } }, 
                { title: { text: '型號' }, labels: { format: '{point.material}' } }, 
              ]
            }
          },
          tooltip: {
            formatter: function () {
              return `<div>
               工廠: ${this.point.factory}<br/>
              開始時間: ${dayjs(this.point.start).format('YYYY-MM-DD HH:mm:ss')}<br/>
              結(jié)束時間: ${dayjs(this.point.end).format('YYYY-MM-DD HH:mm:ss')}<br/>
              </div>`
            }
          },
          series: [{ data: newData }],
          plotOptions: {
            series: {
              animation: false,     // Do not animate dependency connectors
              dragDrop: {
                draggableX: true,   // 橫向拖拽
                draggableY: true,   // 縱向拖拽
                dragMinY: 0,        // 縱向拖拽下限
                dragMaxY: 3,        // 縱向拖拽上限
                dragPrecisionX: 3600000   // 橫向拖拽精度,單位毫秒
              },
              dataLabels: {
                enabled: true,
                format: '{point.factory}-{point.uid}',
                style: {
                  cursor: 'default',
                  pointerEvents: 'none'
                }
              },
              allowPointSelect: true,
              point: {
                events: {
                  dragStart: dragStart,
                  drag: drag,
                  drop: drop,
                  select: handleSelect
                }
              }
            }
          },
          exporting: {
            sourceWidth: 1000
          },
          credits: {    // 去掉右下角版權(quán)信息
            enabled: false
          },
        });
      } catch (error) {
        console.log(error)
      }
    })

    return {
      gantt,
      getData
    }
  },
})
</script>

<style scoped>
.hightChart-gantt {
  overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}
#container {
    max-width: 1200px;
    min-width: 800px;
    height: 400px;
    margin: 1em auto;
}
</style>

到此這篇關(guān)于詳解gantt甘特圖可拖拽、編輯(vue、react都可用 highcharts)的文章就介紹到這了,更多相關(guān)vue 甘特圖gantt內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 教你如何開發(fā)Vite3插件構(gòu)建Electron開發(fā)環(huán)境

    教你如何開發(fā)Vite3插件構(gòu)建Electron開發(fā)環(huán)境

    這篇文章主要介紹了如何開發(fā)Vite3插件構(gòu)建Electron開發(fā)環(huán)境,文中給大家提到了如何讓 Vite 加載 Electron 的內(nèi)置模塊和 Node.js 的內(nèi)置模塊,需要的朋友可以參考下
    2022-11-11
  • 最新評論