D3_js

[D3.js] 막대 추가해보기

vhxpffltm 2019. 9. 18. 22:44
반응형

이전시간에 막대 그래프와 산포도에 동적인 변화를 주었다. 이번에는 막대 그래프에서 클릭 시, 새로운 문서요소가 추가되어 막대가 생성되는 시각화를 본다.

 

- 코드 -

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <script type="text/javascript" src="https://d3js.org/d3.v5.js"></script>
    <meta charset="utf-8" />
    <style>
        .ss{
            fill : rgb(244, 14, 254);
            font-size : 11px;
        }
    </style>
</head>
<body>
    <p>이 문구를 클릭해보세요,</p>
    <script>
        //이때까지 데이터 집합의 배열값을 변경하고 DOM 문서요소와 엮어서 먼저 엮인 값을 덮어 씀.
        //이제는 그 데이터 중 한두개 더하거나 뺴는 유연한 경우를 살펴본다.
        //여기서는 막대를 추가해본다.
        var w = 600;
        var h = 350;
 
        var dataset = [5101319212522181513,
                        11121520181716182325];
 
 
        var xScale = d3.scaleBand()
                        .domain(d3.range(dataset.length))
                        .rangeRound([0, w])
                        .paddingInner(0.05);
 
        var yScale = d3.scaleLinear()
                        .domain([0d3.max(dataset)])
                        .range([0, h]);
 
 
        var svg = d3.select("body")
                    .append("svg")
                    .attr("width", w)
                    .attr("height", h);
 
 
        svg.selectAll("rect"// 모든 rect를 선택한다. (아직 존재하지 않음)
           .data(dataset)     // 선택물에 데이터를 엮는다. 데이터가 갱신된 선택물 반환
           .enter()           // 부족한 선택물을 추출, 즉 20개의 plackholder 문서요소이다.
           .append("rect")    // 각 플레이스 홀더에 rect 생성한다.
           .attr("x"function (d, i) {
               return xScale(i);
           })
           .attr("y"function (d) {
               return h - yScale(d);
           })
           .attr("width", xScale.bandwidth())
           .attr("height"function (d) {
               return yScale(d);
           })
           .attr("fill"function (d) {
               return "rgb(0, 0, " + Math.round(d * 10+ ")";
           });
 
 
        svg.selectAll("text")
           .data(dataset)
           .enter()
           .append("text")
           .text(function (d) {
               return d;
           })
           .attr("text-anchor""middle")
           .attr("x"function (d, i) {
               return xScale(i) + xScale.bandwidth() / 2;
           })
           .attr("y"function (d) {
               return h - yScale(d) + 10;
           })
           .attr("font-family""sans-serif")
           .attr("font-size""11px")
           .attr("fill""white");
 
 
        d3.select('p').on("click"function () {
 
            var maxValue = 25;
            var newNumber = Math.floor(Math.random() * maxValue);
            dataset.push(newNumber);
 
            yScale.domain([0d3.max(dataset)]);
            xScale.domain(d3.range(dataset.length)); // 차트를 추가하기 때문에 xscale값도 같이 갱신을 해야한다.
 
            //select
            var bars = svg.selectAll("rect").data(dataset);
            //모든 bar를 선택해서 새로운 데이터와 다시 엮은 후, 데이터가 갱신된 선택물을 한 번에 추려 낸 결과를 볼것.
            //이제는 21개의 데이터를 가지고 있다. 새로운 데이터 값을 위한 rect를 그려야한다.
 
            //Enter 
            //이것을 통해 만들것이다. enter는 부족한(새로 들어올) 그리고 넘치는(삭제할) 모든 요소를 건드릴 수 있다.
            //selectAll -> data() -> enter() -> append() 로 일어나는 과정으로 생각해보자
 
            bars.enter().append('rect').attr('x', w).attr('y'function (d) {
                return h - yScale(d);
            })
            .attr('width', xScale.bandwidth())
            .attr('height'function (d) {
                return yScale(d);
            })
            .attr('fill'function (d) {
                return 'rgb(0,255,' + Math.round(d * 10+ ')';
            })  //새로 추가될 rect의 모양, 즉 xscal,yscal, 색상을 위의 내용과 똑같이 만든다
            .merge(bars).transition().duration(500).attr('x'function (d, i) {
                return xScale(i);
            })
           .attr('y'function (d) {
               return h - yScale(d);
           })
            .attr('width', xScale.bandwidth()).attr('height'function (d) {
                return yScale(d);
            });
            //merge : 전달인자 arrays를 하나의 배열로 합쳐준다.  
 
            
            var bar2 = svg.selectAll('text').data(dataset);
            bar2.enter().append('text').attr('width', xScale.bandwidth()).attr('height'function (d) {
                return yScale(d);
            })
            .attr('class''ss')
            .text(function (d) {
                return d;
            }) // 각 인덱스에서 값을 리턴해야 텍스트가 출력딤
            .merge(bar2).transition().duration(function(i,d){
                return i / dataset.length * 200;}).duration(1000).each(d3.easeBounce) //합치면서 transision 효과를 넣어줌
            .attr('x'function (d, i) {
                return xScale(i) + xScale.bandwidth()*0.3 ;
            })
            .attr('y'function (i) {
                return h - yScale(i) + 14;
            }); // 텍스트의 x,y위치에 대한 값인데 이 부분을 좀 수정해서 rect모양의 가운데에 입력되도록 조정할 필요가 있음
           
        })
    </script>
</body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 

코드에 있는 주석을 확인하여 이해하길 바란다.

 

가장 중요한 부분은 'p' 태그를 클릭한 이후의 내용이다. 새로운 막대를 추가하기에 xscale값을 변경해야 함을 알아야한다.

 

추가하는 과정은 모든 bar를 선택해 새로운 데이터와 다시 엮은 후, 데이터가 갱신된 선택물을 한번에 추려내야 한다. 이 과정을 Select라 하자.

 

이제 Enter의 과정이 필요하다. enter는 부족한(새로들어오는) 그리고 넘치는(삭제할) 모든 요소를 참조할 수 있다. 

 

즉 SelectAll -> data -> enter -> append 로 일어나는 과정으로 생각하자.

 

 bars.enter().append('rect').attr('x', w).attr('y'function (d) {

                return h - yScale(d);

            })

            .attr('width', xScale.bandwidth())

            .attr('height'function (d) {

                return yScale(d);

            })

            .attr('fill'function (d) {

                return 'rgb(0,255,' + Math.round(d * 10+ ')';

            })  //새로 추가될 rect의 모양, 즉 xscal,yscal, 색상을 위의 내용과 똑같이 만든다

 

이 과정을 통해 새로 들어오는 하나의 새로운 막대를 생성한다. 

 

이제 만든 막대를 합친다고 생각하자. merge를 통해 합하는데 그 위치인 x,y와 width를 추가한다.

합칠때, transition을 사용하였다. 이 부분을 빼도 무난히 동작한다.

 

여기서 중요한 것은 추가된 데이터를 SelectAll로 선택하고 추가된 데이터를 enter().append()로 시각화를 추가함과 함께 그려준다. 그렸으면 merge를 통해 합쳐준다.

 

 

-실행 결과-

 

 

 

다른 방법도 있으니 아래의 주소를 참고바란다. 아래코드는 자동으로 랜덤한 데이터의 값이 막대로 계속 갱신된다.

 

https://github.com/NickQiZhu/d3-cookbook/blob/master/src/chapter6/multi-element-transition.html

반응형

'D3_js' 카테고리의 다른 글

[D3.js] 막대 추가, 삭제 같이하기  (0) 2019.10.16
[D3.js] 막대 제거하기  (0) 2019.09.23
[D3.js] 산포도 갱신, 트랜지션  (0) 2019.08.28
[D3.js] 막대 그래프 갱신, 트랜지션(trasition)  (0) 2019.08.28
[D3.js] 축_ aXis  (0) 2019.08.15