들어가며

이번 강좌에서는 HighCharts와 RealGrid를 연계하여 동작하는 방법을 배워보겠습니다.

이론

RealGrid에는 셀 렌더러Cell Renderer라는 기능을 통해 기본적인 스타일에 비해 확장된 개념의 그래피컬한 기능을 제공하고 있습니다. 셀 렌더러 중에서도 아래와 같이 차트와 유사한 형태의 인라인 그래프 기능의 렌더러가 있습니다.

셀 렌더러에 대해서는[B Class]의 강좌에서 자세히 다루게 됩니다.

이번 강좌에서는 차트 라이브러리인 HighCharts와 RealGrid가 서로 데이터를 공유하고, HighCharts가 그리드의 동작에 반응하도록 하는 방법을 배워보겠습니다.

What is HighCharts?

Highcharts는 Web 사이트 나 Web 응용 프로그램에 인터랙티브 한 차트를 추가하기 위해 쉬운 방법을 제공하는 순수한 JavaScript로 작성된 그래프 라이브러리입니다.
라이브러리 파일은 http://www.highcharts.com/download 페이지에서 다운 받을수 있습니다.
본 강좌는 highcharts의 기초지식에 의거하여 구현한 예제입니다. 보다 전문적인 지식이 필요한 경우 http://api.highcharts.com/highcharts 페이지를 참조해 주세요.

RealGrid와 HighCharts간 데이터 공유하기

먼저 RealGrid에 로드된 데이터를 HighCharts에 설정하기 위해 그리드에 데이터를 로드한 후 setHighChart 함수를 호출합니다.

setHighChart

$(element).highcharts({})는 HighCharts를 화면에 setup하는 함수입니다.
그리드와 데이터를 연계하기 위해 setup하는 과정에 HighCharts의 데이터나 x축 category에 DataProvider값을 설정해야 합니다.
HighCharts에 데이터를 설정하기 위해서는 특정 필드의 값을 배열형식의 데이터로 만들기 위해 LocalDataProvider.getFieldValues()함수를 사용하였습니다.

function setHiChart(provider) {
    var categories = provider.getFieldValues("year");
 
    $('#highcharts').highcharts({
        title: {
            text: '통계청 총생산소득',
            x: -20
        },
        subtitle: {
            text: 'www.realgrid.com',
            x: -20
        },
        xAxis: {
            categories: categories,
            crosshair: true
        },
        yAxis: [{
            title: {
                text: '소득 ($)'
            },
            labels: {
                format: '{value} $'
            }
        }],
        tooltip: {
            shared: true // 한 로우에 여러 컬럼의 값을 표시
        },
        legend: {
            enabled : false
        },
        series: [{
            name: "GDP",
            data: provider.getFieldValues("GDP"),
            tooltip: {
                valueSuffix: "$ ($100 million)"
            }
        }, {
            name: "GNI",
            data: provider.getFieldValues("GNI"),
            tooltip: {
                valueSuffix: "$ ($100 million)"
            }
        }, {
            name: "PGNI",
            data: provider.getFieldValues("PGNI"),
            tooltip: {
                valueSuffix: "$"
            }
        }, {
            name: "DIncome",
            data: emptyValue("DIncome"),
            tooltip: {
                valueSuffix: "$"
            }
        }],
        chart: {
            type: 'column',
            events: {
                load: function () {
                    var chart = $("#highcharts").highcharts();
                    $.each(chart.series, function () {
                    	setColumnColor(this.name, this.color, true);
                    });
                }
            }
        }
    });
}

emptyValue

RealGrid는 로드한 데이터에 빈값은 undefined로 저장되어 있습니다. 하지만 HighCharts는 undefined값을 빈값으로 인지하지 않아 null로 변경해줘야 합니다.
빈값이 허용된 필드인 경우 emptyValue함수로 undefined값을 null값으로 변경합니다.

function emptyValue(fieldName){
	var fieldValues = dataProvider.getFieldValues(fieldName);
	$.each(fieldValues, function (k, v) {
        if (v == undefined)
            fieldValues[k] = null;
    });
    return fieldValues;
}

setColumnColor

그리드화면을 좀 더 직관적으로 보기위해 활성화된 Highcharts의 컬럼색상과 그리드 컬럼의 body 배경색을 매칭하는 소스입니다.

function setColumnColor(name, color, check) {
    var col = gridView.columnByName(name);
    //그리드의 색상은 8자리로 지정. (ex:'#aarrggbb') aa에 opacity값을 지정하기위해 replace.
    col.styles = check ? { background: color.replace("#", "#39") } : { background: "" };
    gridView.setColumn(col);
}

LocalDataProvider.onRowUpdated()

onRowUpdated()는 그리드의 데이터를 변경 하였을때 호출되는 콜백 함수로 변동된 데이터를 HighCharts와 연계하기 위해 사용합니다.

