我正在尝试转换示例component
使用可观察对象通过HTTP传输STOCKS
数组。
我已将lineChartComponent
中的代码修改为:
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import * as d3 from 'd3-selection';
import * as d3Scale from 'd3-scale';
import * as d3Shape from 'd3-shape';
import * as d3Array from 'd3-array';
import * as d3Axis from 'd3-axis';
import { STOCKS } from '../shared';
import { Stock } from '../stock';
import { GraphService } from '../graph.service';
@Component({
selector: 'app-line-chart',
encapsulation: ViewEncapsulation.None,
templateUrl: './line-chart.component.html',
styleUrls: ['./line-chart.component.css']
})
export class LineChartComponent implements OnInit {
title = 'Line Chart';
stocks: Stock[];
private margin = { top: 20, right: 20, bottom: 30, left: 50 };
private width: number;
private height: number;
private x: any;
private y: any;
private svg: any;
private line: d3Shape.Line<[number, number]>;
constructor(private graphService: GraphService) {
this.width = 900 - this.margin.left - this.margin.right;
this.height = 500 - this.margin.top - this.margin.bottom;
}
ngOnInit() {
this.getStocks();
this.initSvg();
this.initAxis();
this.drawAxis();
this.drawLine();
}
getStocks(): void {
this.graphService.getStocks()
.subscribe(stocks => this.stocks = stocks);
}
private initSvg() {
this.svg = d3.select('svg')
.append('g')
.attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');
}
private initAxis() {
this.x = d3Scale.scaleTime().range([0, this.width]);
this.y = d3Scale.scaleLinear().range([this.height, 0]);
this.x.domain(d3Array.extent(this.stocks, (d) => d.date));
this.y.domain(d3Array.extent(this.stocks, (d) => d.value));
}
private drawAxis() {
this.svg.append('g')
.attr('class', 'axis axis--x')
.attr('transform', 'translate(0,' + this.height + ')')
.call(d3Axis.axisBottom(this.x));
this.svg.append('g')
.attr('class', 'axis axis--y')
.call(d3Axis.axisLeft(this.y))
.append('text')
.attr('class', 'axis-title')
.attr('transform', 'rotate(-90)')
.attr('y', 6)
.attr('dy', '.71em')
.style('text-anchor', 'end')
.text('Price ($)');
}
private drawLine() {
this.line = d3Shape.line()
.x((d: any) => this.x(d.date))
.y((d: any) => this.y(d.value));
this.svg.append('path')
.datum(this.stocks)
.attr('class', 'line')
.attr('d', this.line);
}
}
graphService
在哪里
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { LineChartComponent } from './graph/line-chart.component';
//import { STOCKS } from './shared';
import { Stock } from './stock';
import { MessageService } from './message.service';
import { HttpClient, HttpHeaders } from '@angular/common/http';
@Injectable({providedIn: 'root'})
export class GraphService {
private stocksUrl = 'api/stocks';
constructor(
private http: HttpClient,
private messageService: MessageService) { }
getStocks(): Observable<Stock[]> {
// TODO: send the message _after_ fetching the heroes
this.messageService.add('GraphService: fetched graph data');
return this.http.get<Stock[]>(this.stocksUrl);
//return of(STOCKS);
}
}
并且stock
是
export class Stock {
date: Date;
value: number;
}
我正在使用ImMemoryDBService
模拟HTTP服务器端
import { InMemoryDbService } from 'angular-in-memory-web-api';
//import { Stock } from './stock';
export class InMemoryDataService implements InMemoryDbService {
createDb() {
const stocks = [
{date: new Date('2010-01-01'), value: 210.73},
{date: new Date('2010-01-04'), value: 214.01},
{date: new Date('2010-01-05'), value: 214.38},
{date: new Date('2010-01-06'), value: 210.97},
.....
如果我将GraphService
更改为
return of(STOCKS)
它工作正常,图形绘制正确。
似乎在
失败this.x.domain(d3Array.extent(this.stocks, (d) => d.date));
with TypeError:无法读取未定义的属性“ length”
我想知道是否是因为IMPORTS中的数据被定义为常量。
答案 0 :(得分:0)
这个问题有两个方面。首先,图形需要等待可观察到的返回数据。其次,通过http返回的日期数据将作为字符串返回,并且需要转换为日期格式:
getStocks(): void {
this.graphService.getStocks()
.subscribe(stocks => {
this.stocks = stocks
for (let i in stocks) stocks[i].date = new Date(stocks[i].date);
console.log(stocks);
this.initAxis();
this.drawAxis();
this.drawLine();
});