2011-09-02 50 views
3

我一直在研究一個Infovis工具包項目,儘管所有的功能都完成了,但我還是無法完成視覺效果。 Infovis工具包API文檔很好,但我的自定義節點類型不起作用。我使用的是hypertree,我想製作兩種不同的自定義節點類型。一個來自圖像,另一個是繪製的路徑。所有的幫助非常感謝,謝謝!如何在Infovis Toolkit中創建自定義節點?

編輯:[我試圖解決的方案並不那麼得心應手。相反,我使用JIT控制器中的onCreateLabel()來使用HTML自定義節點。在性能方面取得了明顯的改善,並在定製節點方面獲得了更大的靈活性。 ]

這是我想出迄今:

$jit.Hypertree.Plot.NodeTypes.implement({ 
    'customNode': { 
     'render': function(node, canvas) { 
      var img = new Image(); 
      img.src = "../icon.png"; 
      var pos = node.pos.getc(true); 
      var ctx = canvas.getCtx(); 

      ctx.drawImage(img, pos.x-15, pos.y-15);     
      /* 
      //...And an other one like this but drawn as a path 
      ctx.beginPath(); 
      ctx.moveTo(pos.x-25, pos.y-15); 
      ctx.lineTo(25, -15); 
      ctx.lineTo(-35, 0); 
      ctx.closePath(); 
      ctx.strokeStyle = "#fff"; 
      ctx.fillStyle = "#bf5fa4"; 
      ctx.fill(); 
      ctx.stroke();*/ 
     } 
     } 
}); 

回答

7

因爲你設置的圖片src的文件URL,它需要時間來加載文件。所以代碼在圖像加載之前打了drawImage

您可以通過修改代碼來在圖像的onload事件處理程序中運行drawImage調用(在圖像加載完成後運行)來解決此問題。

$jit.Hypertree.Plot.NodeTypes.implement({ 
    'customNode': { 
     'render': function (node, canvas) { 
      var img = new Image(), 
       pos = node.pos.getc(true), 
       ctx = canvas.getCtx(); 

      img.onload = function() { 
       ctx.drawImage(img, pos.x - 15, pos.y - 15); 
      }; 

      img.src = '../icon.png'; 
     } 
    } 
}); 
3

上面給出的答案是正確的。但是它有兩個缺點。

1:它沒有包含沒有它,自定義節點將不會觸發像OnMouseEnter在或的onClick事件等方法

2:圖像閃爍每次移動任何節點圖,或者你出鍋的任何時間整個圖。這是因爲每次調用render函數重新繪製節點時都會加載圖像。由於相同的原因,這也會影響性能。更好的選擇是爲所有具有「圖像」類型的節點加載一次圖像,並僅在渲染功能中重新繪製它們。這將有助於提高性能並阻止圖像閃爍。

我們可以有一個函數'loadImages',它在每個節點中加載'type'爲'image'的圖像。每個類型爲'image'的節點都應該有一個名爲'url'的屬性,它是要加載的圖像的url。

json數據中這樣的節點的'Data'部分看起來像下面的樣子。

"data": { 
     "$color": "#EBB056", 
     "$type": "image", 
     "$dim": 7, 
     "$url":"magnify.png" // url of the image 
    } 

的loadImages功能應該被稱爲loadJson函數即後右後右裝載JSON數據。

// load JSON data. 
fd.loadJSON(json); 

//load images in node 
loadImages(); 

下面是loadImages函數的實現。

function loadImages(){ 
    fd.graph.eachNode(function(node){ 
     if(node.getData('type') == 'image'){ 
      var img = new Image(); 
      img.addEventListener('load', function(){ 
       node.setData('image',img); // store this image object in node 
      }, false); 
      img.src=node.getData('url'); 
     } 
    }); 
} 

最後,您的自定義節點實現將如下所示。

$jit.ForceDirected.Plot.NodeTypes.implement({ 
'image': { 
     'render': function(node, canvas){ 
       var ctx = canvas.getCtx(); 
       var pos = node.pos.getc(true); 
       if(node.getData('image') != 0){ 
       var img = node.getData('image'); 
       ctx.drawImage(img, pos.x-15, pos.y-15); 
       } 
      }, 
      'contains': function(node,pos){ 
       var npos = node.pos.getc(true); 
       dim = node.getData('dim'); 
       return this.nodeHelper.circle.contains(npos, pos, dim); 
      } 
} 
}); 
0

通過PRATIK給出的答案也不太工作對我超樹 - 有我需要做得到節點圖像的顯示,並在超樹表示適當擴展一些小的修改。希望這個答案能夠幫助其他類似實現麻煩的用戶。 免責聲明我是一個新手程序員,很可能我錯過了Pratik答案中的一些必要的東西,它會使它工作。而且,如果沒有他的回答,我永遠不會接近,對此我很感激。

沒有更改json中的數據定義 - 按預期工作。對我來說的一個關鍵是確保設置overridable: true,例如

var ht = new $jit.Hypertree({ 
    Node: { 
     overridable: true, 
     dim: 9, 
     color: "#ffffff", 
     type: "square" 
    }, 

我需要圖像高度/寬度來稍後適當地縮放它們。我實現了它在由PRATIK提供的loadImages功能,因此它只能運行一次:

function loadImages(){ 
    ht.graph.eachNode(function(node){ 
     if(node.getData('type') == 'image'){ 
      var img = new Image(); 
      img.addEventListener('load', function(){ 
       node.setData('image',img); // store this image object in node 
       node.setData('imageheight',this.height); 
       node.setData('imagewidth',this.width); 
      }, false); 
      img.src=node.getData('url'); 
     } 
    }); 
} 

沒有變化的loadImages()函數調用只是loadJSON後的時間。

我的自定義節點是這樣的:

$jit.Hypertree.Plot.NodeTypes.implement({ 
    'image': { 
      'render': function(node, canvas){ 
        var ctx = canvas.getCtx(); 
        var pos = node.pos.getc().$scale(node.scale); 
        var nconfig = this.node; 
        if(node.getData('image') != 0){ 
         var img = node.getData('image'); 
         var dim = node.getData('dim'); 
         var w = node.getData('imagewidth'); 
         var h = node.getData('imageheight'); 
         var r = 50/h; // Scaling factor to scale images to 50px height 
         w = r * w; 
         h = r * h; 
         var dist = Math.sqrt((pos.x*pos.x)+(pos.y*pos.y)); //dist to origin 
         var scale = 1 - (dist/node.scale); 
         // scale nodes based on distance to origin 
         var sw = nconfig.transform ? w * scale : w/dim/2; 
         var sh = nconfig.transform ? h * scale : h/dim/2; 
         if (node._depth < 2) { 
          ctx.drawImage(img, 
           pos.x - sh/2, //center images on nodes 
           pos.y - sw/2, 
           sw, 
           sh); 
         } 
        } 
       }, 
       'contains': function(node,pos){ 
        var npos = node.pos.getc().$scale(node.scale); 
        var h = node.getData('imageheight'); 
        var w = node.getData('imagewidth'); 
        return this.nodeHelper.rectangle.contains(npos, pos, w, h); 
       } 
      } 
    }); 

唯一懸而未決的問題是,圖像不會出現,直到我已單擊圖表後。我認爲這與img.addEventListener('load', function(){有關,但一直未能找出造成問題的原因。任何想法都表示讚賞。