Home > Blockchain >  Unable to render d3 chart in table cells
Unable to render d3 chart in table cells

Time:11-30

currently using angular 7 with d3 v7. Trying to render area chart in each cell of table (shown in picture below). But using angular method the rendered svg keeps rendering in a loop. Not sure what im doing wrong here enter image description here

HTML Code

<tr [id]="'row'   '-'   fleet" *ngFor="let fleet of fleetcolumn">
      <td>{{ fleet }}</td>
      <ng-container *ngFor="let station of formattedBaseStations | slice: 1">
        <td style="width: 28em;">
              <div [id]="'demandChartInTable1-'   station   '-'   fleet   '-A'"> {{d3DemandChartIntable(station, fleet, 'A')}} </div>
            </mat-grid-tile>
            <mat-grid-tile class="FOChart">
              <div [id]="'demandChartInTable1-'   station   '-'   fleet   '-B'"> {{d3DemandChartIntable(station, fleet, 'A')}} </div>
            </mat-grid-tile>
          </mat-grid-list>
        </td>
      </ng-container>
    </tr> 

.ts code

    d3DemandChartIntable(station, code, position) {
    // set data
    let temp1 = this.data
      .filter(d => d.baseCode == station && d.code == code && d.position == position)
      .map(d => {
        return {
          date: d3.timeParse('%Y-%m-%d')(d.date),
          hours: d.hours
        };
      });
    const e = document.querySelector('.captainChart');
    // set the dimensions and margins of the graph
    const margin = { top: 0, right: 0, bottom: 1, left: 1 },
      width = 120 - margin.left - margin.right,
      height = 90 - margin.top - margin.bottom;

    // append the svg object to the body of the page
    const svg = d3
      .select(`#demandChartInTable1-${station}-${fleet}-${position}`)
      .append('svg')
      .attr('width', e.clientWidth   margin.left   margin.right)
      .attr('height', e.clientHeight   margin.bottom)
      .append('g')
      .attr('transform', `translate(${margin.left},${margin.top})`);

    const x = d3
      .scaleTime()
      .domain(d3.extent(data, d => d.date))
      .range([0, e.clientWidth]);

    // Y axis
    const y = d3
      .scaleLinear()
      .domain([0, 500])
      .range([e.clientHeight   margin.bottom, 0]);

    // Add the area
    return svg
      .append('path')
      .datum(temp1)
      .attr('fill', '#cce5df')
      .attr('stroke', '#69b3a2')
      .attr('stroke-width', 1.5)
      .attr(
        'd',
        d3
          .area()
          .x(d => x(d.date))
          .y0(y(0))
          .y1(d => y(d.hours))
      );
  }

Above code renders repeated svg in each cell instead of rendering just once

enter image description here

any help would be greatly appreciated

CodePudding user response:

The crux is in the following code:

const svg = d3
      .select(`#demandChartInTable1-${station}-${fleet}-${position}`)
      .append('svg')

It selects the table cell and then appends an SVG element. That means that if an SVG already exists, another one is added next to it. If you want to solve this issue, you can either

  • Select and update the existing SVG and only create one once (for example in ngOnInit or ngAfterViewInit);
  • Delete any existing SVGs and draw a new one, using
const cell = d3.select(`#demandChartInTable1-${station}-${fleet}-${position}`);
cell.remove('*');
const svg = cell.append('svg')
  • Related