D3_js

[D3.js] 막대 추가, 삭제 같이하기

vhxpffltm 2019. 10. 16. 23:35
반응형

이때까지 막대그래프를 가지고 데이터를 추가하고 삭제하는 시각화를 진행해보았다.

 

이 두가지를 함께 응용하여 추가와 삭제가 동시에 이루어지도록 해보자.

 

전체코드는 아래와 같다.

 

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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <meta charset="utf-8" />
    <script type="text/javascript" src="https://d3js.org/d3.v5.js"></script>
    <style>
        .st {
            font-family: sans-serif;
            font-size: 13px;
            fill: black;
        }
    </style>
    </head>
<body>
    <p id="re">이 문구를 클릭하면 데이터가 왼쪽부터 삭제될 겁니다.</p>
    <p id="add">이 문구를 클릭하면 데이터가 오른쪽부터 추가될 겁니다.</p>
    <script>
 
        //이전까지 갱신된 선택물(data()) 부족한 선택물(enter()) 남는 선택물(exit) 로 삽입 삭제를 해보았다.
        //데이터 결합에 대해 해보자
        //결합은 데이터와 DOM을 엮을 떄 발생, data()를 호출할 때이다.
        //key함수를 지정해서 데이터를 원하는대로 짝지어보자
        //마지막으로 추가 제거를 함께 적용하도록 만들어보자
 
        var dataset = [{ key: 0, value: 5 },        
                                { key: 1, value: 10 },        
                                { key: 2, value: 13 },
                                { key: 3, value: 19 },
                                { key: 4, value: 21 },
                                { key: 5, value: 25 },
                                { key: 6, value: 22 },
                                { key: 7, value: 18 },
                                { key: 8, value: 15 },
                                { key: 9, value: 13 },
                                { key: 10, value: 11 },
                                { key: 11, value: 12 },
                                { key: 12, value: 15 },
                                { key: 13, value: 20 },
                                { key: 14, value: 18 },
                                { key: 15, value: 17 },
                                { key: 16, value: 16 },
                                { key: 17, value: 18 },
                                { key: 18, value: 23 },
                                { key: 19, value: 25 }];
        var w = 600, h = 250;
        var xscale = d3.scaleBand().domain(d3.range(dataset.length)).rangeRound([0, w]).paddingInner(0.05);
 
        var yscale = d3.scaleLinear().domain([0d3.max(dataset, function (d) {
            return d.value;
        })]).range([0, h]);
 
        var key = function (d) {
            return d.key;
        }
        //키 함수 정의, d를 입력받아서 전달된 객체 d가 무엇이든간에 key값을 취하도록 명시.
 
        var svg = d3.select("body").append('svg').attr('width', w).attr('height', h);
        svg.selectAll('rect').data(dataset, key).enter().append('rect'//data(dataset,key)로 엮음, key는 위에서 정의한 함수이다.
           .attr('x'function (d, i) {
               return xscale(i);
           })
           .attr('y'function (d) {
               return h - yscale(d.value);
               // 속성지정을 위해 yscale(d) 가 아니라 yscale(d.value) 로 고쳐준다.
           })
           .attr('width', xscale.bandwidth())
           .attr('height'function (d) {
               return yscale(d.value);
           })
           .attr('fill'function (d) {
               return "rgb(155," + (d.value * 10+ ",155)";
           });
 
        svg.selectAll('text').data(dataset, key).enter().append('text')
           .text(function (d) {
               return d.value;
           })
           .attr('text-anchor''middle')
           .attr('x'function (d, i) {
               return xscale(i) + xscale.bandwidth() / 2;
           })
           .attr('y'function (d) {
               return h - yscale(d.value) + 14;
           })
           .attr('class''st');
 
 
        d3.selectAll('p').on('click'function () {
 
            var ID = d3.select(this).attr('id'); // 클릭한 문서요소의 id를 취한다.
            if (ID == 'add') {
                var minv = 2;
                var maxv = 25 - minv;
                var newnum = Math.floor(Math.random() * maxv) + minv;
                var lastkeyv = dataset[dataset.length - 1].key; // 마지막 원소의 키값을 찾는다.
                dataset.push({ key: lastkeyv + 1, value: newnum });
                //중복방지를 위해 키의 값을 1 늘리고 임의의 데이터를 넣는다.
            } // 새로운 값을 추가함
            else {
                dataset.shift();//datas에서 첫번째 데이터를 하나 지움, select묶음에서 제거
            }
 
 
            xscale.domain(d3.range(dataset.length));
            yscale.domain([0d3.max(dataset, function (d) {
                return d.value;
            })]);
            //domain값을 새로 갱신한다. 한개가 삭제되거나 추가되서
 
            var bars = svg.selectAll('rect').data(dataset,key);
            // 데이터를 key를 통해 바인딩하자.
 
            bars.enter().append('rect').attr('x', w)
                .attr('y'function (d) {
                    return h - yscale(d.value);
                })// x,y의 position을 다시 잡음, rect를 새로 만들어서 시작 x,y 좌표를 각 scale값에 맞게 잡음
                .attr('width', xscale.bandwidth())
                .attr('height'function (d) {
                    return yscale(d.value);
                })// 너비와 높이를 업데이트된 축에따라 x,y축에 기반하여 세팅
                .attr('fill'function (d) {
                    return 'rgb(255,0,' + (d.value*10)+')';
                })
                //merge를 하게되면 새로 또 세팅해서 그려야 한다.
                .merge(bars).transition().duration(1000)
                //아래에서 x,y,width,height를 조정하여 그리는거다.
                .attr('x'function (d, i) {
                    return xscale(i);
                })
                .attr('y'function (d) {
                    return h - yscale(d.value);
                })
                .attr('width', xscale.bandwidth())
                .attr('height'function (d) {
                    return yscale(d.value);
                }); // 새로운 rect의 x,y좌표와 svg width,height를 세팅
 
            bars.exit().transition().duration(1000).attr('x',-xscale.bandwidth()).remove();
            //exit를 통해 남은 문서요소를 추출하고 remove로 삭제
 
 
            var bar2 = svg.selectAll('text').data(dataset,key);
                bar2.enter().append('text').attr('width',xscale.bandwidth()).attr('height',function (d){
                    return yscale(d.value);
                })
                .attr('class','st')
                .text(function (d){
                    return d.value;
                })
                .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.25;
                })
                .attr('y'function (i) {
                    return h - yscale(i.value) + 14;
            }); // 텍스트의 x,y위치에 대한 값인데 이 부분을 좀 수정해서 rect모양의 가운데에 입력되도록 조정할 필요가 있음
        
        if(ID != 'add'bar2.exit().transition().duration(800).attr('x', w).remove();
 
        });
 
    </script>
</body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

코드에 주석을 참고하여 보자.

 

데이터를 추가하고 제거할 때 data와 관련이 있었다. 그리고 우리는 제거와 삭제를 진행할 때,

1) 데이터를 넣거나(push) 제거한다 (shift)

