1. 程式人生 > >HT Vue 整合

HT Vue 整合

(本文中 dataModel = dm = 資料容器, gv = graphView = g2d = 2D 檢視)

初始化專案

使用 vue-cli 生成專案。生成注意以下幾個問題

1. 建議手動配置 Manually select features

2. 勾選 Router 

3. 配置設定 Indedicated config files

 

4. 專案初始化完成後增加 vue.config.js 並配置

module.exports = {
    devServer: {
        port: 12580
    }
}

vue 啟動專案預設在 8080 埠,容易衝突所以我們把這個埠設定走

5. .eslintrc.js 增加配置

  globals: {
    ht: true
  }

至此初始化專案完成。

引入 HT 相關資源

1. 引入 核心庫

將 libs 資料夾拷貝進 public 目錄下

2. 引入資源庫(如果是基礎專案可忽略這一步)

將 storage 資料夾拷貝進 public 目錄下

3. index.html 插入如下程式碼

    <script>
      window.htconfig = {
        Default: {
          convertURL: function(url){
            // console.log(url);
            return 'storage/' + url;
          }
        }
      }
    </script>
    <script src='libs/core/ht.js'></script>
    <script src='libs/plugin/ht-modeling.js'></script>
    <script src='libs/plugin/ht-obj.js'></script>
    <script src='libs/plugin/ht-edgetype.js'></script>
    <script src='libs/plugin/ht-form.js'></script>
    <script src="libs/plugin/ht-vector.js"></script>

至此專案搭建完成,可在命令列 npm run serve 執行起來專案,在瀏覽器訪問 localhost:12580 (前面手動配置的埠) 訪問專案

除錯 HT 資源是否正確訪問

在 views/Home.vue 下增加 created 生命週期,新建 ht.Node 節點並 console.log 出來,看控制檯是否有正確輸出。

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'home',
  components: {
    HelloWorld
  },
  created: function() {
    console.log(ht);
    let n = new ht.Node();
    console.log(n);
  }
}
</script>

瀏覽器開啟控制檯如果正確輸出 Node 節點表示 ht 引入成功

如上輸出 Node 可進行下一步。否則檢查前面流程,比如 eslint 配置,或者 script 匯入是否成功

完成第一個拓撲圖 

完成至上一步後,接下來就需要把一個 ht 的 graphView 插入到 vue 元件裡,我們在不同生命週期做不同工作,在 created 的時候建立 gv 和 dm,在 mounted 的時候把 gv 掛載到元件裡, 並新建一個圖元

1. 修改 template 如下

<template>
  <div class='home ht-view'>
      
  </div>
</template>

2. 增加 style 參考如下

<style scoped>
.ht-view {
    text-align: left;
    position: relative;
    width: 800px;
    height: 500px;
    margin: auto;
    border: 1px solid #ccc;
}
</style>

3. 按上述計劃修改 script,參考如下

export default {
  name: 'home',
  components: {
    // HelloWorld
  },
  created: function() {
    this.gv = new ht.graph.GraphView();
    this.dm = this.gv.dm();
  },
  mounted: function() {
    this.gv.addToDOM(this.$el);

    let node = new ht.Node();
    this.dm.add(node);
  }
}
</script>

儲存後,瀏覽器會熱更新,會得到如下圖介面

如圖左上方出現 1/4 個小電腦,此時一個 ht-vue 最簡單的專案就搭建完成了。我們可以在檢視中間的區域隨意操作並修改 Home.vue 程式碼來重新整理介面看效果。

可複用 2D 元件

上述實現了第一個小拓撲,但是直接修改 Home 元件達到目的,如果我們頁面裡面有很多拓撲,我們會考慮複用這個元件,下面開始可複用元件的一點介紹。

HT 的每一個作檢視展示的元件都會有一個 dataModel 來管理資料,這個 dm 是可以複用的所以我們希望把他作為獨立的載體而不是元件獨享,這個我們在教程下一步會介紹到為什麼。

基於此考慮 vue 元件的 dataModel 考慮由父節點管理,子節點 dataModel 借用 props 傳遞使用,但是帶來一個問題是父節點如果沒有傳入 dm,子節點應該有一個預設的 dataModel 作使用,那麼我們應該給 props 賦個預設值,這個值應該是子節點 graphView 預設的 dataModel。於是我們會想到給 vue 子元件 data 包裹一個 graphView,但是不幸的是 vue 元件 props 構建先於 data,所以導致無法給 props/dm 賦預設值,所以我們選擇在 vue 生命週期 beforeCreate 來手動建立 graphView 節點。

於上考慮我們在 components 下面建立一個 HT2D.vue 的元件,程式碼參考如下

<template>
  <div>
      <div ref="htview"></div>
  </div>
</template>

<script>
export default {
    name: 'HT2D',
    props: {
        dm: {
            default: function() {
                return this.g2d.dm();
            }
        }
    },
    data: function() {
        return {

        }
    },
    watch: {
        dm: function() {
            this.g2d.dm(this.dm);
            this.g2d.fitContent();
        }
    },

    beforeCreate: function() {
        this.g2d = new ht.graph.GraphView();
    },
    beforeMount: function() {
        this.g2d.dm(this.dm);
    },
    mounted: function() {
        this.g2d.addToDOM(this.$refs.htview);
        this.g2d.fitContent();
    }
}
</script>

然後在 views 下建一個 Embeded2D.vue 的元件使用這個 HT2D.vue,並傳入一個 dm 來構建檢視,可以在元件生命週期 created 加入一段測試程式碼,參考如下

<template>
    <div>
        <HT2D class='ht-view' :dm='dm' ref='g2d'></HT2D>
    </div>
