2011-09-02 53 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(){有关,但一直未能找出造成问题的原因。任何想法都表示赞赏。