Uncaught TypeError: (void 0) is not a function using d3 with angular 7

Uncaught TypeError: (void 0) is not a function using d3 with angular 7

我是 angular 的新手,以前从未使用过 d3。 所以我有两个图表(一个是条形图,另一个是饼形图),它们在 dev 上都可以正常工作。但是一旦我部署,条形图就会抛出该错误并且不会显示,而饼图工作正常。我正在使用 d3 和 angular 7.

    "dependencies": {
    "@angular/animations": "^6.1.10",
    "@angular/cdk": "^7.3.7",
    "@angular/common": "^6.1.0",
    "@angular/compiler": "^6.1.0",
    "@angular/core": "^6.1.0",
    "@angular/forms": "^6.1.0",
    "@angular/http": "^6.1.0",
    "@angular/material": "^7.3.7",
    "@angular/platform-browser": "^6.1.0",
    "@angular/platform-browser-dynamic": "^6.1.0",
    "@angular/pwa": "^0.13.9",
    "@angular/router": "^6.1.0",
    "@angular/service-worker": "^6.1.0",
    "core-js": "^2.6.9",
    "d3": "^5.14.2",
    "hammerjs": "^2.0.8",
    "moment": "^2.24.0",
    "rxjs": "^6.5.2",
    "symbol-observable": "^1.2.0",
    "typescript": "^3.1.1",
    "zone.js": "^0.8.29"
}

这是我的饼图代码:

import { Component, OnInit, OnChanges, ViewChild, ElementRef, Input, ViewEncapsulation, HostListener } from '@angular/core';
import * as d3 from 'd3';

