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
它运行得很好!
我是 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
它运行得很好!