chart and window in an Angular app not resizing

Viewed 59

My code draws an adjustable donut chart in an Angular project.

I, then, added a window resize event listener and handler, assuming that re-drawing and re-painting are all I need to do:

import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { Item, DataService } from '../data.service';
import * as d3 from 'd3';

@Component({
  selector: 'app-donut',
  templateUrl: './donut.component.html',
  styleUrls: ['./donut.component.css'],
})
export class DonutComponent implements OnInit {

  svg: d3.Selection<SVGGElement, unknown, HTMLElement, any>;

  margin = 50;
  width = 750 - (this.margin * 2);
  height = 400 - (this.margin * 2);

  arc: any;
  pie: any;
  slices: any;
  color: any;
  radius: number;
  mainContainer: any;
  dataSource: Item[];

  constructor(private dataService: DataService) { this.dataSource = this.dataService.getData(); }

  ngOnInit() {
    this.createSvg();
  }

  createSvg(): void {
    this.svg = d3
      .select("figure#donut")
      .append("svg")
      .attr("width", this.width + (this.margin * 2))
      .attr("height", this.height + (this.margin * 2))
      .append("g")
      .attr("transform", "translate(" + this.margin + "," + this.margin + ")");

    this.pie = d3.pie().sort(null).value((d: any) => d.abs);
    this.radius = (Math.min(this.width, this.height)) / 1.8;
    this.color = d3.scaleOrdinal(d3.schemeCategory10);

    this.mainContainer = this.svg
      .append('g')
      .attr('transform', `translate(${this.radius},${this.radius})`);
  }

  drawBars() {
    this.setArcs();
    this.drawSlices();
  }

  setArcs() {
    // innerRadius(0) draws a pie chart; i.e. a donut chart without a hole!
    this.arc = d3.arc().outerRadius(this.radius).innerRadius(this.radius * 0.5);
  }

  drawSlices() {
    this.slices = this.mainContainer
      .selectAll('path')
      .remove().exit()
      .data(this.pie(this.dataSource))
      .enter().append('g').append('path')
      .attr('d', this.arc);

    this.slices
      .attr('fill', (d, i) => this.color(i));
  }

  resize() {
    this.createSvg();
    this.drawBars();
  }
}

This is the content of my DataService script:

import { Injectable } from '@angular/core';

export interface Item {
  name: string;
  value: number;
  abs: number;
}

@Injectable({
  providedIn: 'root'
})
export class DataService {

  private readonly NAMES = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];

  private readonly MIN_ITEM = 10;
  private readonly MAX_ITEM = 20;

  private readonly MAX_VALUE = 100;

  constructor() { }

  private generateRandomValue(start: number, end: number) {

    return Math.ceil(Math.random() * (end - start) + start);
  }

  getData(): Item[] {

    const nbItems = this.generateRandomValue(this.MIN_ITEM, this.MAX_ITEM);
    const samples = [];
    
    for (let i = 0; i < nbItems; i++) {
      const val = this.generateRandomValue(1, this.MAX_VALUE);
      samples.push({
        name: this.NAMES[i],
        value: val,
        abs: Math.abs(val)
      });
    }

    return samples;
  }
}

My CSS script:

.center {
    display: flex;
    justify-content: center;
}

My HTML script:

<h3 class="center">Donut Chart</h3>

<figure id="donut" class="center"></figure>

The only problem I am having is that the resize function does not work. As soon as I start dragging the edges, the chart breaks up and multiplies fast, until it disappears...

What am I doing wrong?

0 Answers
Related