LANGUAGE/JAVASCRIPT

d3.js 사용법 - ② bar chart 그리기

옐옐루 2022. 11. 8. 15:54

d3.js 를 사용하여 막대그래프(bar chart)를 그려보기 전에 , 기초 세팅을 해야함

기초 세팅은 아래 포스팅에서 확인가능 

d3.js 사용법 - ① 개념 및 초기세팅 (tistory.com)

 

d3.js 사용법 - ① 개념 및 초기세팅

Data - Driven Documents. JavaScript 데이터 중심의 문서 (Data - Driven Documents)의 약자로 자바스크립트 기반의 라이브러리 언어 웹브라우저 상에서 동적인 정보시각화를 구현하기 위한 자바스크립트 라이

tjqud531531.tistory.com


그리드와 차트를 그릴때 사용한 데이터

사용된 데이터 예제

 

 

 

 

1. 데이터 세팅

    차트를 불러오기전에 Jgrid 와 마찬가지고 데이터를 먼저 불러와야한다. 

    ajax를 통해 컨트롤러에서 json데이터를 불러오고, DB에서 불러드린 데이터를 getData라는 변수에 담아 사용

    drawChart1()이라는 함수를 호출 . 실행함수를 빠져나와 drawChart1이라는 이름을 가진 함수를 만들어주자 

    데이터를 가지고 올 getData와 이후 버튼 이벤트 추가를 고려하여 type을 변수에 넣어줌 

출처 : 본인 PPT

 

2. html에 차트가 들어갈 공간 만들어주기 

 

출처 : 본인 PPT

 

3. d3.js chart 그리기

