不少可視化編輯器都或多或少有一些拖拽功能,好比從一個List列表中拖拽一個節點到拓撲組件上進行建模,而且在拖拽的過程當中鼠標位置下會附帶一個被拖拽節點的縮略圖,那麼今天咱們就來實現這樣的拖拽效果。php
首先咱們須要建立一個List列表,在列表中加入圖片信息,讓List列表不那麼單調,先來看看效果圖。html
接下來咱們一步一步來是想這個List列表,先來解決下數據,在這裏我就列舉一兩個:node
var products = [ { ProductId : 1, ProductName : "Chai", QuantityPerUnit : "10 boxes x 20 bags", UnitPrice : 18.00, Description : "Soft drinks, coffees, teas, beers, and ales" }, { ProductId : 2, ProductName : "Chang", QuantityPerUnit : "24 - 12 oz bottles", UnitPrice : 19.00, Description : "Soft drinks, coffees, teas, beers, and ales" }, …… ];
有了數據,咱們就能夠來建立List組件了:canvas
var listView = new ht.widget.ListView(), view = listView.getView(); document.body.appendChild(view);
這時咱們建立的是一個空的List組件,在瀏覽器上看不到任何東西,那麼接下來咱們就該把咱們定義的數據添加到List組件上了:瀏覽器
products.forEach(function(product){ var data = new ht.Data(); data.a(product); listView.dm().add(data); });
數據的添加是否是很簡單,可是List組件上顯示的內容默認是Data的name屬性或displayName屬性,在建立Data時,並無對Data設置displayName或者name屬性,因此這個時候在頁面上看到的仍是一個空的List組件,別急,咱們能夠在不設置displayName或name屬性的狀況下讓組件顯示效果圖上的文本內容,請看:緩存
listView.getLabel = function(data){ return data.a('ProductName') + ' - $' + data.a('UnitPrice').toFixed(2); };
嘿嘿,ListView組件提供了getLabel方法供用戶重載來實現自定義顯示文本內容,這下應該就能夠顯示文本內容了吧~app
oh no~仍是什麼都沒有,是否是還少了點什麼呢~對了,忘記給ListView組件添加鋪滿瀏覽器的樣式了,將廈門的樣式添加到head標籤中:編輯器
<style> html, body { padding: 0px; margin: 0px; } .main { margin: 0px; padding: 0px; position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; }</style>
接下來指定view的className屬性:this
view.className = 'main';
噢~總算出來了~spa
行高過小了,背景也太單調了,向效果圖看齊:
listView.setRowHeight(50); listView.drawRowBackground = function(g, data, selected, x, y, width, height){ if(this.isSelected(data)){ g.fillStyle = '#87A6CB'; } else if(this.getRowIndex(data) % 2 === 0){ g.fillStyle = '#F1F4F7'; } else{ g.fillStyle = '#FAFAFA'; } g.beginPath(); g.rect(x, y, width, height); g.fill(); };
經過setRowHeight()方法設置行高,經過重載drawRowBackground()方法繪製交叉背景。
嘿,有點樣子了,和效果圖愈來愈近了~那麼就差圖標了呢。
ht.Default.setImage('1', 40, 40, 'data:image/jpeg;base64,...'); ht.Default.setImage('2', 40, 40, ‘data:image/jpeg;base64,...');…… listView.setIndent(60); listView.getIcon = function(data){ return data.a('ProductId'); };
經過ht.Default.setImage()方法定義ProductId對應的圖片資源,以ProductId做爲圖片的別名,而後接下來定義icon位置大小爲60,重載ListView的getIcon方法返回數據中定義的ProductId屬性,如此就能夠看到圖標了。
還沒完,效果圖上顯示的圖片是圓形的,這該如何是好呢?別急,咱們有萬能的矢量,上麼樣的圖形都難不倒咱們:
ht.Default.setImage('productIcon', { width: 50, height: 50, clip: function(g, width, height) { g.beginPath(); g.arc(width/2, height/2, Math.min(width, height)/2-3, 0, Math.PI * 2, true); g.clip(); }, comps: [ { type: 'image', stretch: 'uniform', rect: [0, 0, 50, 50], name: {func: function(data){return data.a('ProductId');}} } ] });
在代碼中咱們定義了一個名稱爲productIcon的矢量,在矢量中經過clip屬性定義裁切區域,效果就是超出該裁切區域外的內容將被隱藏。如今矢量定義好了,咱們只須要在ListView的getIcon()方法中返回咱們定義的矢量名稱就能夠實現圓形圖標了:
listView.getIcon = function(data){ return 'productIcon'; };
到這裏,和效果圖的效果就如出一轍了~那麼接下來咱們就該建立3D拓撲組件了,來看看效果圖:
很簡單,就在3D拓撲中放兩個正方體:
var g3d = new ht.graph3d.Graph3dView();var node = new ht.Node(); node.s3(30, 30, 30); node.p3(-30, 15, 0); node.s('all.color', '#87A6CB'); g3d.dm().add(node); node = new ht.Node(); node.s3(30, 30, 30); node.p3(30, 15, 0); node.s('all.color', '#87A6CB'); node.setElevation(15); g3d.dm().add(node);
這是你會發現並無像效果圖中顯示的那麼會有網格效果,而且視角也不對,沒事,待我添加幾個屬性:
g3d.setEye(-100, 100, 80); g3d.setGridVisible(true); g3d.setGridColor(‘#F1F4F7');
如此就和效果圖如出一轍了~
ListView和3D拓撲是兩個獨立的組件,咱們該如何將這兩個組件組合在一塊兒呢?這時候,我想到了BorderPane組件,將List組件放在左邊,將3D拓撲組件放在右邊:
var borderPane = new ht.widget.BorderPane(); borderPane.setLeftView(listView, 350); borderPane.setCenterView(g3d);
看,成功將兩個組件合併在一塊兒了,離成功不遠了。接下來就是今天的重頭戲了,該如何實現拖拽List上的節點到3D拓撲上,並實現節點的圖標吸附到3D拓撲的圖元上呢,我給你們細細道來。
首先先來了解下ListView的handleDragAndDrop()方法,draganddrop一共有4個狀態:prepare、begin、between和end,可更具這4個不一樣狀態來作不一樣的業務處理。
第一步,咱們來實現鼠標附帶圖標的效果,在拖拽ListView的節點時,在鼠標下方增長一個該節點的縮略圖:
思路是這樣的:
1. 在prepare狀態時獲取當前拖拽節點的ProductId屬性,並經過調用ht.Default.toCanvas()方法將當前拖拽節點結合矢量productIcon得到一個canvas對象;
2. 在begin狀態時根據鼠標當前位置設置canvas對象的left和top屬性,並將其添加到DOM樹中;
3. 在between狀態時,根據鼠標位置信息,從新設置canvas對象的left和top屬性,令canvas對象一直跟着鼠標在移動;
4. 在end狀態時,將canvas對象移除DOM樹。
var dragImage = null, productId = null; listView.handleDragAndDrop = function(e, state) { if (state === 'prepare') { var data = listView.getDataAt(e); listView.sm().ss(data); if (dragImage && dragImage.parentNode) { document.body.removeChild(dragImage); } dragImage = ht.Default.toCanvas('productIcon', 30, 30, 'uniform', data); productId = data.a('ProductId'); } else if (state === 'begin') { if (dragImage) { var pagePoint = ht.Default.getPagePoint(e); dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px'; dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; document.body.appendChild(dragImage); } } else if (state === 'between') { if (dragImage) { var pagePoint = ht.Default.getPagePoint(e); dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px'; dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; } } else { if (dragImage) { if (dragImage.parentNode) { document.body.removeChild(dragImage); } dragImage = null; productId = null; } } };
如此在拖拽ListView節點時就可以看到有一個小圖標一直跟着鼠標在移動。
OK,接下來該解決圖元吸附功能,當鼠標拖拽ListView節點到3D拓撲上的圖元是,將該節點的圖標設置爲圖元當前面的貼圖。
思路是這樣子的:
1. 在between狀態時,經過ht.Default.containedInView()方法判斷殿前鼠標是否在3D拓撲組件上;
2. 若鼠標在3D拓撲上,則經過g3d.getHitFaceInfo()方法,根據鼠標當前信息獲取當前鼠標下的圖元表面信息;
3. 若當前鼠標在圖元的某個表面上,則先保存該圖元表面信息的貼圖,而後設置當前圖元表面的貼圖爲拖拽節點對應的圖片,最後將當前圖元表面信息緩存下來,當鼠標離開該表面時,還原圖元的貼圖;
4. 在end狀態時,若是當前鼠標位置在某個圖元表面時,就將當前拖拽節點的對應的圖片作爲當前圖元表面的貼圖。
那麼接下來就須要對ListView組件的handleDragAndDrop()方法作些微的修改了。
listView.handleDragAndDrop = function(e, state) { if (state === 'prepare') { var data = listView.getDataAt(e); listView.sm().ss(data); if (dragImage && dragImage.parentNode) { document.body.removeChild(dragImage); } dragImage = ht.Default.toCanvas('productIcon', 30, 30, 'uniform', data); productId = data.a('ProductId'); } else if (state === 'begin') { if (dragImage) { var pagePoint = ht.Default.getPagePoint(e); dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px'; dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; document.body.appendChild(dragImage); } } else if (state === 'between') { if (dragImage) { var pagePoint = ht.Default.getPagePoint(e); dragImage.style.left = pagePoint.x - dragImage.width / 2 + 'px'; dragImage.style.top = pagePoint.y - dragImage.height / 2 + 'px'; if (ht.Default.containedInView(e, g3d)) { if (lastFaceInfo) { lastFaceInfo.data.s(lastFaceInfo.face + '.image', lastFaceInfo.oldValue); lastFaceInfo = null; } var faceInfo = g3d.getHitFaceInfo(e); if (faceInfo) { faceInfo.oldValue = faceInfo.data.s(faceInfo.face + '.image'); faceInfo.data.s(faceInfo.face + '.image', productId); lastFaceInfo = faceInfo; } } } } else { if (dragImage) { if (lastFaceInfo) { lastFaceInfo.data.s(lastFaceInfo.face + '.image', lastFaceInfo.oldValue); lastFaceInfo = null; } if (ht.Default.containedInView(e, g3d)) { var faceInfo = g3d.getHitFaceInfo(e); if (faceInfo) { faceInfo.data.s(faceInfo.face + '.image', productId); } } if (dragImage.parentNode) { document.body.removeChild(dragImage); } dragImage = null; productId = null; } } };
在看看最後的效果圖吧
今天就到這吧,將的內容有點多,涉及到HT for Web的知識點也比較多,下面附上本次Demo的源代碼,感興趣的朋友能夠載下來看看,同時也歡迎你們留言質詢。