I am new on angular and never use d3 before. So I have two charts (one is bar type and the other is pie type), they both work fine on dev. But once I deploy, the bar chart throws that error and does not show while the pie chart works just fine. I am using d3 along with 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"
}
Here is my pieChart code:
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();
}
}
and here is my barchart:
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
Can anyone help?
To anyone having the same issue, the problem is that angular build optimizer is removing too much code (minifying) and that is why I was getting that error. I am still trying to find a better solution but for now, I can just turn Off the build optimizer ng build --prod --build-optimizer=false
and it runs just fine!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With