[Angular] D3.js Pie Chart 그리기, 갱신하기

dh·2023년 2월 27일
0

이번에는 pie chart를 만들어 보려고 한다.
10분전, 30분전, 1시간전 데이터와 10초주기 갱신은 등 로직은 Line chart와 똑같고 d3.js로 파이차트를 만드는 코드만 다르다.

파이차트 그리기 코드

1. 먼저 pie Div에 svg태그를 설정한다.

 this.svg = d3.select("#pie")
        .append("svg")
        .attr("width",this.width)
        .attr("height",this.height)
        .append("g")
        .attr("transform", "translate(" + this.width / 2 + "," + this.height / 2 + ")");

2. 파이차트 셋팅

https://github.com/d3/d3-shape/blob/main/README.md#pie_sort

color는 파이 각각의 영역의 색을 설정하는데 내 pie데이터에는 5개가 들어있어 5개만 설정한다.
arc는 호의 외부 반경과 내부 반경을 설정한다. 내부 반경은 도넛의 가운데 구멍의 크기를 설정한다. 0으로 해서 도넛 모양 대신 완전한 원으로 할 수 있다.
pie는 파이차트를 랜더링할 데이터를 설정한다.

var colors = d3.scaleOrdinal()
                    .domain(msg.data)
                    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56"])
  
  
var arc = d3.arc().innerRadius(this.innerRadius)
			.outerRadius(this.outRadius)

var pie = d3.pie().sort(null).value(function(d:any){return d.value})

3. 차트 그리기

 this.svg.selectAll('pieces')
          .data(pie(msg.data))
          .enter()
          .append('path')
            .attr("class","pie")
            .attr('d', arc)
            .attr('fill',(d:any, i:any)=>(colors(i)))
            .attr("stroke", "black")
            .style("stroke-width", "2px")
            .style("opacity", 0.7)

4. 라벨 텍스트 그리기

 const labelLocation = d3.arc()
                          .innerRadius(100)
                          .outerRadius(this.radius);
this.svg.selectAll('pieces')
  .data(pie(msg.data))
  .enter()
  .append('text')
  .text((d: any)=> d.data.name)
  .attr("transform", (d: any) => "translate(" + labelLocation.centroid(d) + ")")
  .style("text-anchor", "middle")
  .style("font-size", 15);        

파이차트 갱신하기

https://medium.com/@kj_schmidt/making-an-animated-donut-chart-with-d3-js-17751fde4679

파이차트 갱신도 역시 transition을 이용해 애니메이션 효과를 준다.

 var pie = d3.pie().value(function(d:any){return d.value}).sort(null)

 var arc = d3.arc().innerRadius(this.innerRadius)
 			.outerRadius(this.outRadius)
 var path = this.svg.selectAll(".pie")
 				.data(pie(msg.data))

 path.transition()
   .duration(1000)
   .attr("d",arc);

전체코드

import { Component, Input, OnInit, OnChanges,ElementRef, ViewChild,AfterViewInit  } from '@angular/core';
import { DataService } from '../data.service';
import * as d3 from 'd3';
import * as d3Scale from 'd3-scale';

@Component({
  selector: 'app-pie',
  templateUrl: './pie.component.html',
  styleUrls: ['./pie.component.css']
})
export class PieComponent implements OnChanges {
  @Input() start = '';
  width=1000;
  height=350;
  margin=50
  outRadius=Math.min(this.width,this.height)/2
  innerRadius=this.outRadius*0.5
  radius = Math.min(this.width, this.height) / 2 - this.margin;
  data : any[]=[]
  svg : any


  constructor(private dataService: DataService){
  }

  ngOnChanges() {
    d3.select("#pie").selectChildren().remove()
    this.drawchart(+this.start)
  }

  ngOnInit(): void {
    setInterval(()=>{this.updatechart(this.start)},10000)
    
  }

  drawchart = (time:Number)=>{
    let now = Date.now()
    let result = this.dataService.getData(now- +this.start, now, "pie").subscribe(
      msg=>{
        this.svg = d3.select("#pie")
        .append("svg")
        .attr("width",this.width)
        .attr("height",this.height)
        .append("g")
        .attr("transform", "translate(" + this.width / 2 + "," + this.height / 2 + ")");
        
      
      var colors = d3.scaleOrdinal()
                    .domain(msg.data)
                    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56"])
  
  
      var arc = d3.arc().innerRadius(this.innerRadius)
                        .outerRadius(this.outRadius)
  
      var pie = d3.pie().sort(null).value(function(d:any){return d.value})
  
      this.svg.selectAll('pieces')
          .data(pie(msg.data))
          .enter()
          .append('path')
            .attr("class","pie")
            .attr('d', arc)
            .attr('fill',(d:any, i:any)=>(colors(i)))
            .attr("stroke", "black")
            .style("stroke-width", "2px")
            .style("opacity", 0.7)
    
      const labelLocation = d3.arc()
                          .innerRadius(100)
                          .outerRadius(this.radius);
      this.svg.selectAll('pieces')
            .data(pie(msg.data))
            .enter()
            .append('text')
            .text((d: any)=> d.data.name)
            .attr("transform", (d: any) => "translate(" + labelLocation.centroid(d) + ")")
            .style("text-anchor", "middle")
            .style("font-size", 15);        
      });
  }

  updatechart = (time:any)=>{
    let now = Date.now()
    let result = this.dataService.getData(now- +this.start, now, "pie").subscribe(
      msg=>{

        var pie = d3.pie().value(function(d:any){return d.value}).sort(null)

        var arc = d3.arc().innerRadius(this.innerRadius)
                            .outerRadius(this.outRadius)
        var path = this.svg.selectAll(".pie")
                          .data(pie(msg.data))

        path.transition()
            .duration(1000)
            .attr("d",arc);
      });
  }
}

결과

0개의 댓글