D3_js

[D3.js] 산포도 갱신, 트랜지션

vhxpffltm 2019. 8. 28. 22:30

이번에는 막대그래프가 아닌 산포도를 갱신해보자.

 

변경사항은 

1 - 클릭이벤트에 따라 새로운 데이터를 랜덤한 값으로 생성한다.

2 - 데이터 갱신이 일어나면 트랜지션이 발생한다.

3 - delay는 없고 1초안에 한번에 트랜지션이 일어나며 갱신 후 새로운 트랜지션이 발생한다.

4 - X, Y 축도 갱신한다.

5 - 산포도의 반지름을 모두 같게 한다.

 

전체코드를 보자. 주석으로도 내용을 표시하였다.

 

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
<!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>
</head>
<body>
    <p>
        이 문구를 클릭하면 동적인 움직임이 나타날 겁니다.
    </p>
    <script>
        var scale = d3.scaleLinear(); // 척도함수 생성
        scale.domain([100500]); // 정의역의 범위를 설정
        scale.range([10350]); // 치역 범위를 생성
 
        var scale2 = d3.scaleLinear().domain([100500]).range([10350]);//위의 코드를 한 라인으로 만든것
        scale2(100); // 10을 반환한다.
 
        var h = 300, w = 500, padding=30;
        // 난수로 동적 데이터 만들기
        var datas = [], xrange = Math.random() * 1000, range=1000;
        var max_num = 50;
        for (var i = 0; i < max_num; i++) {
            var newnum1 = Math.floor(Math.random() * range);
            var newnum2 = Math.floor(Math.random() * range);
            datas.push([newnum1, newnum2]);
        }
 
        var xscale = d3.scaleLinear().domain([0d3.max(datas, function (d) {
            return d[0]; // datas는 배열의 배열, 해당 배열에서 배열의 0번째 원소중 가장 큰걸 반환
        })]).range([padding, w-padding*4]);
 
        var yscale = d3.scaleLinear().domain([0d3.max(datas, function (d) {
            return d[1]; //내장 배열의 2번째 값을 반환함.
        })]).range([h-padding, padding]); // y값이 큰것이 위로가고 작은것이 아래로 내려오게 된다. 치역이 바껴버림!!!
        //척도함수에 쓰일 x,y 최대값을 만들어냄
        var rscale = d3.scaleLinear().domain([0d3.max(datas, function (d) {
            return d[1];
        })]).range([25]);
        //반지름을 전용 척도로 사용한것, 반지름값은 항상 range의 범위때문에 2~5사이의 값을 가짐, 정의역의 크기에 따라 2~5값을 가지게 된다.
        // 즉, 척도라 함은 y=f(x) 함수라고 이해하자!! domain이 정의역 range가 치역!!!
       
        var svg = d3.select("body")
                    .append("svg")
                    .attr("width", w)
                    .attr("height", h);
 
        
        svg.append("clipPath")
                .attr("id""chart-area")
                .append("rect")
                .attr("x", padding)
                .attr("y", padding)
                .attr("width", w - padding * 3)
                .attr("height", h - padding * 2.5);
 
        //클리핑 패스 : 경계선을 벗어난 지점을 덮는것이 목적. g그룹을 이용하여 앞의 만든 ID로 참조한다.
        //아래에서 3줄의 라인이 필요하다 그룹g에 모든 점을 넣고 이와 함께 id가 chart-area인 clip path를 참조한다. 
        //예제에서 h값을 적절히 조정하여 클리핑 패스를 적용시켜준다.
        svg.append('g').attr('id','circles').attr("clip-path","url(#chart-area)")
            .selectAll("circle")
            .data(datas)
            .enter()
            .append("circle")
            .attr("cx"function (d) {
                return xscale(d[0]);
            })
            .attr("cy"function (d) {
                return yscale(d[1]);
            })
            .attr("r"function (d) {
                return rscale(d[1]);
            });
 
        //축
        //x축 만들기
        var xAxis = d3.axisBottom().scale(xscale).ticks(5);
 
        svg.append('g').attr('class''x axis').attr('transform''translate(0,' + (h - padding - 10+ ')')
            .call(xAxis);
 
        var yAxis = d3.axisLeft().scale(yscale).ticks(3);
 
        svg.append('g').attr('class''y axis')
            .attr('transform''translate(' + padding + ',0)').call(yAxis); 
        // ' ' (구간)을 구별해서 숫자를 잘 더하고 변경하기
 
        d3.select("p").on("click"function () {
            var maxval = datas.length;
            var maxra = Math.random() * 1000;
            datas = [];
            for (var i = 0; i < maxval; i++) {
                var newnum1 = Math.floor(Math.random() * maxra);
                var newnum2 = Math.floor(Math.random() * maxra);
                datas.push([newnum1, newnum2]);
            }
 
            xscale.domain([0d3.max(datas, function (d) { return d[0]; })]);
            yscale.domain([0d3.max(datas, function (d) { return d[1]; })]);
            rscale.domain([0d3.max(datas, function (d) { return d[1]; })]);
 
            
 
 
            svg.selectAll('circle').data(datas).transition().duration(1000).on('start'function () {
                d3.select(this).attr("fill"'masgenta').attr('r'3);
                //this는 해당 문서요소이다. this의 배경색과 반지름을 변환한다.
            })
            .attr('cx'function (d) {
                return xscale(d[0]);
            })
            .attr('cy'function (d) {
                return yscale(d[1]);
            })
            .attr('r'function (d) {
                return rscale(d[1]);
            })
            .on('end'function () {
                d3.select(this).attr('color''black').attr('r'2)
                .transition().duration(3000).attr('fill''blue').attr('r'5);
                //end에서는 새로운 트랜지션을 적용해도 문제가 발생하지 않는다. -> 해당 트랜지션이 끝나기 떄문
                //시작하거나 끝나는 시점에 on을 사용하여 시작시 해당 설정으로 바뀌고 끝날때 설정한 값으로 바뀜...
            });
 
            svg.select(".x.axis").transition().duration(1000).call(xAxis);
            svg.select(".y.axis").transition().duration(1000).call(yAxis);
            //축을 동적으로 움직이고 변화하게 된다. 이벤트 밖에서 클래스에 'x axis' ,'y axis'로 변경한다.
            //관련된 축 생성자 함수를 호출하면서 축도 동적으로 변화한다.
            //축 생성자는(xaxis,yaxis) 이미 척도함수(xscale,yscale)을 참조한다. 척도함수가 갱신되므로 축 생성자도 갱신 
        });
        
    </script>
 
</body>
</html>
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 

여기서는 클릭 이벤트가 발생했을 때의 내용만을 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
 d3.select("p").on("click"function () {
            var maxval = datas.length;
            var maxra = Math.random() * 1000;
            datas = [];
            for (var i = 0; i < maxval; i++) {
                var newnum1 = Math.floor(Math.random() * maxra);
                var newnum2 = Math.floor(Math.random() * maxra);
                datas.push([newnum1, newnum2]);
            }
 
            xscale.domain([0d3.max(datas, function (d) { return d[0]; })]);
            yscale.domain([0d3.max(datas, function (d) { return d[1]; })]);
            rscale.domain([0d3.max(datas, function (d) { return d[1]; })]);
 

 

많이 본 구문이다. 클릭 시, 데이터를 랜덤한 값으로 갱신하고 있다. 이 후 X축과 Y축 역시 최대값으로 척도를 갱신한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
svg.selectAll('circle').data(datas).transition().duration(1000).on('start'function () {
                d3.select(this).attr("fill"'green').attr('r'3);
                //this는 해당 문서요소이다. this의 배경색과 반지름을 변환한다.
            })
            .attr('cx'function (d) {
                return xscale(d[0]);
            })
            .attr('cy'function (d) {
                return yscale(d[1]);
            })
            .attr('r'function (d) {
                return rscale(d[1]);
            })
            .on('end'function () {
                d3.select(this).attr('color''black').attr('r'2)
                .transition().duration(3000).attr('fill''blue').attr('r'5);
            });
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

원을 그리고 있다. duration 뒤의 on이 붙어있는데 여기서 트랜지션이 시작하거나 끝나는 시점에 무언가를 동작시키기 위함이다. 'start'를 통해 트랜지션 시작 시 먼저 반지름이 3이고 색상이 녹색인 원이 1초동안 이동한다. 이 트랜지션이 실행되는 동안 코드는 잠시 멈춘다.

 

이후 'end' 를 통해 두 번째 트랜지션이 시작된다. 이 트랜지션이 시작될때, 주요 트랜지션은 이미 종료가 된 상태이다. 3초 동안 반지름이 5인 파란색 원으로 변화될 것이다. 

 

ClipPath

 

코드에 clipPath가 있을텐데 이것은 SVG요소로 다른 문서요소에 덧댈 때 사용하는 가시적인 요소를 가진다. 

 

예제를 실행시켜 clippath를 보면 다음과 같은 값을 가진다. 가시적인 요소로 'rect' 를 주고 마스크로 덮을 문서요소에 clippath 참조를 추가한다. 

 

예제의 주석에도 있지만 'g' 를 새로 생성해 아이디를 지정하고 ID가 'chart-area'인 clippath 참조를 추가하였다. 이것을 이용하여 산포도의 점이 차트 영역의 경계에 다다르면 그 픽셀을 잘라 버린다. 코드 결과를 확인하면 알 수 있다.

 

 

축 생성자와 척도를 구별해야한다. 주석을 참조바라며 X, Y축은 다음의 단계를 따른다.

1 - 축을 선택한다.

2 - 트랜지션을 생성하고 지속시간을 지정한다.

3 - 관련 축 생성자 함수(call)를 통해 호출한다.

 

X 축 생성

1
2
svg.append('g').attr('class''x axis').attr('transform''translate(0,' + (h - padding - 10+ ')')
            .call(xAxis);
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 

X축 갱신

1
 svg.select(".x.axis").transition().duration(1000).call(xAxis);
 

 

 

위 코드의 결과는 아래와 같다.

 

'D3_js' 카테고리의 다른 글

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