dataProvider.onRowUpdated = function (provider, row) {
	var chart = $("#highcharts").highcharts();
	$.each(chart.series, function() {
		if(this.name == "Year") return true;  //year필드는 countinue.
		var fieldValues = emptyValue(this.name);
		this.setData(fieldValues);
	});
}
컬럼의 CheckBox에 체크된 데이터만 HighCharts에 표시하기

GridBase.onColumnCheckedChanged()

컬럼의 checkbox선택/해제하였을때 호출되는 콜백 함수인 onColumnCheckedChanged()에 Highcharts의 컬럼을 숨기거나 보이게하는 기능은 연계합니다.
highcharts.series[i].setVisible 함수를 사용하여 highcharts의 컬럼의 display를 설정할 수 있습니다.

gridView.onColumnCheckedChanged = function (grid, column, checked) {
    var colName = column.name;
    var chart = $("#highcharts").highcharts();
    $.each(chart.series, function () {
        if (this.name === colName) {
            this.setVisible(checked);
            setColumnColor(this.name, this.color, checked);
        }
    });
}

실습

  1. 이번 강좌에서는 HighCharts의 category 값은 변경치 않도록 하겠습니다. Year컬럼을 편집불가로 설정합니다.

     var column = [{
         name: "Year",
         fieldName: "Year",
         width: "50",
         styles: {
             textAlignment: "center"
         },
         header: {
             text: "Year"
         },
         editable : false  //편집불가
     },{
     ...
     
  2. 컬럼에 checkbox를 사용하기 위해 column.header.checkLocation을 설정하고 checkbox의 초기값을 checked로 설정하겠습니다.

     var columns = [{
     ...
     }, {
         name: "GDP",
         fieldName: "GDP",
         width: "130",
         styles: {
             textAlignment: "far",
             numberFormat: "#,##0"
         },
         header: {
             text: "GDP ($100 milion)",
             checkLocation : "left" // 기본값은 none으로 none외에 값으로 지정시 checkbox가 보여진다.
         },
         checked: true // checked
     }, {
     ...
     
  3. 이벤트에 필요한 코드를 추가합니다.

     gridView.onColumnCheckedChanged = function (grid, column, checked) {
         var colName = column.name;
         var chart = $("#highcharts").highcharts();
         $.each(chart.series, function () {
             if (this.name === colName) {
                 this.setVisible(checked);
                 setColumnColor(this.name, this.color, checked);
             }
         });
     }
        
     dataProvider.onRowUpdated = function (provider, row) {
     	var chart = $("#highcharts").highcharts();
     	$.each(chart.series, function() {
     		if(this.name == "Year") return true;
     		var fieldValues = emptyValue(this.name);
     		this.setData(fieldValues);
     	});
     }
     
  4. 데이타 로드 후 HighCharts를 setup합니다.

     dataProvider.fillJsonData(data);
     setHiChart(dataProvider);

실행화면

  1. RealGrid column.headercheckbox선택/해제 합니다.

  2. checkboxchecked, unchecked됨에 따라 highcharts의 컬럼이 보여지거나 숨겨지는걸 확인하세요.

  3. 그리드의 데이터를 변경 후 HighCharts의 그래프가 변동되는 걸 확인하세요.

전체 소스코드

SCRIPT
<link rel="stylesheet" href="/css/bootstrap.css">
<script type="text/javascript" src="/script/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="/script/bootstrap.min.js"></script>
<!--realgrid-->
<script type="text/javascript" src="/script/realgridjs-lic.js"></script>
<script type="text/javascript" src="/script/realgridjs_eval.1.0.14.min.js"></script>
<script type="text/javascript" src="/script/realgridjs-api.1.0.14.js"></script>
<!--highcharts-->
<script type="text/javascript" src="/script/highcharts.js"></script>
<script>
var gridView;
var dataProvider;
    
$(document).ready( function() {

    RealGridJS.setTrace(false);
    RealGridJS.setRootContext("/script");
    
    dataProvider = new RealGridJS.LocalDataProvider();
    gridView = new RealGridJS.GridView("realgrid");
    gridView.setDataSource(dataProvider);
 	
 	//다섯 개의 필드를 가진 배열 객체를 생성합니다.
    var fields = [{
        fieldName: "Year"
    }, {
        fieldName: "GDP",
        dataType: "number"
    }, {
        fieldName: "GNI",
        dataType: "number"
    }, {
        fieldName: "PGNI",
        dataType: "number"
    }, {
        fieldName: "DIncome",
        dataType: "number"
    }];
    dataProvider.setFields(fields);
    
    //필드와 연결된 컬럼을 가진 배열 객체를 생성합니다.
    var columns = [{
        name: "Year",
        fieldName: "Year",
        width: "50",
        styles: {
            textAlignment: "center"
        },
        header: {
            text: "Year"
        },
        editable : false //편집불가
    }, {
        name: "GDP",
        fieldName: "GDP",
        width: "130",
        styles: {
            textAlignment: "far",
            numberFormat: "#,##0"
        },
        header: {
            text: "GDP ($100 milion)",
            checkLocation : "left"	// 기본값은 none으로 none외에 값으로 지정시 checkbox가 보여진다.
        },
        checked: true	// checked
 
    }, {
        name: "GNI",
        fieldName: "GNI",
        width: "130",
        styles: {
            textAlignment: "far",
            numberFormat: "#,##0"
        },
        header: {
            text: "GNI ($100 milion)",
            checkLocation: "left"
        },
        checked: true
    }, {
        name: "PGNI",
        fieldName: "PGNI",
        width: "120",
        styles: {
            textAlignment: "far",
            numberFormat: "#,##0"
        },
        header: {
            text: "PGNI ($)",
            checkLocation: "left"
        },
        checked: true
    }, {
        name: "DIncome",
        fieldName: "DIncome",
        width: "120",
        styles: {
            textAlignment: "far",
            numberFormat: "#,##0"
        },
        header: {
            text: "DIncome ($)",
            checkLocation: "left"
        },
        checked: true
    }];
    gridView.setColumns(columns);
    
    gridView.onColumnCheckedChanged = function (grid, column, checked) {
        var colName = column.name;
        var chart = $("#highcharts").highcharts();
        $.each(chart.series, function () {
            if (this.name === colName) {
                this.setVisible(checked);
                setColumnColor(this.name, this.color, checked);
            }
        });
    }
    
    dataProvider.onRowUpdated = function (provider, row) {
    	var chart = $("#highcharts").highcharts();
    	$.each(chart.series, function() {
    		if(this.name == "Year") return true;	//year필드는 countinue.
    		var fieldValues = emptyValue(this.name);
    		this.setData(fieldValues);
    	});
    }
    
	var data = [{"Year":"2008","GDP":9309,"GNI":9379,"PGNI":19161}
	,{"Year":"2009","GDP":8344,"GNI":8381,"PGNI":17041,"DIncome":10057}
	,{"Year":"2010","GDP":10147,"GNI":10160,"PGNI":20562,"DIncome":11796}
	,{"Year":"2011","GDP":11147,"GNI":11176,"PGNI":22451,"DIncome":12906}
	,{"Year":"2012","GDP":11292,"GNI":11355,"PGNI":22708,"DIncome":13150}];
    dataProvider.fillJsonData(data);
    
    setHiChart(dataProvider);
});
 
function setHiChart(provider) {
    var categories = provider.getFieldValues("year");
    var diVal = emptyValue("DIncome"); 
 
    $('#highcharts').highcharts({
        title: {
            text: '통계청 총생산소득',
            x: -20
        },
        subtitle: {
            text: 'www.realgrid.com',
            x: -20
        },
        xAxis: {
            categories: categories,
            crosshair: true
        },
        yAxis: [{
            title: {
                text: '소득 ($)'
            },
            labels: {
                format: '{value} $'
            }
        }],
        tooltip: {
            shared: true // 한 로우에 여러 컬럼의 값을 표시
        },
        legend: {
            enabled : false
        },
        series: [{
            name: "GDP",
            data: provider.getFieldValues("GDP"),
            tooltip: {
                valueSuffix: "$ ($100 million)"
            }
        }, {
            name: "GNI",
            data: provider.getFieldValues("GNI"),
            tooltip: {
                valueSuffix: "$ ($100 million)"
            }
        }, {
            name: "PGNI",
            data: provider.getFieldValues("PGNI"),
            tooltip: {
                valueSuffix: "$"
            }
        }, {
            name: "DIncome",
            data: diVal,
            tooltip: {
                valueSuffix: "$"
            }
        }],
        chart: {
            type: 'column',
            events: {
                load: function () {
                    var chart = $("#highcharts").highcharts();
                    $.each(chart.series, function () {
                    	setColumnColor(this.name, this.color, true);
                    });
                }
            }
        }
    });
}
 
function setColumnColor(name, color, check) {
    var col = gridView.columnByName(name);
    //그리드의 색상은 8자리로 지정. (ex:'#aarrggbb') aa에 opacity값을 지정하기위해 replace.
    col.styles = check ? { background: color.replace("#", "#39") } : { background: "" };
    gridView.setColumn(col);
}
 
function emptyValue(fieldName){
	var fieldValues = dataProvider.getFieldValues(fieldName);
	$.each(fieldValues, function (k, v) {
        if (v == undefined)
            fieldValues[k] = null;
    });
    return fieldValues;
}
<script>

</script>
HTML
<div id="highcharts" style="width: 100%; height: 200px;"></div>
<div id="realgrid" style="width: 100%; height: 200px;"></div>

관련 데모 페이지


API 참조