이번에는 pie chart를 만들어 보려고 한다.
10분전, 30분전, 1시간전 데이터와 10초주기 갱신은 등 로직은 Line chart와 똑같고 d3.js로 파이차트를 만드는 코드만 다르다.
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 + ")");
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})
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);
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);
});
}
}