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>