I have customised a donut chart for displaying with a grid layout. The grid has 3 different cards of same height in one row. But when i change the svg size manually from within the d3 component, the child component in the grid overflows the grid-area I have specified for it, which is manageable at bigger screen sizes. But on laptop screens the edges of the svg get cut off as the edges are outside the boundaries of the grid view port.
I want the graph to scale down/up depending on how much of the grid viewport is available. I have also added the attribute preserveAspectRatio to the svg but that is not very helpful as the component width is too much.
Expected Grid behaviour:

When the screen width is reduced even a little bit:

How do I make the d3 graph fit responsively within the grid?
EDIT: the code used;
grid.component.html
<div class="grid-container">
<!-- Grid 1 -->
<mat-card class="card">
<mat-card-title-group>
<mat-card-title>
<div class="bold-font font-size-16 ml-15">Grid 1</div>
</mat-card-title>
</mat-card-title-group>
<mat-card-content class="card-grid">
<app-d3-donut class="card-grid-graph"></app-d3-donut>
</mat-card-content>
</mat-card>
</div>
grid-component.scss
.card-grid {
display: grid;
grid-template-columns: repeat(6, 0.5fr);
grid-template-rows: repeat(8, 1fr);
height: calc(100% - 40px);
}
.card-grid-graph {
grid-area: 3 / 1 / 5 / 7;
justify-self: center;
align-self: center;
}
The component I am using is app-d3-donut to render the donut graphs in the card.
d3-donut.component.html
<div #donut></div>
d3-donut.component.scss
div{
width: 300px;
position: relative;
zoom: 140%;
}
d3-donut.component.ts
import { AfterViewInit, Component, ElementRef, Input, OnChanges, OnInit, ViewChild } from '@angular/core';
import { D3Service } from '../services/d3.service';
@Component({
selector: 'app-d3-donut',
templateUrl: './d3-donut.component.html',
styleUrls: ['./d3-donut.component.scss']
})
export class D3DonutComponent implements AfterViewInit{
@Input('data') private data: SimpleDataModel[] = [
{ name: "Test String 1 25%", value: '25', color: '#254C66' },
{ name: `Test string 2 75%`, value: '75', color: '#49A0CC' },
];
legend: any;
private svg: any;
private colors: any;
@ViewChild('donut') figureElement: ElementRef;
private d3: any;
private margin = { top: 10, right: 0, bottom: 30, left: 0 };
private width = 700;
private height = 600;
private radius = Math.min(this.width, this.height) / 2 - this.margin.left;
graphGroup: any;
constructor(private d3Service: D3Service) {
this.d3 = d3Service.d3;
}
ngAfterViewInit(): void {
this.createSvg();
this.createColors(this.data);
this.createLegend();
this.drawChart();
}
private createSvg(): void {
this.d3
.select(this.figureElement.nativeElement)
.append('svg')
.attr('viewBox', `0 0 ${this.width} ${this.height}`)
.attr("preserveAspectRatio", "xMinYMin meet");
this.svg = this.d3
.select(this.figureElement.nativeElement)
.select('svg');
this.legend = this.svg
.append('g')
.attr('id','legend');
this.graphGroup = this.svg
.append('g')
.attr(
'transform',
'translate(' + this.width / 2 + ',' + this.height / 2 + ')'
);
}
private createLegend(): void {
//code for creating the vertical legend at the top
}
private createColors(data): void {
//code for generating random colors
}
private drawChart(): void {
const pie = this.d3
.pie()
.sort(null) // Do not sort group by size
.value(d => {
return d.value;
});
const data_ready = pie(this.data);
// The arc generator
const arc = this.d3
.arc()
.innerRadius(this.radius * 0.4)
.outerRadius(this.radius * 0.48);
// code for building pie chart
// code to add the lines between chart and labels:
// code to add the labels:
}
