- visualization의 버전 1.0 을 명시하고 사용할 차트 패키지를 설정한다. 보통 corechart 로 하면 bar, line, pie등을 사용할 수 있다
  - anuglar의 controller에서 하기와 같이 json형태로 정의 가능. 또는 addColumn() 호출 설정방식중 택일
  - 높이는 px(pixel) 단위이다.
  - Formatters 에는 arrow, bar, color, date, number 등이 있고, 주로 table에서 사용된다. 단, color는 차트에서도 사용됨 (참조)
/**
 * @description Google Chart Api Directive Module for AngularJS
 * @version 0.0.9
 * @author Nicolas Bouillon <nicolas@bouil.org>
 * @author GitHub contributors
 * @moidifier Peter Yun <nulpulum@gmail.com>
 * @license MIT
 * @year 2013
 */
(function (document, window, angular) {
    'use strict';
    angular.module('googlechart', [])
        .constant('googleChartApiConfig', {
            version: '1.0',
            optionalSettings: {
                packages: ['corechart']
            }
        })
        /**
         * 인코딩 주의)
         * index.html 안에 UTF-8 설정
         * <meta http-equiv="content-type" content="text/html; charset=UTF-8">
         *
         * 사용예)
         * <script type="text/javascript" src="https://www.google.com/jsapi"></script>
         * <script type="text/javascript">
         *   google.load('visualization', '1.0', {'packages':['corechart']});
         *   google.setOnLoadCallback(drawChart);
         *   function drawChart() { ... }
         * </script>
         *
         * @변경 : jsapi.js 파일을 로컬에서 읽어오도록 수정할 수 있다
         * googleJsapiUrlProvider.setProtocol(undiefined);
         * googleJsapiUrlProvider.setUrl('jsapi.js');
         *
         * @참조 : https://google-developers.appspot.com/chart/interactive/docs/quick_start
         */
        .provider('googleJsapiUrl', function () {
            var protocol = 'https:';
            var url = '//www.google.com/jsapi';
            this.setProtocol = function(newProtocol) {
                protocol = newProtocol;
            };
            this.setUrl = function(newUrl) {
                url = newUrl;
            };
            this.$get = function() {
                return (protocol ? protocol : '') + url;
            };
        })
        /**
         * google.load('visualization', '1.0', {'packages':['corechart']}); 수행하는 팩토리
         *
         * @param  {[type]} $rootScope     [description]
         * @param  {[type]} $q             [description]
         * @param  {[type]} apiConfig      [description]
         * @param  {[type]} googleJsapiUrl [description]
         * @return {[type]}                [description]
         */
        .factory('googleChartApiPromise', ['$rootScope', '$q', 'googleChartApiConfig', 'googleJsapiUrl', function ($rootScope, $q, apiConfig, googleJsapiUrl) {
            var apiReady = $q.defer();
            var onLoad = function () {
                // override callback function
                var settings = {
                    callback: function () {
                        var oldCb = apiConfig.optionalSettings.callback;
                        $rootScope.$apply(function () {
                            apiReady.resolve();
                        });
                        if (angular.isFunction(oldCb)) {
                            oldCb.call(this);
                        }
                    }
                };
                settings = angular.extend({}, apiConfig.optionalSettings, settings);
                window.google.load('visualization', apiConfig.version, settings);
            };
            var head = document.getElementsByTagName('head')[0];
            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.src = googleJsapiUrl;
            if (script.addEventListener) { // Standard browsers (including IE9+)
                //console.log('>>> 1. load jsapi...');
                script.addEventListener('load', onLoad, false);
            } else { // IE8 and below
                //console.log('>>> 2. load jsapi...');
                script.onreadystatechange = function () {
                    if (script.readyState === 'loaded' || script.readyState === 'complete') {
                        script.onreadystatechange = null;
                        onLoad();
                    }
                };
            }
            head.appendChild(script);
            return apiReady.promise;
        }])
        /**
         * Element 또는 Attribute로 사용할 수 있다. Element 사용시에는 IE8+에 대한 고려가 있어야 함
         *
         * 사용예)
         * <div google-chart chart="chartObject" style="height:300px; width:100%;"></div>
         *
         * @param  {[type]} $timeout              [description]
         * @param  {[type]} $window               [description]
         * @param  {[type]} $rootScope            [description]
         * @param  {[type]} googleChartApiPromise [description]
         * @return {[type]}                       [description]
         */
        .directive('googleChart', ['$timeout', '$window', '$rootScope', 'googleChartApiPromise', function ($timeout, $window, $rootScope, googleChartApiPromise) {
            return {
                restrict: 'EA',
                scope: {
                    chartOrig: '=chart',
                    onReady: '&',
                    select: '&'
                },
                link: function ($scope, $elm, attrs) {
                    // Watches, to refresh the chart when its data, title or dimensions change
                    $scope.$watch('chartOrig', function () {
						$scope.chart = angular.copy($scope.chartOrig);
                        drawAsync();
                    }, true); // true is for deep object equality checking
                    // Redraw the chart if the window is resized
                    $rootScope.$on('resizeMsg', function () {
                        $timeout(function () {
                            // Not always defined yet in IE so check
                            if($scope.chartWrapper) {
                                drawAsync();
                            }
                        });
                    });
                    // Keeps old formatter configuration to compare against
                    $scope.oldChartFormatters = {};
                    function applyFormat(formatType, formatClass, dataTable) {
                        var i, cIdx;
                        if (typeof($scope.chart.formatters[formatType]) != 'undefined') {
                            if (!angular.equals($scope.chart.formatters[formatType], $scope.oldChartFormatters[formatType])) {
                                $scope.oldChartFormatters[formatType] = $scope.chart.formatters[formatType];
                                $scope.formatters[formatType] = [];
                                if (formatType === 'color') {
                                    for (cIdx = 0; cIdx < $scope.chart.formatters[formatType].length; cIdx++) {
                                        var colorFormat = new formatClass();
                                        for (i = 0; i < $scope.chart.formatters[formatType][cIdx].formats.length; i++) {
                                            var data = $scope.chart.formatters[formatType][cIdx].formats[i];
                                            if (typeof(data.fromBgColor) != 'undefined' && typeof(data.toBgColor) != 'undefined')
                                                colorFormat.addGradientRange(data.from, data.to, data.color, data.fromBgColor, data.toBgColor);
                                            else
                                                colorFormat.addRange(data.from, data.to, data.color, data.bgcolor);
                                        }
                                        $scope.formatters[formatType].push(colorFormat)
                                    }
                                } else {
                                    for (i = 0; i < $scope.chart.formatters[formatType].length; i++) {
                                        $scope.formatters[formatType].push(new formatClass(
                                            $scope.chart.formatters[formatType][i])
                                        );
                                    }
                                }
                            }
                            //apply formats to dataTable
                            for (i = 0; i < $scope.formatters[formatType].length; i++) {
                                if ($scope.chart.formatters[formatType][i].columnNum < dataTable.getNumberOfColumns())
                                    $scope.formatters[formatType][i].format(dataTable, $scope.chart.formatters[formatType][i].columnNum);
                            }
                            //Many formatters require HTML tags to display special formatting
                            if (formatType === 'arrow' || formatType === 'bar' || formatType === 'color')
                                $scope.chart.options.allowHtml = true;
                        }
                    }
                    function draw() {
                        // 그리고 있는중에는 다시 그리기 안함
                        if (!draw.triggered && ($scope.chart != undefined)) {
                            draw.triggered = true;
                            // ref: https://docs.angularjs.org/api/ng/service/$timeout
                            $timeout(function () {
                                if (typeof($scope.formatters) === 'undefined')
                                    $scope.formatters = {};
                                var dataTable;
                                if ($scope.chart.data instanceof google.visualization.DataTable)
                                    dataTable = $scope.chart.data;
                                else if (angular.isArray($scope.chart.data))
                                    dataTable = google.visualization.arrayToDataTable($scope.chart.data);
                                else
                                    dataTable = new google.visualization.DataTable($scope.chart.data, 0.5);
                                if (typeof($scope.chart.formatters) != 'undefined') {
                                    applyFormat("number", google.visualization.NumberFormat, dataTable);
                                    applyFormat("arrow", google.visualization.ArrowFormat, dataTable);
                                    applyFormat("date", google.visualization.DateFormat, dataTable);
                                    applyFormat("bar", google.visualization.BarFormat, dataTable);
                                    applyFormat("color", google.visualization.ColorFormat, dataTable);
                                }
                                var customFormatters = $scope.chart.customFormatters;
                                if (typeof(customFormatters) != 'undefined') {
                                    for (var name in customFormatters) {
                                        applyFormat(name, customFormatters[name], dataTable);
                                    }
                                }
								
				// resize > 0 이상이면 적용됨  
				// by peter yun
 // <div style="height:100%" id="gc"> 
 //	<div google-chart chart="chartObject" resize="#gc" style="width:100%;"></div>
 // </div>
			 var height = angular.element(attrs.resize).height();
			       if(height) {
					$scope.chart.options.height = height;
			       }
                                var chartWrapperArgs = {
                                    chartType: $scope.chart.type,
                                    dataTable: dataTable,
                                    view: $scope.chart.view,
                                    options: $scope.chart.options,
                                    containerId: $elm[0]
                                };
                                $scope.chartWrapper = new google.visualization.ChartWrapper(chartWrapperArgs);
                                google.visualization.events.addListener($scope.chartWrapper, 'ready', function () {
                                    $scope.chart.displayed = true;
                                    $scope.$apply(function (scope) {
                                        scope.onReady({chartWrapper: scope.chartWrapper});
                                    });
                                });
                                google.visualization.events.addListener($scope.chartWrapper, 'error', function (err) {
                                    console.log("Chart not displayed due to error: " + err.message + ". Full error object follows.");
                                    console.log(err);
                                });
                                google.visualization.events.addListener($scope.chartWrapper, 'select', function () {
                                    var selectedItem = $scope.chartWrapper.getChart().getSelection()[0];
                                    $scope.$apply(function () {
                                        $scope.select({selectedItem: selectedItem});
                                    });
                                });
                                $timeout(function () {
                                    $elm.empty();
                                    $scope.chartWrapper.draw();
					draw.triggered = false;
                                });
                            }, 0, true);
                        }
                    }
                    /**
                     * jsapi의 load가 끝나면 draw하도록 promise를 걸어 놓은 것
                     *
                     * @return {[type]} [description]
                     */
                    function drawAsync() {
                        googleChartApiPromise.then(function () {
                            draw();
                        })
                    }
                }
            };
        }])
        /**
         * window즉 브라우져의 사이즈가 변경되면 google chart의 size를 변경토록 한다. 단 html설정에서 다음과 같이 되어야 한다
         * <div google-chart chart="chartObject" style="height:300px; width:100%;"></div>
         * height는 %가 아니라 자신이 속한 parent dive의 height를 따르도록 해주어야 한다
         *
         * @param  {[type]} $rootScope [description]
         * @param  {[type]} $window    [description]
         * @return {[type]}            [description]
         */
        .run(['$rootScope', '$window', function ($rootScope, $window) {
            angular.element($window).bind('resize', function () {
                $rootScope.$emit('resizeMsg');
            });
        }]);
})(document, window, window.angular);