2) 문서요소를 SelectAll로 모두 선택하고 여기서는 'key' 를 통해 데이터를 바인딩한다.

3) enter().append()를 통해 기존의 데이터를 엮는다.

4) 추가하든 삭제하든 merge를 통해 구현한다.

 

*삭제일 경우에 exit() 함수를 끝에 추가하여 뺀 요소의 제거를 완료해야한다. *

 

여기서는 삭제와 삽입이 같이 이루어지기 때문에, 어떤 데이터가 삭제되거나 추가된것을 key를 사용하여 구분하여 시각화하는 점이 이전에 했던 점과 다른점이다.

 

여기서 또 한가지는 p태그에 id를 주어 이것이 추가인지 삭제인지 확인한다.

이후, 우리가 축을 재설정하고 전체 요소를 선택하기 전에 이미 데이터는 추가되거나 빠져있다. 그렇기에 이후의 작업은 이전에 배운대로 위의 내용에 따라 진행함을 이해하며 작업하는 것이 좋다.

 

본래, 'text' 파트는 개인이 구현해야 하며, 필자가 작성한 코드이다. 여러분이 원하는대로 수정하여 바꾸어보자. 

 

 

 

 

이렇게 하면서 기본내용은 익혔다고 본다. 많은 예제들은 D3 Github 공식 API문서와 Gallery를 참고하여 다양한 예제를 볼 수 있다.

 

다음에는 이벤트에 대해 알아보자,

 

https://github.com/d3/d3/wiki/Gallery

반응형

'D3_js' 카테고리의 다른 글

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