@Component({
  selector: 'pie-chart',
  templateUrl: './pie-chart.component.html',
  styleUrls: ['./pie-chart.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class PieChartComponent implements OnInit {
  @ViewChild('chart') private chartContainer: ElementRef;
  @Input() private data: Array<any>;
  @Input() private xDomain: Array<any>;
  @HostListener('window:resize', ['$event'])
  getScreenSize(event?) {
        this.scrHeight = window.innerHeight;
        this.scrWidth = window.innerWidth;
        // console.log(this.scrHeight, this.scrWidth);
  }
  scrHeight:any = window.innerHeight;
  scrWidth:any = window.innerWidth;

  private margin: any = 15;
  private chart: any;
  private width: number;
  private height: number;
  private xScale: any;
  private yScale: any;
  private colors: any;
  private xAxis: any;
  private yAxis: any;

  private yStep: any;

  constructor() { }

  drawChart(isInit = false) {
    var windowWidth;
    var windowHeigth;
    (Number(this.scrWidth)> 1100) ?  windowWidth = Number(this.scrWidth)/3 :
    (Number(this.scrWidth) < 850) ?  windowWidth = Number(this.scrWidth) - 35 :  windowWidth = 
    Number(this.scrWidth) - 150;
    windowHeigth = windowWidth;
    const margin = this.margin;
    const width = windowWidth;
    const height = windowHeigth;
    const actualWidth = width + (margin * 2);
    const actualHeight = height + margin;

    const radius = Math.min(width, height) / 2;

    const element = this.chartContainer.nativeElement;
    element.innerHTML = "";

    const presvg = d3.select(element).append("svg")
      .attr("width", actualWidth)
      .attr("height", actualHeight)

    const svg = presvg.append("g")
      .attr("transform", `translate(${actualWidth / 2}, ${height / 2})`);

    var color10 = d3.scaleOrdinal(["#6D0800", "#741606", "#7A240C", "#813211", "#884017", "#8F4E1D", "#955D23", "#9C6B29", "#A3792F", "#AA8734", "#B0953A", "#B7A340"]);
    var color5 = d3.scaleOrdinal(["#6D0800", "#79220B", "#863C15", "#925620", "#9E6F2B", "#AB8935", "#B7A340"]);
    var color3 = d3.scaleOrdinal(["#6D0800", "#802F10", "#925620", "#A57C30", "#B7A340"]);

    const pie = d3.pie()
      .value(d => d[1])
      .sort(null);

    const arc = d3.arc()
      .innerRadius(0)
      .outerRadius(radius);

    function arcTween(a) {
      const i = d3.interpolate(this._current, a);
      this._current = i(1);
      return (t) => arc(i(t));
    }

    var data = this.data;

    const path = svg.selectAll("path")
      .data(pie(data));

    path.transition().duration(200).attrTween("d", arcTween);

    path.enter().append("path")
      .attr("fill", (d, i) => color3(i))
      .attr("d", arc)
      .attr("stroke", "black")
      .attr("stroke-width", "1px")
      .each(function (d) { this._current = d; })
      .on('mouseenter', function (actual, i) {
        presvg.append('text')
          .attr('class', 'name')
          .text("Name: " + actual.data[0].name);

        presvg.append('text')
          .attr('class', 'amount')
          .text("Value: " + actual.data[1]);

        var element = d3.select('.amount');
        var element1 = d3.select('.name');

        element.attr('x', 40)
          .attr('y', 20);
        element1.attr('x', 40)
          .attr('y', 40);
      })
      .on('mouseleave', function (actual, i) {
        d3.selectAll('.amount').remove();
        d3.selectAll('.name').remove();
      });;
  }

  ngOnInit() {
    console.log("pie-chart");
    this.drawChart();
  }
}

这是我的条形图:

    import { Component, OnInit, ViewChild, ElementRef, Input, ViewEncapsulation, HostListener } from '@angular/core';
import * as d3 from 'd3';

@Component({
  selector: 'general-chart',
  templateUrl: './general-chart.component.html',
  styleUrls: ['./general-chart.component.css'],
  encapsulation: ViewEncapsulation.None
})
export class GeneralChartComponent implements OnInit {
  @ViewChild('chart') private chartContainer: ElementRef;
  @Input() private data: any;
  @Input() private xDomain: Array<any>;
  @HostListener('window:resize', ['$event'])
  getScreenSize(event?) {
        this.scrHeight = window.innerHeight;
        this.scrWidth = window.innerWidth;
        // console.log(this.scrHeight, this.scrWidth);
  }
  scrHeight:any = window.innerHeight;
  scrWidth:any = window.innerWidth;

  private margin: any = 20;
  // private xDomain: any = [];
  private xDomainFilter: any = [];
  private chartData: any = [];
  private chart: any;
  private width: number;
  private height: number;
  private xScale: any;
  private yScale: any;
  private colors: any;
  private xAxis: any;
  private yAxis: any;

  private yStep: any;

  private xAxisMax: any;
  private yAxisMax: any;
  private yAxisLimit: any;

  private isWithGrid: boolean = true;
  private isSelectedYRange: boolean = true;

  private yLabel: string = "";
  private xLabel: string = "";


  constructor() { }



  drawChart(isInit = false) {
    this.yLabel = this.data.yName;
    this.xLabel = this.data.xName;
    //-------------------------------------------------------------
    //setting up field
    const margin = this.margin;
    var elementWidth;
    (Number(this.scrWidth)> 1100) ?  elementWidth = Number(this.scrWidth)/2.5 :
    (Number(this.scrWidth) < 850) ?  elementWidth = Number(this.scrWidth) - 35 :  elementWidth = Number(this.scrWidth) - 150;
    // const elementWidth = Number(this.scrWidth)/2;
    const elementHeight = 450;
    const width = elementWidth - 10;
    var height = elementHeight - 10 - margin;

    if (this.data.applyRotation) {
      height = elementHeight - 10 - margin * 2;
    }

    const element = this.chartContainer.nativeElement;
    element.innerHTML = "";

    this.yAxisMax = d3.max(this.chartData, d => d[1]) + 1;
    this.yAxisLimit = d3.max(this.chartData, d => d[1]) + 1;


    const svg = d3.select(element).append('svg')
      .attr('width', elementWidth+50)
      .attr('height', elementHeight+100);
    
    var scaleVal = this.margin + 25;

    const chart = svg.append('g')
      .attr('transform', `translate(${scaleVal}, 15)`);
    //-------------------------------------------------------------



    //-------------------------------------------------------------
    //y axis setup

    var yDomain;
    if (this.isSelectedYRange) {
      //use if want to choose from selected: 
      yDomain = [0, this.yAxisMax];
    } else {
      //use if want to choose from max VALUE: 
      yDomain = [0, d3.max(this.chartData, d => d[1]) + 1];
    }

    const yScale = d3.scaleLinear()
      .range([height, 0]) //axis unit setup on the DOM size
      .domain(yDomain); //applying domain set before based on data

    //graph without grid
    chart.append('g')
      .attr('class', 'initial-axis')
      .call(d3.axisLeft(yScale)); //appending axis based on created function

    if (this.isWithGrid) {
      //graph with grid
      chart.append('g')
        .attr('class', 'grid')
        .call(d3.axisLeft()
          .scale(yScale)
          .tickSize(-width)
          .tickFormat(''))
    }
    //-------------------------------------------------------------



    //-------------------------------------------------------------
    //x axis setup
    //use for columns names

    const xScale = d3.scaleBand() //scale type for names
      .range([0, width]) //axis unit setup on the DOM size
      .domain(this.xDomain) //applying domain set before based on data
      .padding(0.2) //set padding 

    if (this.data.applyRotation) {
      chart.append('g')
        .attr('class', 'initial-axis')
        .attr('transform', `translate(0, ${height})`) //apped axis to the position based on parent element height
        .call(d3.axisBottom(xScale))
        .selectAll("text")
        .style("text-anchor", "end")
        .attr("dx", "0.2em")
        .attr("dy", "0.80em")
        .attr("transform", "rotate(-35)"); //apped axis point by function based on data above
    } else {
      chart.append('g')
        .attr('class', 'initial-axis')
        .attr('transform', `translate(0, ${height})`) //apped axis to the position based on parent element height
        .call(d3.axisBottom(xScale))
    }

    if (this.isWithGrid) {
      //graph with grid
      chart.append('g')
        .attr('class', 'grid')
        .attr('transform', `translate(0, ${height})`)
        .call(d3.axisBottom()
          .scale(xScale)
          .tickSize(-height, 0, 0)
          .tickFormat(''))
    }
    //-------------------------------------------------------------



    //-------------------------------------------------------------
    //bars setup
    this.colors = d3.scaleLinear().domain([0, this.chartData.length]).range(<any[]>['#6d0800', '#b7a340']); //setting color range for bars

    var bars = chart
      .selectAll()
      .data(this.chartData) //source of data
      .enter();

    bars //entering data for a check
      .append('rect') //appending svg element
      .attr('class', 'bar')
      .attr('x', (d) => xScale(d[0].name)) //binding x on our x axis
      .attr('y', (d) => yScale([d[1]])) //binding y on our y axis
      .attr('height', (d) => height - yScale(d[1])) //setting height of an element by calculating it from element height and binded data from y axis
      .attr('width', xScale.bandwidth())
      .attr('opacity', 1)
      .style('fill', (d, i) => this.colors(i))
      .on('mouseenter', function (actual, i) {
        d3.select(this)
          .transition()
          .duration(300)
          .attr('opacity', 0.6)
          .attr('x', (d) => xScale(d[0].name) - 5)
          .attr('width', xScale.bandwidth() + 10);

        const y = yScale(actual[1]) + 1;

        chart.append('text')
          .attr('class', 'amount')
          .text("Value: " + actual[1]);

        var element = d3.select('.amount');
        var val = d3.select('.amount').node();
        var dim = val.getBoundingClientRect();

        element.attr('x', width - dim.width - 20)
          .attr('y', 30);
      })
      .on('mouseleave', function (actual, i) {
        d3.select(this)
          .transition()
          .duration(300)
          .attr('opacity', 1)
          .attr('x', (d) => xScale(d[0].name))
          .attr('width', xScale.bandwidth());

        d3.selectAll('.amount').remove();
      });
    //-------------------------------------------------------------
  }

  checkIsInFilter(val, index) {
    this.xDomain = [];
    this.chartData = [];
    for (var i = 0; i < this.xDomainFilter.length; i++) {
      if ((this.xDomainFilter[i].isApplied && i != index) || (i == index && !val)) {
        this.xDomain.push(this.xDomainFilter[i].name);
        this.chartData.push(this.data.chartData[i]);
      }
    }

    this.drawChart();
  }

  ngOnInit() {
    console.log("General-chart");
    this.xDomain = this.data.chartData.map(d => d[0].name);

    for (var i = 0; i < this.xDomain.length; i++) {
      this.xDomainFilter.push({
        name: this.xDomain[i],
        isApplied: true
      })
    }

    for (var i = 0; i < this.data.chartData.length; i++) {
      this.chartData.push(this.data.chartData[i]);
    }

    this.drawChart();
    document.getElementById("chart-block-0").getElementsByClassName("charts-btn")[0].setAttribute('style', 'background-color: #8b0d04; color: beige');
  
  }
}

Error with barChart

Working PieChart

有人可以帮忙吗?

对于遇到相同问题的任何人,问题是 angular 构建优化器删除了太多代码(缩小),这就是我收到该错误的原因。我仍在努力寻找更好的解决方案,但现在,我可以关闭构建优化器 ng build --prod --build-optimizer=false 它运行得很好!