2017-03-19 16 views
0

Ionic2アプリ内の1ページに2つ(またはそれ以上)の類似グラフを表示しようとしています。私はAng3のd3型をラップするのにd3-ng2-serviceを使います。私の問題は次のとおりです。それぞれのカスタム要素内に2つの異なるdiv要素に2つのグラフを配置しようとすると、両方のグラフが失敗します。ページの最初のdivを選択すると、2番目のグラフが最初のグラフを上書きしますが、描画されます。1つのIonic2ページ内に2つのd3折れ線グラフを配置しようとしています

グラフを1つのグラフに配置するという巧妙な方法はありますか?例は、いつも私があまりにもやろうものを、外容器にある一意のIDを与える:

import { Component, Input, OnInit, ElementRef } from '@angular/core'; 

import { D3Service, D3, Selection, ScaleLinear, ScaleTime, Axis, Line } from 'd3-ng2-service'; // <-- import the D3 Service, the type alias for the d3 variable and the Selection interface 


@Component({ 
    selector: 'd3-test-app', 
    templateUrl: 'd3-test-app.html', 
    providers: [D3Service], 
}) 

export class D3TestAppComponent { 
    //Time is on x-axis, value is on y-axis 
    @Input('timeSeries') timeSeries: Array<{isoDate: string | Date | number | {valueOf(): number}, value: number}>; 
    @Input('ref') ref: string; 
    /* the size input defines, how the component is drawn */ 
    @Input('size') size: string; 


    private d3: D3; 

    private margin: {top: number, right: number, bottom: number, left: number}; 
    private width: number; 
    private height: number; 
    private d3ParentElement: Selection<any, any, any, any>; // <-- Use the Selection interface (very basic here for illustration only) 



    constructor(element: ElementRef, 
       d3Service: D3Service) { // <-- pass the D3 Service into the constructor 
       this.d3 = d3Service.getD3(); // <-- obtain the d3 object from the D3 Service 
       this.d3ParentElement = element.nativeElement; 
    } 

    ngOnInit() { 
    let x: ScaleTime<number, number>; 
    let y: ScaleLinear<number, number>; 

    let minDate: number; 
    let maxDate: number; 

    let minValue: number = 0; 
    let maxValue: number; 

    // set the dimensions and margins of the graph 
    switch (this.size) { 
     case "large": 
     this.margin = {top: 20, right: 20, bottom: 30, left: 50}; 
     this.width = 640 - this.margin.left - this.margin.right; 
     this.height = 480 - this.margin.top - this.margin.bottom; 
     break; 
     case "medium": 
      this.margin = {top: 20, right: 0, bottom: 20, left: 20}; 
      //golden ratio 
      this.width = 420 - this.margin.left - this.margin.right; 
      this.height = 260 - this.margin.top - this.margin.bottom; 
      break; 
     case "small": 
     this.margin = {top: 2, right: 2, bottom: 3, left: 5}; 
     this.width = 120 - this.margin.left - this.margin.right; 
     this.height = 80 - this.margin.top - this.margin.bottom; 
     break; 
     default: 
     this.margin = {top: 20, right: 20, bottom: 30, left: 50}; 
     this.width = 640 - this.margin.left - this.margin.right; 
     this.height = 480 - this.margin.top - this.margin.bottom; 
    } 


    // ... 
    if (this.d3ParentElement !== null) { 
     let d3 = this.d3; // <-- for convenience use a block scope variable 

     //THIS FAILS... 
     let selector: string = '#' + this.ref + ' .graphContainer'; 
     console.log(selector); 

     let svg = d3.select(selector).append("svg") 
     .attr("width", this.width + this.margin.left + this.margin.right) 
     .attr("height", this.height + this.margin.top + this.margin.bottom) 
     .append("g") 
     .attr("transform", 
      "translate(" + this.margin.left + "," + this.margin.top + ")"); 


      this.timeSeries.forEach((d) => { 

      d.isoDate = +d3.isoParse(d.isoDate as string); 
      d.value = +d.value; 
      if (minDate == null || minDate >= d.isoDate) { 
       minDate = d.isoDate as number; 
      } 
      if (maxDate == null || maxDate <= d.isoDate) { 
       maxDate = d.isoDate as number; 
      } 
      // if (minValue == null || minValue >= d.value) { 
      // minValue = d.value as number; 
      // } 
      if (maxValue == null || maxValue <= d.value) { 
       maxValue = d.value as number; 
      } 
      }); 

     // TODO magic numbers to real min max 
     x = d3.scaleTime().domain([minDate, maxDate]).range([0,this.width]); 
     y = d3.scaleLinear().domain([0, maxValue]).range([this.height, 0]); 

     let xAxis: Axis<number | Date | {valueOf() : number;}> = d3.axisBottom(x); 
     let yAxis: Axis<number | {valueOf(): number;}> = d3.axisLeft(y); 

     let valueLine: Line<{isoDate: number; value: number}> = d3.line<{ isoDate: number; value: number }>() 
     .x(function (d) { return x(d.isoDate)}) 
     .y(function (d) { return y(d.value)}); 


     // Add the valueline path. 
     svg.append("path") 
     .data([this.timeSeries as {isoDate: number, value: number}[]]) 
     .attr("class", "line") 
     .attr("d", valueLine); 

     svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + this.height + ")") 
     .call(xAxis) 

     svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis) 

    } 
    } 

    myParser() : (string) => Date { 
    return this.d3.utcParse("%Y-%m-%dT%H:%M:%S.%LZ"); 
    } 
} 

HTML:

<div class='graphContainer'> 
</div> 

HTMLファイルカスタムコンポーネントが使用されます。

<ion-header> 
    <ion-navbar #dashboardNav> 
    <ion-title>Dashboard</ion-title> 
    <button ion-button menuToggle="favMenu" right> 
     <ion-icon name="menu"></ion-icon> 
    </button> 
    </ion-navbar> 
</ion-header> 

<ion-content> 
    <ion-item *ngFor="let entry of dashboard"> 
    {{ entry.name }} 
    <d3-test-app [id]='entry.name' [timeSeries]='entry.timeSeries' [ref]='entry.name' size='medium'></d3-test-app> 
    </ion-item> 
</ion-content> 

答えて

0

スタックトレースが表示されずにデバッグするのは難しいですが、要素の選択方法が原因で失敗しているようです。私はその仮定に基づいて私の答えに基づいていきます。

IDによる照会は、特定の要素のDOMを調べなければならない場合や、そのIDを持つ要素が1つしかないと確信できる場合に便利です。あなたが必要とする参照を既に持っているAngular要素の中にいるので、要素自体であり、ID参照を動的に作成する必要はありません。

私はng2の専門家ではありませんが、どのようにしてを見て、フレームワークに最適な方法を選択してください。あなたがthe example shown on this answerのようなもののために行くと言う:

constructor(public element: ElementRef) { 
    this.element.nativeElement // <- your direct element reference 
    } 

NB - これを達成するための様々な方法があるように、これは最高/正しいものであるかわからない...見えますが、目標は、とにかく参照を取得すること

です

それから、既に生の参照を渡すことによって、D3 dslでそれを選択するだけです。

// At this point this.element.nativeElement 
// should contain the raw element reference 
    if (this.d3ParentElement !== null) { 
     const { d3, element } = this; // <-- for convenience use block scope variables 

     const svg = d3.select(element.nativeElement).append("svg")...