2017-12-10 6 views
3

こんにちはみんな、 私はng2-nvd3コンポーネントを使用して角度CLIプロジェクト(http://bl.ocks.org/mbostock/1153292)にD3可視化ネットワークグラフを統合しようとしています。以下 D3.js角度CLIダニに失われた、スコープ()メソッド

は、角度成分である:Webアプリケーション負荷が、それはまた、グラフをロード

import { Component, OnInit } from '@angular/core'; 
declare let d3: any; 

@Component({ 
    selector: 'app-visual', 
    templateUrl: './visual.component.html', 
    styleUrls: ['./visual.component.css'] 
}) 
export class VisualComponent implements OnInit { 
    private links = [ 
    { source: "Microsoft", target: "Amazon", type: "licensing" }, 
    { source: "Microsoft", target: "HTC", type: "licensing" }, 
    { source: "Samsung", target: "Apple", type: "suit" }, 
    { source: "Motorola", target: "Apple", type: "suit" }, 
    { source: "Nokia", target: "Apple", type: "resolved" }, 
    { source: "HTC", target: "Apple", type: "suit" }, 
    { source: "Kodak", target: "Apple", type: "suit" }, 
    { source: "Microsoft", target: "Barnes & Noble", type: "suit" }, 
    { source: "Microsoft", target: "Foxconn", type: "suit" }, 
    { source: "Oracle", target: "Google", type: "suit" }, 
    { source: "Apple", target: "HTC", type: "suit" }, 
    { source: "Microsoft", target: "Inventec", type: "suit" }, 
    { source: "Samsung", target: "Kodak", type: "resolved" }, 
    { source: "LG", target: "Kodak", type: "resolved" }, 
    { source: "RIM", target: "Kodak", type: "suit" }, 
    { source: "Sony", target: "LG", type: "suit" }, 
    { source: "Kodak", target: "LG", type: "resolved" }, 
    { source: "Apple", target: "Nokia", type: "resolved" }, 
    { source: "Qualcomm", target: "Nokia", type: "resolved" }, 
    { source: "Apple", target: "Motorola", type: "suit" }, 
    { source: "Microsoft", target: "Motorola", type: "suit" }, 
    { source: "Motorola", target: "Microsoft", type: "suit" }, 
    { source: "Huawei", target: "ZTE", type: "suit" }, 
    { source: "Ericsson", target: "ZTE", type: "suit" }, 
    { source: "Kodak", target: "Samsung", type: "resolved" }, 
    { source: "Apple", target: "Samsung", type: "suit" }, 
    { source: "Kodak", target: "RIM", type: "suit" }, 
    { source: "Nokia", target: "Qualcomm", type: "suit" } 
    ]; 
    private nodes: Array<Object> = []; 
    private width = 960; 
    private height = 500; 
    private force: any; 
    public svg: any; 
    private path: any; 
    private circle: any; 
    private text: any; 

    constructor(/*d3Service: D3Service*/) { 
    // this.d3 = d3Service.getD3(); 
    } 



ngOnInit() { 
    // let d3 = this.d3; 
    this.computeLinks(this.nodes); 
    this.forceLayout(); 
    this.appendGraph(); 
    } 

    computeLinks(nodes) { 
    // Compute the distinct nodes from the links. 
    this.links.forEach(function (link) { 
     link.source = nodes[link.source] || (nodes[link.source] = { name: link.source }); 
     link.target = nodes[link.target] || (nodes[link.target] = { name: link.target }); 
    }); 
    this.nodes = nodes; 
    } 


    forceLayout() { 
    this.force = d3.layout.force() 
     .nodes(d3.values(this.nodes)) 
     .links(this.links) 
     .size([this.width, this.height]) 
     .linkDistance(60) 
     .charge(-300) 
     .on("tick", this.tick) 
     .start(); 
    } 

    appendGraph() { 
    this.svg = d3.select(".graph").append("svg") 
     .attr("width", this.width) 
     .attr("height", this.height); 

    // Per-type markers, as they don't inherit styles. 
    this.svg.append("defs").selectAll("marker") 
     .data(["suit", "licensing", "resolved"]) 
     .enter().append("marker") 
     .attr("id", function (d) { return d; }) 
     .attr("viewBox", "0 -5 10 10") 
     .attr("refX", 15) 
     .attr("refY", -1.5) 
     .attr("markerWidth", 6) 
     .attr("markerHeight", 6) 
     .attr("orient", "auto") 
     .append("path") 
     .attr("d", "M0,-5L10,0L0,5"); 

    this.path = this.svg.append("g").selectAll("path") 
     .data(this.force.links()) 
     .enter().append("path") 
     .attr("class", function (d) { return "link " + d.type; }) 
     .attr("marker-end", function (d) { return "url(#" + d.type + ")"; }); 

    this.circle = this.svg.append("g").selectAll("circle") 
     .data(this.force.nodes()) 
     .enter().append("circle") 
     .attr("r", 6) 
     .call(this.force.drag); 

    this.text = this.svg.append("g").selectAll("text") 
     .data(this.force.nodes()) 
     .enter().append("text") 
     .attr("x", 8) 
     .attr("y", ".31em") 
     .text(function (d) { return d.name; }); 
    } 
    tick() { 
    this.path.attr("d", this.linkArc); 
    this.circle.attr("transform", this.transform); 
    this.text.attr("transform", this.transform); 
    } 

    linkArc(d) { 
    var dx = d.target.x - d.source.x, 
     dy = d.target.y - d.source.y, 
     dr = Math.sqrt(dx * dx + dy * dy); 
    return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; 
    } 

    transform(d) { 
    return "translate(" + d.x + "," + d.y + ")"; 
    } 
} 

Error message

ERROR TypeError: Cannot read property 'attr' of undefined 
at d3_dispatch.VisualComponent.tick (visual.component.ts:124) 
at d3_dispatch.event [as tick] (d3.js:504) 
at Object.force.tick [as c] (d3.js:6307) 
at d3_timer_mark (d3.js:2166) 
at d3_timer_step (d3.js:2147) 
at ZoneDelegate.invokeTask (zone.js:425) 
at Object.onInvokeTask (core.js:4747) 
at ZoneDelegate.invokeTask (zone.js:424) 
at Zone.runTask (zone.js:192) 
at ZoneTask.invokeTask (zone.js:499) 

、それは全く見えません。 Picture of generated graph

たとえば、tick()メソッドでthis.pathをログに記録すると、appendGraph()メソッドで作成されていても未定義です。

答えて

1

これは"setTimeout() inside JavaScript Class using “this”"のバリエーションです。 D3のフォースレイアウトではsetTimeout()を使用して目盛りをスケジューリングし、tick()関数が実際に実行されると間違った範囲になるようにします。

この問題を示すJSFiddleをご覧ください。

上記のリンクされた質問とは対照的に、setTimeout()は独自のコードではなくD3によって呼び出されます。必要なスコープを維持するには別の回避策が必要です。あなたは、実際の目盛りを返すジェネレータとして.tick()を呼び出すために力レイアウトの初期化を修正する必要がこれらの調整のほか

tick() { 
    let self = this;  // close over this 
    return function() { 
    // the function uses self throughout, which still references the instance of your class 
    self.path.attr("d", self.linkArc); 
    self.circle.attr("transform", self.transform); 
    self.text.attr("transform", self.transform); 
    } 
} 

:この場合は、あなたのtick()方法でthisの参照を保持するためにクロージャを使用することができますクラスインスタンスのthisスコープへの参照を保持するハンドラ関数です。

forceLayout() { 
    this.force = d3.layout.force() 
    //...omitted for brevity 
    .on("tick", this.tick()) // Notice the parentheses after tick 
    .start(); 
} 

私はこのJSFiddleで完全に動作するデモを設定します。

関連する問題