Trying to create a basic line graph using d3 in Angular 2 typescript. Below is the code snippet:
import { Component, ViewChild, ElementRef, Input, OnInit } from '@angular/core';
import * as d3 from 'd3';
@Component({
selector: 'my-app',
template: `<h1>Hello {{name}}</h1><div class="chart" #chart></div>`,
})
export class AppComponent implements OnInit {
@ViewChild('chart') private chartContainer: ElementRef;
@Input() private data: Array<any>;
private margin: any = { top: 20, bottom: 20, left: 20, right: 20};
private chart: any;
private width: number;
private height: number;
private xScale: any;
private yScale: any;
private colors: any;
private xAxis: any;
private yAxis: any;
name = 'Angular';
ngOnInit() {
this.generateData();
this.createChart();
if (this.data) {
this.updateChart();
}
}
Random data generation:
generateData() {
this.data = [];
for (let i = 0; i < (8 + Math.floor(Math.random() * 10)); i++) {
this.data.push([
`Index ${i}`,
Math.floor(Math.random() * 100)
]);
}
}
X and Y axis creation:
createChart() {
let element = this.chartContainer.nativeElement;
let svg = d3.select(element).append('svg');
svg.attr('width', element.offsetWidth)
.attr('height', element.offsetHeight);
this.width = this.chartContainer.nativeElement.offsetWidth -
this.margin.left - this.margin.right;
this.height = this.chartContainer.nativeElement.offsetHeight -
this.margin.top - this.margin.bottom;
// plot area settings
this.chart = svg;
// defining X & Y domains
let xDomain = this.data.map(d => d[0]);
let yDomain = [0, d3.max(this.data, (d: any) => {return d[1]})];
// creating scales
this.xScale = d3.scaleBand().padding(0.1).domain(xDomain).rangeRound([0, this.width]);
this.yScale = d3.scaleLinear().domain(yDomain).range([this.height, 0]);
// bar color scale
this.colors = d3.scaleLinear().domain([0, this.data.length]).range(<any[]>['red', 'blue']);
// setting up x & y axis
this.xAxis = svg.append('g')
.attr('class', 'axis axis-x')
.attr('transform', `translate(${this.margin.left}, ${this.margin.top + this.height})`)
.call(d3.axisBottom(this.xScale));
this.yAxis = svg.append('g')
.attr('class', 'axis axis-y')
.attr('transform', `translate(${this.margin.left}, ${this.margin.top})`)
.call(d3.axisLeft(this.yScale));
}
Adding plots to the graph:
updateChart() {
this.chart = this.chart.append('g')
.attr('class', 'dots')
.attr('transform', `translate(${this.margin.left}, ${this.margin.top})`);
this.xScale.domain(this.data.map(d => d[0]));
this.yScale.domain([0, d3.max(this.data, (d:any) => {return d[1]})]);
this.colors.domain([0, this.data.length]);
this.xAxis.transition().call(d3.axisBottom(this.xScale));
this.yAxis.transition().call(d3.axisLeft(this.yScale));
let update = this.chart.selectAll('.dot')
.data(this.data);
update.exit().remove();
update
.enter()
.append('circle')
.attr('class', 'dot')
.attr('cx', (d : any) => {return this.xScale(d[0])})
.attr('cy', (d:any) =>{return this.yScale(d[1])})
.style('fill', (d:any, i:any) => { console.log(d); return this.colors(i)});
}
If 'rect' elements are placed instead of 'circle' with specific dimensions, they appear correctly on the UI. There seems to be an issue with styling or missing elements for 'circle'. Looking for suggestions or fixes.