HT for Web列表和3D拓撲組件的拖拽應用

不少可視化編輯器都或多或少有一些拖拽功能,好比從一個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, &lsquo;data:image/jpeg;base64,...');&hellip;&hellip;

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(&lsquo;#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的源代碼,感興趣的朋友能夠載下來看看,同時也歡迎你們留言質詢。

下載源碼

相關文章
相關標籤/搜索