(本文中 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 案例介紹基本完成。