天天看點

基于HTML5 Canvas 點選添加 2D 3D 機櫃模型

今天又傳回好好地消化了一下我們的資料容器 DataModel,這裡給新手做一個典型的資料模型事件處理的例子作為參考。這個例子看起來很簡單,實際上結合了資料模型中非常重要的三個事件處理的部分:屬性變化事件監聽、選中變化事件監聽以及資料模型變化事件監聽。

為了讓這個例子具現化,我将這個簡單的例子做了一點改動,下面我會一一解釋。

基于HTML5 Canvas 點選添加 2D 3D 機櫃模型

這是我改造之後的模樣,将 dataModel 資料容器共享,通過對資料容器的增删事件的監聽得到的現在的結果,并且在顯示上做了一點“手腳”。下面我們從頭解析這例子,你們會知道為什麼我特地将這個簡單的例子提出來。

首先,我們得建立場景将作為基礎,整個場景我算是分為三個部分,頂部工具欄,2D 部分以及 3D 部分。頂部工具欄部分使用的純 HTML 寫的:

因為有點選事件,是以我們直接在 button 按鈕上進行,後面的 span 标簽顯示純文字内容。

我們知道,HT 的所有元件都是基于一個根部 div 的,要将這個 div 部署到 html 頁面上很簡單,但是 HT 内部對這個 div 設定了絕對定位,是以我們在添加這個 div 進 HTML 頁面中時,也要設定絕對定位中的位置,我在頁面中添加了一個 div,将 HT 的部分都添加進這個 div 中:

接着添加節點進入 dataModel 資料模型之中,我們這裡做的是機房的機櫃,本來想做的是伺服器,手頭上暫時隻有這個資源,也不賴。我封裝了一個增加函數,一個删除函數,還有一個清楚函數,分别對應的是工具欄上的“Add”、“Remove”以及“Clear”三個功能:

2D 的圖檔顯示肯定和 3D 的模型顯示是不一樣的,2D 中我們直接用貼圖就能解決,而 HT 3D 中支援 obj 格式的模型顯示,就是這個部分:

基于HTML5 Canvas 點選添加 2D 3D 機櫃模型

HT 封裝了解析 obj 格式的函數 ht.Default.loadObj 函數用來導入模型,該函數有三個參數,第一第二分别為 obj 檔案的路徑和 mtl 檔案的路徑,第三個參數為 json 格式控制參數,具體參數請參考 HT for Web OBJ 手冊 loadObj 函數章節(ps:用 obj 模型會導緻跨域問題,要放到伺服器上運作):

現在,節點和模型都已經導入到場景中了,終于來到了我們今天的重點,事件互動部分。ht.DataModel 資料容器管理着 Data 資料的增删以及變化事件的派發,這裡我們就這兩種事件進行對 Data 資料的管理。

1. addDataModelChangeListener(function(e) {}, scope) 增加資料模型增删變化事件監聽器,可用簡寫 mm(func, scope), func 為監聽器函數,scope 為監聽器函數域(可選),在監聽器函數中的 event 有兩個屬性: kind 和 data,其中 kind 為事件的類型:

<code>e.kind === 'add'</code>代表添加<code>Data</code>對象,<code>e.data</code>為被添加的對象

<code>e.kind === 'remove'</code>代表删除<code>Data</code>對象,<code>e.data</code>為被删除的對象

<code>e.kind === 'clear'</code>代表容器被清除

這裡我們将對模型的增删事件的監聽結果傳給 HTML 中的 id 為 model 的 span 作為内容:

2. addDataPropertyChangeListener(function(e) {}, scope) 增加模型中 Data 資料屬性變化事件監聽器,可用簡寫 md(func, scope),其中 event 事件有四種屬性:

<code>e.data</code>代表屬性變化的對象

<code>e.property</code>代表變化屬性的名字

<code>e.newValue</code>代表屬性的新值

<code>e.oldValue</code>代表屬性的老值

<code>Data</code>對象在設定屬性值函數内調用<code>firePropertyChange(property, oldValue, newValue)</code>觸發屬性變化事件:

<code>get/set</code>類型屬性,如<code>setAge(98)</code>觸發事件的<code>e.property</code>為<code>age</code>

<code>style</code>類型屬性名前加<code>s:</code>字首以區分,如<code>setStyle('age', 98)</code>觸發事件的<code>e.property</code>為<code>s:age</code>

<code>attr</code>類型屬性名前加<code>a:</code>字首以區分,如<code>setAttr('age', 98)</code>觸發事件的<code>e.property</code>為<code>a:age</code>

這裡我們将對模型中 Data 的屬性變化事件的監聽結果傳給 HTML 中的 id 為 property 的 span 作為内容:

3. 最後,我們對選中的節點進行增加監聽器,監聽選中變化事件。ht.SelectionModel管理 DataModel 模型中 Data 對象的選擇狀态, 每個 DataModel 對象都内置一個 SelectionModel 選擇模型,控制這個 SelectionModel 即可控制所有綁定該 DataModel 的元件的對象選擇狀态, 這意味着共享同一 DataModel 的元件預設就具有選中關聯功能。

如果希望某些元件不與其他元件選中關聯,可通過調用 view.setSelectionModelShared(false), 這樣該 view 将建立一個專屬的 SelectionModel 執行個體。

綜上所述有兩種途徑可得到 SelectionModel:<code></code>

<code>dataModel.getSelectionModel()</code>擷取資料容器中元件共享的選中模型。

<code>view.getSelectionModel()</code>擷取目前元件使用的選中模型,<code>selectionModelShared</code>為<code>false</code>時,傳回<code>view</code>專用的選擇模型。

addSelectionChangeListener(function(e) {}, scope)增加監聽器,監聽選中變化事件,簡寫為 ms(func, scope):

<code>e.datas</code>包含所有選中狀态變化的對象,之前選中現在取消選中,或之前沒選中現在被選中的對象

<code>e.kind === 'set'</code>代表此事件由<code>setSelection(datas)</code>引發

<code>e.kind === 'remove'</code>代表此事件由<code>removeSelection(datas)</code>引發

<code>e.kind === 'append'</code>代表此事件由<code>appendSelection(datas)</code>引發

<code>e.kind === 'clear'</code>代表此事件由<code>clearSelection(datas)</code>引發

這裡我們将對模型中 Data 的選中變化事件的監聽結果傳給 HTML 中的 id 為 selection 的 span 作為内容:

以上,所有的代碼全部分析完畢!大家可以天馬行空,建立出屬于你自己的3維模型!

繼續閱讀