function drawChart1(getData,type){	

	  // 순서대로 척도만들고, 축도 생성해주기
      if(!type){
      chartHeight = 500 // 차트의 전체 높이
      chartWidth  = 500 // 차트의 전제 너비 
	  
      // de.select함수를 이용해 차트가 만들어질 공간의 아이디 선택
      // 아이디에 svg라는 공간 확보 후 높이와 넓이 속성 추가 
      chartSvg = d3.select("#yerin-chart")
      .append("svg")
      .attr("height",500).attr("width",500)
      .attr("id","svg1")       
	  
	  // 척도 만들기
      // Y축은 숫자가 증가하는 선형모양 - linear함수사용
      // X축은 문자가 증가하는 모양 - ordinal 함수 사용
      // Domain(실제값의 array), range(픽셀값) 
	  Yscale = d3.scale.linear().domain([0,40]).range([470,30])
	  Xscale = d3.scale.ordinal()
      .domain(["A","B","C","D","E","F","G","H","I","J"])
      .rangeBands([30,470]);
	
	  // 축만들기
      // 위에 만들어 놓은 svg호출 후 axis()함수 호출 
      // 축의 방향을 정하는 orient 태그를 활용 하여 축의 위치 정하기
	  Yaxis = d3.svg.axis().scale(Yscale).orient("left")
	  Xaxis = d3.svg.axis().scale(Xscale).orient("bottom")

	  // 만들어진 svg 공간에 'g'공간을 추가한 후 이 공간 안에 축을 그리는 axis를 불러온다.
	  chartSvg.append("g").call(Yaxis)
      .attr("transform","translate(30,0)")
      .attr("class","axis")
	  
      chartSvg.append("g").call(Xaxis)
      .attr("transform","translate(0,470)")
      .attr("class","axis")
	  }
}

 

 * Yscale 에는 domain은 범위를 쓰고, Xscale에는 하나하나 넣어주는 이유 

   - Y축에 들어갈 숫자는 범위로 쓰는게 가능하지만 X축에 들어가는 글자는 따로따로 다 써줘야함 (글자는 범위를 지정하

     기가 애매하기 때문

 * domain과 range의 정확한 차이 

   - 지도를 생각했을때 우린 축적을 계산하여 엄청나게 큰 지구를 작게 축소시켜 나타낸다 차트도 데이터 값이 어떨지 모

     르므로 사용자가 봤을때 한눈에 보이도록 다 담아야한다

   - 따라서 실제 값을 domain에 써주고, 사용자가 인식하는 픽셀값은 range에 해당한다고 이해하면 된다

 * Yscale 에는 range를 쓰고, Xscale에는 rangeBands를 쓰는 이유

    - scale은 말그대로 축적을 얘기 하는 것. 숫자로 표현된 Yscale은 range또한 범위로 지정하기가 쉽지만 Xscale은 

      문자가 들어가게 됨. 그럼 그 문자열을 하나하나 위치 지정을 해주어야 하지만 이 행동이 귀찮기 때문에 자동으로

      width검사를 해서 글자 사이의 간격을 맞추는 아이가 rangeBands임 

 

 

 

3. 만들어놓은 차트의 틀 내부에 데이터 집어 넣기 

  * 위에서 만들어 놓은건 말그대로 데이터가 들어가기 전의 차트의 공간만 확보해놓은 상황

  * 만들어 놓은 공간에 데이터를 집어 넣어 보자 

 

	//위에 만들어 놓은 drawChart() 코드에 이어서 바로 쓰면됨
    
      // 데이터가 들어갈 공간을 'g'=group 속성으로 만든 뒤 dataSvg 변수에 넣기
      // 앞으로 var1과 var2 두가지의 변수가 들어갈 것이기 때문에 if문으로 type구분
      // 데이터를 하나만 넣고 싶다면 이렇게 만들 필요 없음 
      dataSvg = chartSvg.append("g").attr("class","datasvg");	
	  if(type=="var1"){ 
      // 데이터를 집어 넣는 부분 
      dataSvg.selectAll("rect").data(getData).enter().append("rect")
        .attr("x", function(d){return Xscale(d.group)})
        .attr("y", function(d){return Yscale(d.var1)})
        .attr("width",30)
        .attr("height", function(d){return chartHeight-Yscale(d.var1)-30})
        .attr("transform","translate(7,0)")
        .style("fill","#687F8F").attr("id","var1")
		
	  }else if(type=="var2"){
      dataSvg.selectAll("rect").data(getData).enter().append("rect")
      	.attr("x", function(d){return Xscale(d.group)})
        .attr("y", function(d){return Yscale(d.var2)})
        .attr("width",30)
        .attr("height", function(d){return chartHeight-Yscale(d.var2)-30})
        .attr("transform","translate(7,0)")
        .style("fill","#687F8F").attr("id","var2")
	  }

 

   *소스 분석하기

  * 우리는 아직까지 rect라는 공간을 만든적이 없음. 하지만 데이터가 들어가 있어야 rect를 생성할 수 있음

  * 다시 말해 실제로는 만들어지지 않았지만 임의로 rect라는아이를 집어내야한다는 뜻 따라서

   *  selectAll("rect") - 임의로 rect라는 요소들을 모두 선택 

   * .data(getData).enter() 임의 rect에 data를 집어 넣음 (하지만 실제 rect가 만들어지기 전이므로 이 또한 임의적인 행동)

   * .append("rect") - 실제로 rect를 만드는 부분 

   * .attr("x", function(d){return Xscale(d.group)}) 콜백 함수를 통해 x축에 위에서 만들어 놓은 X축의 틀을 집어 넣는 과

      정 (group에 해당되는 변수를 x축의 틀에 담아 실제 x축 데이터로 집어넣어라)   

    * .attr("y", function(d){return Yscale(d.var1)}) 위와 동일. y축에는 var1의 값들이 들어갈 것 

    * attr("width",15) 생성할 차트의 막대 너비

    * attr("height",function(d){return chartHeight-Yscale(d.var1)-30}) : 좌표 [0,0] 기준 화면상 왼쪽 맨 위끝임. chart는 

       저 0,0 좌표를 기준으로 생성되다보니 막대그래프의 시작점은 0,0이 되어버림. 즉 그래프가 위에서 부터 생성됨

    * 하지만 우리는 그래프를 아래에서부터 그리고 싶음 , 위에서 그래프의 Yscale의 range를 [30,470]이 아니라 [470,30] .        로 생성해주면 됨.  내가 실제로 저렇게 값을 쓴 이유가 이것 . 
    * 왜 range가 0,500이 아니라 30,470인지 궁금해 하는 사람이 있는데 단순히 padding값을 css적으로 적용시켜서 저렇          값을 매긴 것 뿐임 (패딩을 먹이지 않으면 y좌표가 화면 왼쪽에 달라붙어 눈에 안보임) 
    * 생성된 그래프의 높이 또한 위를 기준으로 잡히기 때문에 화면상의 var1의 값은 내가 넣고 싶은 값이 아닌 전체 차트의        높이 - var1의 값이 되어버림 . 그렇기 때문에 전체 높이에서 Yscale에 들어온 데이터 var1의 값과 패딩 값 30을 빼야            우리가 원하는 모양의 막대 그래프의 모양이 나오게 됨 

    * 아래 포스팅에 bar chart의 높이 및 모양을 설정하는 부분만 따로 빼서 설명해 놨으니 이해가 되지 않으면 한번 보기

       d3.js 막대그래프 높이 및 위치 설정 (tistory.com)

 

d3.js 막대그래프 높이 및 위치 설정

d3.js를 이용하여 막대 그래프를 그릴 때 그래프가 아래서부터 그려지는 것이 아닌 위에서부터 그려지는 경우가 있다 이 부분을 해결하기 위해선 (전체 높이-넣고자 하는 데이터 값) 계산을 해야

tjqud531531.tistory.com

 

 

 

4. 데이터를 집어넣은 drawChart()를 실행함수에서 호출시켜주면 끝  (우린 이미 1번 과정에서 drawChart(getData)로 호 

    출 시켜놨음 

 

 

  [위를 다 적용시킨 전체 drawChart 소스]

function drawChart1(getData,type){
	  if(!type){
	  chartHeight = 500
	  chartWidth  = 500
	  chartSvg = d3.select("#yerin-chart").append("svg")
      	.attr("height",500).attr("width",500)
      	.attr("id","svg1")
	  
	  Yscale = d3.scale.linear().domain([0,40]).range([470,30])
	  Xscale = d3.scale.ordinal()
      	.domain(["A","B","C","D","E","F","G","H","I","J"])
      	.rangeBands([30,470]);
	
	  Yaxis = d3.svg.axis().scale(Yscale).orient("left")
	  Xaxis = d3.svg.axis().scale(Xscale).orient("bottom")

	  chartSvg.append("g").call(Yaxis)
      	.attr("transform","translate(30,0)")
      	.attr("class","axis")
	  
      chartSvg.append("g").call(Xaxis)
     	 .attr("transform","translate(0,470)")
      	.attr("class","axis")
	  
      }

	  dataSvg = chartSvg.append("g").attr("class","datasvg");	
	  
      if(type=="var1"){ 
	    dataSvg.selectAll("rect").data(getData).enter().append("rect")
        .attr("x", function(d){return Xscale(d.group)})
        .attr("y", function(d){return Yscale(d.var1)})
        .attr("width",30)
        .attr("height", function(d){return chartHeight-Yscale(d.var1)-30})
        .attr("transform","translate(7,0)")
        .style("fill","#687F8F")
        .attr("id","var1")
		
      }else if(type=="var2"){
	    dataSvg.selectAll("rect").data(getData).enter().append("rect")
        .attr("x", function(d){return Xscale(d.group)})
        .attr("y", function(d){return Yscale(d.var2)})
        .attr("width",30)
        .attr("height", function(d){return chartHeight-Yscale(d.var2)-30})
        .attr("transform","translate(7,0)")
        .style("fill","#687F8F").attr("id","var2")
	  }
}

  

 

다음 포스팅에선 기본으로 그려놓은 차트를 가지고 여러가지 이벤트를 추가해 볼 예정

반응형