Blog for QTI developers

2016/08/09

AJAX 그리고, JavaScript를 이용한 Google Chart 생성

AJAX에 대하여

  AJAX[1]는 비동기 JavaScript와 XML을 말한다.
간단히 말해 데스크톱 애플리케이션 수준으로 웹 페이지 간 상호 작용을 하기 위한 기술들의 모음이다.

이름 때문에 XML로만 한정된 것으로 오인 할지 모르지만 실제로 서버 측으로부터 다양한 형식(JSON, XML, HTML 및 일반 텍스트 형식 등)의 정보를 주고받을 수 있다.
이런 AJAX의 중요한 특징으로 페이지 전체를 갱신하지 않고서 수행되는 '비동기성'이 있는데 이러한 비동기성을 통해 사용자의 Event가 있으면 전체 페이지가 아닌 일부분만을 변경할 수 있다.


XMLHttpRequest에 대하여

  JavaScript(이하 'JS'로 표기)에서 실제로 AJAX를 이용하기 위해서는 XMLHttpRequest(이하 일부 'XHR'로 표기) 개체를 사용한다.
이 XHR는 'Microsoft Exchange Server 2000'의 'Outlook Web Access' 개발자에 의해 만들어졌으며, 이후에 Mozilla도 받아 들여 Gecko layout engine에도 XHR에 대한 인터페이스가 구현이 되었다.
즉, 웬만한 브라우저에서 사용이 가능하다.
더욱이 jQuery에서 제공하는 AJAX API인 '$.ajax()'도 XHR을 Wrapping 한 것이라고 하니, XHR에 대해서 알아두면 좋을 듯하다.

XHR은 IE4 이하에서는 사용할 수 없으며, IE5, 6에서는 XMLHttpRequest 개체 대신 ActiveXObject를 이용해 'ActiveXObject("Microsoft.XMLHTTP")'와 같이 사용해야하지만, 이미 MS社에서 지원 중단을 공표[2]한 브라우저에 대해서는 대응 여부를 고려해볼 필요가 있을 것 같다.


Node.js를 이용한 간단한 서버 구현

  Google에서 서비스하는 'Google Charts'에는 다양한 Open-source의 Chart가 제공되고 있다. 해당 Chart API를 사용하기 위해서는 별도의 복잡한 절차가 필요하지 않으며, 각각의 예제 페이지와 해당 문서를 참조하면 된다.
우선 간단한 예제로, 그림과 같은 pie chart를 생성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    ... 전략 ...
 
    // Create the data table.
    var data = new google.visualization.DataTable();
    data.addColumn('string''Topping');
    data.addColumn('number''Slices');
    data.addRows([
        ['Mushrooms'3],
        ['Onions'1],
        ['Olives'1],
        ['Zucchini'1],
        ['Pepperoni'2]
    ]);
 
    ... 후략 ...
예제에서 사용된 코드를 보면 'data table'을 생성하기 위해서, string 타입의 'Topping' Column과 number 타입의 'Slices' Column이 필요하다. 그리고 'Topping'과 'Slices' 각각의 Column에 대응되는 5개의 Row가 필요하다.

Node.js를 이용해서 서버를 구현하고 다음과 같은 JSON 데이터를 출력하도록 코드를 작성한다.
1
2
3
4
5
6
7
8
// JSON data
{"RecordSet":{"header":"Google Chart data",
    "RecordFields":[{"string":"Topping"},{"number":"Slices"}],
    "RecordData":[{"Topping":"Mushrooms","Slices":3},
        {"Topping":"Onions","Slices":1},
        {"Topping":"Olives","Slices":1},
        {"Topping":"Zucchini","Slices":1},
        {"Topping":"Pepperoni","Slices":2}]}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// server.js
let http = require('http');
 
http.createServer(function(req, res) {
    let jsonObjData = {"RecordSet": {
        "header""Google Chart data",
        "RecordFields": [{"string""Topping"}, {"number""Slices"}],
        "RecordData": [
            {Topping: "Mushrooms", Slices: 3},
            {Topping: "Onions", Slices: 1},
            {Topping: "Olives", Slices: 1},
            {Topping: "Zucchini", Slices: 1},
            {Topping: "Pepperoni",ㅣ Slices: 2}
        ]}
    };
 
    res.writeHead(200, {"Content-Type""application/json"});
    res.end(JSON.stringify(jsonObjData));
}).listen(8000'127.0.0.1');
 
console.log('### Server start');


XMLHttpRequest object 생성

  다음은 XHR 개체를 실제 구현한 JS 코드이다.
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
    // 브라우저에 맞게 XHR 개체를 생성한다.
    function getXMLHttpRequest() {
        if(typeof ActiveXObject != 'undefined') {
            return new ActiveXObject(
                // IE 5 버전일 경우와 아닌 경우로 나누어 리턴한다.
                navigator.userAgent.indexOf('MSIE 5'> -?
                'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP'
            );
        }
        return new XMLHttpRequest();
    }
 
    ... 일부 생략 ...
 
    // 서버에 데이터를 요청하고, 응답에 대한 처리를 한다.
    // 참조 > https://msdn.microsoft.com/ko-kr/library/ms535874(v=vs.85).aspx
    function initAjaxData(func) {
        let xhr = getXMLHttpRequest();
        if(xhr != 'undefined') {
            // Event 처리; request 이후 state 변경에 따른 처리를 담당한다.
            function stateHandler() {
                // --readyState
                // Holds the status of the XMLHttpRequest. Changes from 0 to 4:
                // 0: request not initialized
                // 1: server connection established
                // 2: request received
                // 3: processing request
                // 4: request finished and response is ready
                // --status
                // 200: (OK)요청 성공
                // 403: (Forbidden)접근 거부
                // 404: (Not Found)페이지 없음
                // 500: (Internal Server Error)서버 오류 발생
                if(xhr.readyState == 4) { //complete
                    if (xhr.status == 200) {
                        let jsonObj = JSON.parse(xhr.responseText);
 
                        let rs = jsonObj.RecordSet;
                        let rfs = new RecordFields(rs.RecordFields);
                        let rds = new RecordData(rs.RecordData);
 
                        func(rfs, rds);
                    } else if(xhr.status == 404) {
                        console.log("Not found");
                    }
                }
            }
 
            // Event 처리; Time out이 선언되면 처리를 담당한다.
            function timeoutHandler() {
                xhr.abort(); // request 취소
                alert("Time Out");
            }
 
            xhr.onreadystatechange = stateHandler; // 상태 변경
            xhr.ontimeout = timeoutHandler; // 응답시간 초과
 
            xhr.open("GET""http://127.0.0.1:8000/"true);
                // HTTP Method 종류, absolute 또는 a relative URL, Async 여부
            xhr.setRequestHeader("Content-Type""Application/json");
                // JavaScript Object Notation JSON; Defined in RFC 4627
            xhr.send(null);
        } else {
            console.log("AJAX (XMLHTTP) not supported.");
        }
    }


Google Pie Chart 생성

  서버로부터 받은 JSON 데이터를 이용하여 Chart를 생성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    initAjaxData(function(rfs, rds) {
        for(i in rfs.data) {
            data.addColumn(rfs.domain(i), rfs.get(i));
        }
 
        let rows = [];
        for(i in rds.data) {
            let columns = [];
            for(j in rfs.data) {
              columns[columns.length= rds.get(i, rfs.get(j));
            }
            rows[rows.length= columns;
        }
        data.addRows(rows);
 
    ... 일부 생략 ...
 
    });


 
-- 예제 파일
Share:

0 개의 댓글:

댓글 쓰기