我有一个在 D3 中制作的简单折线图
https://jsfiddle.net/goanhefy/
我正在尝试将此图表集成到 Angular 项目中,并由应用程序组件管理数据。我实际上已经在 Angular 中重新创建了它并将其发布到网上
https://stackblitz.com/edit/angular-irjxus?file=app%2FShared%2Fline-graph%2Fline-graph.component.css
问题是我在 Angular CLI 中看到错误
src/app/shared/line-graph/line-graph.component.ts(84,40) 中的错误:错误 TS2339:类型“[number,number]”上不存在属性“x”。src/app/shared/line-graph/line-graph.component.ts(85,40):错误 TS2339:类型“[number,number]”上不存在属性“y”。
这是我的全线图打字稿
import { Component, OnInit, OnChanges, ViewChild, ElementRef, Input, ViewEncapsulation } from '@angular/core';
import * as d3 from 'd3';
@Component({
selector: 'app-line-graph',
templateUrl: './line-graph.component.html',
styleUrls: ['./line-graph.component.css'],
encapsulation: ViewEncapsulation.None
})
export class LineGraphComponent implements OnInit, OnChanges {
@ViewChild('line') private lineContainer: ElementRef;
@Input() private lineData: Array<any>;
private margin: any = 25;
private chart: any;
private width = 500;
private height = 500;
private xScale: any;
private yScale: any;
private colors: any;
private xAxis: any;
private yAxis: any;
private axisLength: any = this.width - 2 * this.margin;
constructor() { }
ngOnInit() {
console.log(this.lineData);
this.createChart();
if (this.lineData) {
this.updateChart();
}
}
ngOnChanges() {
if (this.chart) {
this.updateChart();
}
}
createChart() {
/*
const data: Array<any> = [
{x: 0, y: 4},
{x: 1, y: 9},
{x: 2, y: 6},
{x: 4, y: 5},
{x: 6, y: 7},
{x: 7, y: 3},
{x: 9, y: 2}
];*/
const element = this.lineContainer.nativeElement;
const svg = d3.select(element).append('svg')
.attr('width', this.width)
.attr('height', this.height)
.style('border', '1px solid');
// Create Scales
const xScale = d3.scaleLinear()
.domain([0, 10])
.range([0, this.axisLength]);
const yScale = d3.scaleLinear()
.domain([0, 10])
.range([0, this.axisLength]);
// Create axis
this.xAxis = d3.axisBottom(xScale);
this.yAxis = d3.axisLeft(yScale);
svg.append('g')
.classed('x-axis', true)
.attr('transform', () => 'translate(' + this.margin + ',' + (this.height - this.margin) + ')')
.call(this.xAxis);
svg.append('g')
.classed('y-axis', true)
.attr('transform', () => 'translate(' + this.margin + ',' + this.margin + ')')
.call(this.yAxis);
const line = d3.line()
.x( (d) => xScale(d.x))
.y( (d) => yScale(d.y));
svg.append('path')
.attr('d', line(this.lineData))
.attr('fill', 'none')
.attr('stroke', 'red')
.attr('transform', () => 'translate(' + this.margin + ',' + this.margin + ')');
}
updateChart() {
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的应用程序组件
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
private chartData: Array<any>;
private lineData: Array<object>;
ngOnInit() {
this.lineData = [
{x: 0, y: 4},
{x: 1, y: 9},
{x: 2, y: 6},
{x: 4, y: 5},
{x: 6, y: 7},
{x: 7, y: 3},
{x: 9, y: 2}
];
console.log(this.lineData, 'Hello from app component');
// give everything a chance to load before starting animation
setTimeout(() => {
this.generateData();
// change data periodically
setInterval(() => this.generateData(), 10000);
}, 1000);
}
generateData() {
this.chartData = [];
for (let i = 0; i < (8 + Math.floor(Math.random() * 10)); i++) {
this.chartData.push([
`Index ${i}`,
Math.floor(Math.random() * 100)
]);
}
//console.log(this.chartData);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您查看 d3 的类型文件及其line
提供的函数,您将看到它有两个重载:export function line(): Line<[number, number]>;
和export function line<Datum>(): Line<Datum>;
。
该Line<Datum>
接口又为该x
方法声明了三个重载:x(): (d: Datum, index: number, data: Datum[]) => number;
、x(x: number): this;
和x(x: (d: Datum, index: number, data: Datum[]) => number): this;
。虽然命名使这有点令人困惑,Datum
但实际上只是一种泛型类型(通常以T
其他语言表示),因此上述两种方法都返回实现此接口的对象,一个具有您为其声明的类型,另一个具有您声明的类型一个元组。
引用的类型位于目录index.d.ts
中的文件中@types/d3-shape
。
当您按如下方式调用方法时:.x( (d) => xScale(d.x))
. Typescript 会查看它并知道你的d
变量应该是Datum
应该传递到方法中的类型x
,但是你没有告诉它该类型是什么,所以它会抱怨它不知道x
你的对象的属性d
。由于您没有告诉它期望什么类型,它假定具有类型(也称为元组类型)的方法的重载[number, number]
。
有两种方法可以消除转译时间错误消息:
解决方案 1:快速修复方法是将您的方法调用更新为:.x( (d: any) => xScale(d.x))
。然后,您告诉 Typescript 您传递的 d 对象是 any 类型,因此无论您尝试访问它的属性是什么,它都不会抱怨。
解决方案 2:更正确的解决方案是利用 Typescript 来帮助您。为图表将显示的对象类型创建一个界面。在您的实例中,看起来您正在传递带有x
和y
属性的对象,因此:
interface IGraphDatum {
x: number;
y: number;
}
Run Code Online (Sandbox Code Playgroud)
然后将您的方法调用更新为.x( (d: IGraphDatum) => xScale(d.x))
.
代码继续工作的原因是你的对象实际上具有 和x
属性y
,因此转译后的 JavaScript 执行时没有错误,但转译器会抛出错误,因为你没有给它足够的信息来强制执行这两个操作属性将位于传递的对象上。