</template>

<script>
import HT2D from '@/components/HT2D'

export default {
    name: 'Embeded2D',
    components: {
        HT2D,
    },
    data: function() {
        return {
            dm: new ht.DataModel(),
        }
    },
    created: function() {
        let node = new ht.Node();
        node.setImage('group_image');
        this.dm.add(node);
    },
    mounted: function() {

    }
}
</script>

<style>
.ht-view {
    text-align: left;
    position: relative;
    width: 800px;
    height: 500px;
    margin: auto;
    border: 1px solid #ccc;
}
</style>

接下來修改下路由讓這個元件展示出來,先修改下 router/index.js 的 routes 參考如下

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/2d',
    name: '2d',
    component: () => import( '../views/Embeded2D.vue')
  },
]

然後在修改下 APP.vue 的 route-link template 參考如下

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/2d">2D</router-link>
    </div>
    <keep-alive>
      <router-view />
    </keep-alive>
    
  </div>
</template>  

重新整理瀏覽器並點選路由導航 2D,會出現如下檢視,代表第一個可複用 2D 元件建立成功。

 

 這個案例中是 Embeded2D.vue 巢狀 HT2D 元件,然後以 props 的方式傳入 dm 引數,那麼可以在父元件中直接修改 dm 來改變檢視展示,比如在 Embeded.vue 生命週期 mounted 做個小測試,參考如下

    mounted: function() {
        setTimeout(() => {
            let dm = new ht.DataModel();

            let node = new ht.Node();
            node.p(100, 100);
            dm.add(node);

            node = new ht.Node();
            node.p(200, 200);
            dm.add(node);

            this.dm = dm;
        }, 3000);
    }

在 mounted 裡面過 3S 重新宣告一個 dm 並複製給 dm 物件。檢視會同步重新整理,這裡注意下箭頭函式和 vue function this 指向的問題,如上是沒有問題的。

注意下 APP.vue 有給 router-view 加上 keep-alive 屬性,這樣在路由切換的時候不會直接銷燬老的元件,可把 keep-alive 屬性去掉,然後在 Home 和 2D 之間切換並操作下 2D 檢視,比如縮放平移,然後再切換回來就能發現問題所在。到此一個基礎 HT 案例和可複用 HT 元件已經介紹完。 

可複用元件進階

上述我們一直強調 gv 的複用,並獨立出來 dm,因為 HT 資料呈現的檢視可以共用一個 dataModel,以一個 ListView 為例介紹

ListView 介紹 (http://www.hightopo.com/guide/guide/core/listview/ht-listview-guide.html)

首先像 HT2D 一樣我們在 components 下面建一個 HTList.vue 的檔案,參考如下,注意去掉 fitContent 等方法,這些是 2D 檢視專用的

<template>
  <div>
      <div ref="htview"></div>
  </div>
</template>

<script>
export default {
    name: 'HTList',
    props: {
        dm: {
            default: function() {
                return this.list.dm();
            }
        }
    },
    data: function() {
        return {

        }
    },
    watch: {
        dm: function() {
            this.list.dm(this.dm);
        }
    },

    beforeCreate: function() {
        this.list = new ht.widget.ListView();
    },
    beforeMount: function() {
        this.list.dm(this.dm);
    },
    mounted: function() {
        this.list.addToDOM(this.$refs.htview);
    },
}
</script>

然後在 views 下面建立一個 MultiHTView.vue 的元件使用 HT2D 和 HTList,並傳入相同的 dm,參考如下

<template>
    <div class = 'ht-view'>
        <HT2D class='ht-2d' :dm='dm'></HT2D>
        <HTList class='ht-list' :dm='dm'></HTList>
    </div>
</template>

<script>
import HT2D from '@/components/HT2D'
import HTList from '@/components/HTList'

export default {
    name: 'Embeded2D',
    components: {
        HT2D,
        HTList,
    },
    data: function() {
        return {
            dm: new ht.DataModel(),
        }
    },
    created: function() {
        let node = new ht.Node();
        node.setImage('group_image');
        node.setName("I'm group");
        this.dm.add(node);
    },
}
</script>

<style scoped>
.ht-view, .ht-2d, .ht-list {
    position: relative;
    box-sizing: border-box;
}
.ht-view {
    text-align: left;
    width: 810px;
    margin: auto;
}
.ht-2d, .ht-list{
    width: 400px;
    height: 300px;
    float: left;
    margin-right: 10px;
    border: 1px solid #ccc;
}
.ht-list{
    margin-right: 0;
}
</style>

 最後修改下路由,router/index.js 參考增加如下路由

  {
    path: '/multi',
    name: 'multi',
    component: () => import( '../views/MultiHTView.vue')
  }

app 增加如下 router-link

<router-link to="/multi">Multi</router-link>

 然後重新整理頁面進入 Multi 出現如下則成功

 

 這裡 HT2D 和 HTList 都是 MultiHTView 元件傳入的同一個 dm,可參考前面方法對 dm 做一段測試,MultiHTView 增加一段生命週期 mounted 測試

    mounted: function() {
        setTimeout(() => {
            var dm = new ht.DataModel();

            let node = new ht.Node();
            node.p(100, 100);
            node.setName("I'm n1 node");
            dm.add(node);

            node = new ht.Node();
            node.p(200, 200);
            node.setName("I'm n2 node");
            dm.add(node);

            this.dm = dm;
        }, 3000);
    }

 至此一個基本的 HT 2D 檢視 + HT 2D 檢視元件構建 + HT 多元件巢狀 vue 案例介紹基本完成。