在Angular Project中,D3属性X和属性Y不存在于[number,number]类型中

时间:2018-04-23 12:49:11

标签: angular d3.js

我有一个简单的线条图,我在D3中做过

https://jsfiddle.net/goanhefy/

我试图将此图表集成到Angular项目中,并让应用程序组件管理数据。我实际上是在Angular中重新创建它并在线发布

https://stackblitz.com/edit/angular-irjxus?file=app%2FShared%2Fline-graph%2Fline-graph.component.css

问题在于我在角度CLI中看到错误

  

src / app / shared / line-graph / line-graph.component.ts(84,40)中的错误:   错误TS2339:属性' x'类型' [数字,数字]'上不存在。   src / app / shared / line-graph / line-graph.component.ts(85,40):错误   TS2339:财产' y'类型' [数字,数字]'。

上不存在

enter image description here 虽然我的项目仍在运行,但我想知道造成这个问题的原因。

这是我的完整线图打字稿

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() {

  }

}

这是我的应用程序组件

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);
  }
}

1 个答案:

答案 0 :(得分:0)

如果您查看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的{​​{1}}类型,但是你没有告诉它那是什么类型是,因此它会抱怨它不知道对象x上的属性x。由于你没有告诉它期望什么类型,它假定具有类型(a.k.a。d元组类型)的方法的重载。

有两种方法可以让转换时间错误消息消失:

解决方案1 ​​:快速解决方法是将方法调用更新为:[number, number]。然后,您告诉Typescript您传递的d对象是any类型,因此无论您尝试访问它的属性如何,它都不会抱怨。

解决方案2 :尽管使用Typescript帮助您,但更合适的解决方法。为图形将显示的对象类型创建一个接口。在您的实例中,看起来您正在传递具有.x( (d: any) => xScale(d.x))x属性的对象,因此:

y

然后将方法调用更新为interface IGraphDatum { x: number; y: number; }

代码继续工作的原因是您的对象实际上具有.x( (d: IGraphDatum) => xScale(d.x))x属性,因此转换后的JavaScript执行时没有错误,但是转换器正在抛出错误没有给它足够的信息来强制这两个属性都在传递的对象上。