4

私は Infovis ツールキット プロジェクトに取り組んできましたが、すべての機能が完成しましたが、ビジュアルを完成させることができませんでした。Infovis ツールキット API のドキュメントは適切ですが、カスタム ノード タイプが機能しません。ハイパーツリーを使用しており、2 つの異なるカスタム ノード タイプを作成したいと考えています。1 つは画像からのもので、もう 1 つは描画されたパスです。すべてのヘルプは大歓迎です、ありがとう!

編集: [私が試していた解決策は、あまり便利ではないことが判明しました。代わりに、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();*/
        }
       }
});
4

4 に答える 4

7

image srcをファイルURLに設定しているため、ファイルの読み込みに時間がかかります。そのため、画像が読み込まれる前にコードがdrawImage呼び出しにヒットしています。

これを回避するには、コードを変更してdrawImage、画像のonloadイベントハンドラーで呼び出しを実行します(画像の読み込みが完了すると実行されます)。

$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';
        }
    }
});
于 2011-09-13T07:19:53.933 に答える
3

上記の答えは正しいです。ただし、それには2つの欠点があります。

1: カスタム ノードが onMouseEnter や onClick などのイベントを発生させない、contains メソッドがありません。

2: グラフ内のノードを移動するたびに、またはグラフ全体をパンするたびに、画像がちらつきます。これは、ノードを再プロットするために render 関数が呼び出されるたびにイメージがロードされるためです。これも同じ理由でパフォーマンスに影響します。より良いオプションは、「イメージ」タイプを持つすべてのノードに対してイメージを一度ロードし、レンダリング関数でそれらを再プロットすることです。これにより、パフォーマンスが向上し、画像のちらつきがなくなります。

「タイプ」を「イメージ」として各ノードにイメージをロードする関数「loadImages」を使用できます。「画像」タイプの各ノードには、ロードする画像の URL である「url」というプロパティも必要です。

json データ内のそのようなノードの「データ」セクションは、次のようになります。

"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); 
            } 
}
});
于 2013-06-13T14:04:53.193 に答える
1

Pratik による回答は、私のハイパーツリーではうまく機能しませんでした。ハイパーツリー表現でノード イメージを表示し、適切にスケーリングするために必要な小さな変更がいくつかありました。この回答が、同様の実装の問題を抱えている他のユーザーに役立つことを願っています。免責事項私は初心者のJavascriptプログラマーであり、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');
        }
    });
}

loadJSON 直後の loadImages() 関数呼び出しのタイミングに変更はありません。

私のカスタムノードは次のようになりました:

$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(){が、トラブルの原因を突き止めることができませんでした。どんな考えでも大歓迎です。

于 2014-07-16T22:56:22.407 に答える
0

他の人と何が違うのか、恐竜の時代から図書館が変わったのかはわかりません。しかし、何らかの理由で、getPos()node.pos.getc(true)使用するときに必要な実際のピクセルではなく、数学ベースの座標系が得られますHyperTree

画像を使用する場合、特に を使用する場合ctx.drawImage、JavaScript はピクセルベースの座標を想定します。私は数学の天才ではないので、問題の原因とその回避方法を理解するのに時間がかかりました。node.pos.getc(true)で与えられた値を掛けることcanvas.widthが私が見つけた唯一の回避策であり、次のようなことをするようになりました:

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

            img.onload = function () {
                ctx.drawImage(img, pos.x*canvas.Width -(imageWidth/2), pos.y*canvas.Height -(imageHeight/2))
            };

            img.src = '/resources/images/customImage.png';
        }
    }
});

予想される位置で画像を中央に配置する必要があります。

于 2020-06-13T14:58:51.890 に答える