學習 HT for Web 中的互動事件
互動事件增強了使用者體驗,使得我們的作品更加生動。今天,使用 HT for Web 寫了個典型的 Demo 來了解 HT 中的互動事件。
場景如下所示,在該場景中雙擊溫度和溼度下的 Node,會生成輸入框供使用者填寫內容,這之後,使用者按下 “Enter” 鍵可以將輸入內容傳到 Node 中,同時刪除輸入框,地址:http://www.hightopo.com/demo/GraphInput/display.html
接下來我們探討一下具體實現:
準備工作如下:先引入我們的 ht.js
<script src='ht.js'></script>
新建一張拓撲圖紙,並將其加入頁面。
dataModel = new ht.DataModel();
graphView = new ht.graph.GraphView(dataModel);
graphView.addToDOM();
1、 利用系統中定義好的向量資源進行反序列化來實現場景圖:
ht.Default.xhrLoad('TemperatureIndex.json', function(text) {
var json = ht.Default.parse(text);
if(json.title) document.title = json.title;
dataModel.deserialize(json);
}
2、 雙擊事件
本例雙擊會產生輸入框,在我們的 HT 中,GraphView 預設內建了一些互動器,以實現基本的選擇、單雙擊、縮放、平移和編輯等互動的功能,內建的互動器有:
內建的 Interactor 在互動過程中會派發事件,可通過 GraphView#addInteractorListener 進行監聽,簡寫為mi(詳情可看 HT for Web 入門手冊),在這裡,我們用內建的 graphView.addInteractorListener 監聽雙擊事件:
graphView.addInteractorListener(function(e){
if (e.kind !== 'doubleClickData') return;
if (currentInput) removeInput();
var data = e.data;
if (clickableTags[data.getTag()]){
setTimeout(function(){
createInput('input', data);
}, 0);
}
});
3、 建立輸入框
在雙擊事件發生時,首先需要判斷髮生雙擊事件的元素是不是場景中定義的標籤名為 ‘temperature’ 和 ‘humidity’ 的 node 圖元,我們用 clickableTags 物件來儲存兩個 node:
var clickableTags = {
'temperature': true,
'humidity': true
}
在雙擊的圖元是 ‘temperature’ 或者 ‘humidity’ 時,呼叫 createInput() 函式生成輸入框, createInput() 程式碼如下:
function createInput(tagName,node){
if (currentInput) {
removeInput(graphView, currentInput);
return;
} else {
var element = document.createElement(tagName);
graphView.getView().appendChild(element);
element.bindingNode = node;
ht.Default.setFocus(element);
currentInput = element;
layout(currentInput); // 佈局
return currentInput;
}
}
在 createInput() 函式中,用全域性變數 currentInput 儲存著當前生成的輸入框元素,為保證再次生成輸入框時,呼叫 removeInput() 清除上次生成的輸入框元素,從而不影響效能。
4、 佈局
生成的輸入框應該放在哪兒?這就是 layout() 函式中所做的事情。layout() 函式修改生成的輸入框的位置資訊,讓其在 GraphView 拓撲圖元件上的位置剛好與 node 圖元的位置相同。
function layout(element){
var rect = element.bindingNode.getRect();
var x = rect.x;
var y = rect.y;
element.style.position = 'absolute';
element.style.width = rect.width + 'px';
element.style.height = rect.height + 'px';
element.style.top = y + 'px';
element.style.left = x + 'px';
element.style.background = '#fff';
element.style.color = '#000';
element.style.textAlign = 'center';
}
以 ‘temperature’ 為例,在點選標籤名為 ‘temperature’ 的 node 圖元時,會在其上生成一個輸入框,獲取該 node 圖元的寬、高、位置資訊,並分別賦值給絕對定位後輸入框的寬、高、位置,這樣即可讓輸入框剛好覆蓋住 node 圖元。
5、 平移和縮放
做到這裡,可能細心思考的朋友會發現,在對整個場景圖進行平移和縮放時,按照上訴佈局方式,輸入框的位置和大小卻沒有跟隨著 node 圖元的位置進行改變,所以我們在佈局時還需要思考到平移、縮放事件。
首先,layout 函式的內容中,元素的寬、高、位置資訊必須加入平移和縮放產生的結果,所以,最終 layout 程式碼如下:
function layout(element){
var rect = element.bindingNode.getRect();
var zoom = graphView.getZoom();
var tx = graphView.tx();
var ty = graphView.ty();
rect.x *= zoom;
rect.y *= zoom;
rect.width *= zoom;
rect.height *= zoom;
var x = tx + rect.x;
var y = ty + rect.y;
element.style.position = 'absolute';
element.style.width = rect.width + 'px';
element.style.height = rect.height + 'px';
element.style.top = y + 'px';
element.style.left = x + 'px';
element.style.background = '#fff';
element.style.color = '#000';
element.style.textAlign = 'center';
}
其次,我們需要對平移和縮放事件新增監聽,以便能在該事件發生時,再次呼叫 layout() 函式將輸入框的位置進行同步,在這裡,我們用內建的互動器 addPropertyChangeListener(簡寫為mp),監聽 zoom、translateX、translateY 屬性的變化:
var changeProperties = {
'zoom': true,
'translateX': true,
'translateY':true
}
graphView.mp(function(e) {
if (changeProperties[e.property]) {
var elements = document.getElementsByTagName('input');
for (var i = 0; i < elements.length; i++) {
layout(elements[i]);
}
}
});
6、 更新 node
大家在 Demo 中可以發現,我們按下 Enter 鍵時,輸入的文字會同步到 node 中,其實這裡做了兩件事: 給 node 設值後刪除輸入框。
a、給 node 設值,是用一個名為 setText() 的函式來實現的,實現程式碼如下:
function setText(tagName){
var element = document.getElementsByTagName(tagName);
if(!element) return;
for (var i = 0; i < element.length; i++) {
var value = (element[i].value) ? element[i].value : 32 ;
element[i].bindingNode.s('text', value);
}
}
在檢測輸入框中有值時,給 node 圖元賦值用到我們 HT 的 setStyle(簡寫為s)方法。
b、刪除輸入框
function removeInput(){
if(!currentInput) return;
graphView.getView().removeChild(currentInput);
currentInput = null;
}
c、新增 Enter 的事件監聽器
因為沒有監聽鍵盤的內建互動器,所以我們通過 graphView.getView().addEventListener 直接對底層的 div 新增監聽。
graphView.getView().addEventListener('keydown', function(event){
if(ht.Default.isEnter(event)){
setText('input');
removeInput();
} else if(ht.Default.isEsc(event)){
removeInput();
}
}, false);
最後,再貼上 Demo 地址(http://www.hightopo.com/demo/GraphInput/display.html ),希望能夠幫助那些需要在拓撲圖中加入原生 HTML 的朋友,也望大家不吝賜教。
相關文章
- HT for Web (Hightopo) 使用心得(5)- 動畫的實現Web動畫
- 學習 PixiJS — 互動工具JS
- (資料科學學習手札116)Python+Dash快速web應用開發——互動表格篇(中)資料科學PythonWeb
- (資料科學學習手札105)Python+Dash快速web應用開發——回撥互動篇(中)資料科學PythonWeb
- MySQL與Python的互動學習筆記MySqlPython筆記
- web互動方式---ajaxWeb
- Hive學習之常用互動命令Hive
- Flutter學習之佈局、互動、動畫Flutter動畫
- 演變:機器學習和基於 Web 的體驗 ,快速、實時和完全互動機器學習Web
- Flutter:如何響應互動事件?Flutter事件
- Flutter 使用者互動事件的響應Flutter事件
- Java學習 使用者互動 ScannerJava
- 如何有效學習互動設計1
- 如何有效學習互動設計2
- Beego框架學習--(核心:資料互動)Go框架
- Flutter學習指南:互動、手勢和動畫Flutter動畫
- web與APP之間的互動—WebViewJavascriptBridgeAPPWebViewJavaScript
- python中web開發框架Django的學習PythonWeb框架Django
- (資料科學學習手札115)Python+Dash快速web應用開發——互動表格篇(上)資料科學PythonWeb
- (資料科學學習手札117)Python+Dash快速web應用開發——互動表格篇(下)資料科學PythonWeb
- Electron學習(三)之簡單互動操作
- (資料科學學習手札104)Python+Dash快速web應用開發——回撥互動篇(上)資料科學PythonWeb
- (資料科學學習手札106)Python+Dash快速web應用開發——回撥互動篇(下)資料科學PythonWeb
- 圖撲 HT for Web 手機端運維管理系統Web運維
- 深度學習中的互資訊:無監督提取特徵深度學習特徵
- web 多屏互動顯示方案Web
- 事件註冊與事件代理學習事件
- 記錄下學習筆記(Laravel 中的事件監聽)筆記Laravel事件
- 區塊鏈學習-Golang 與智慧合約的互動(一)區塊鏈Golang
- springCloud學習5(Spring-Cloud-Stream事件驅動)SpringGCCloud事件
- 拖放事件(自己的學習筆記)事件筆記
- Java中的事件溯源簡介:包含學習進度的練習工具包Java事件
- Rust使用Sauron實現Web介面互動RustWeb
- 007 Web Assembly康威遊戲新增互動Web遊戲
- Redis 中的事件驅動模型Redis事件模型
- JS學習之事件和事件繫結JS事件
- 表單事件與鍵盤事件學習事件
- 移動Web——localStorage,sessionStorage,Storage事件監聽WebSession事件