aboutsummaryrefslogblamecommitdiff
path: root/kamon-dashboard/src/main/resources/web/js/highcharts-ng.js
blob: 19c25e28f3ae0adf2bf591fb21ce17e5299618d8 (plain) (tree)



























































































































































































                                                                                                        
'use strict';

angular.module('highcharts-ng', [])
    .directive('highchart', function () {

        function prependMethod(obj, method, func) {
            var original = obj[method];
            obj[method] = function () {
                var args = Array.prototype.slice.call(arguments);
                func.apply(this, args);
                if(original) {
                    return original.apply(this, args);
                }  else {
                    return;
                }

            };
        }

        function deepExtend(destination, source) {
            for (var property in source) {
                if (source[property] && source[property].constructor &&
                    source[property].constructor === Object) {
                    destination[property] = destination[property] || {};
                    deepExtend(destination[property], source[property]);
                } else {
                    destination[property] = source[property];
                }
            }
            return destination;
        }

        var seriesId = 0;
        var ensureIds = function (series) {
            series.forEach(function (s) {
                if (!angular.isDefined(s.id)) {
                    s.id = "series-" + seriesId++;
                }
            });
        }

        var defaultOptions = {
            chart: {
                events: {}
            },
            title: {},
            series: [],
            navigator: {enabled: false}
        }

        var getMergedOptions = function (scope, element, config) {
            var mergedOptions = {}
            if (config.options) {
                mergedOptions = deepExtend(defaultOptions, config.options);
            } else {
                mergedOptions = defaultOptions;
            }
            mergedOptions.chart.renderTo = element[0];
            if(scope.config.xAxis) {
                prependMethod(mergedOptions.chart.events, 'selection', function(e){
                    var thisChart = this;
                    if(e.xAxis) {
                        scope.$apply(function () {
                            scope.config.xAxis.currentMin = e.xAxis[0].min;
                            scope.config.xAxis.currentMax = e.xAxis[0].max;
                        });
                    } else {
                        //handle reset button - zoom out to all
                        scope.$apply(function () {
                            scope.config.xAxis.currentMin = thisChart.xAxis[0].dataMin;
                            scope.config.xAxis.currentMax = thisChart.xAxis[0].dataMax;
                        });
                    }
                });

                prependMethod(mergedOptions.chart.events, 'addSeries', function(e){
                    scope.config.xAxis.currentMin = this.xAxis[0].min || scope.config.xAxis.currentMin;
                    scope.config.xAxis.currentMax = this.xAxis[0].max || scope.config.xAxis.currentMax;
                });
            }

            if(config.xAxis) {
                mergedOptions.xAxis = angular.copy(config.xAxis)
            }
            if(config.title) {
                mergedOptions.title = config.title
            }
            return mergedOptions
        }

        var updateZoom = function (axis, modelAxis) {
            var extremes = axis.getExtremes();
            if(modelAxis.currentMin !== extremes.dataMin || modelAxis.currentMax !== extremes.dataMax) {
                axis.setExtremes(modelAxis.currentMin, modelAxis.currentMax, false);
            }
        }

        var processExtremes = function(chart, axis) {
            if(axis.currentMin || axis.currentMax) {
                chart.xAxis[0].setExtremes(axis.currentMin, axis.currentMax, true);
            }
        }

        var processSeries = function(chart, series) {
            var ids = []
            if(series) {
                ensureIds(series);

                //Find series to add or update
                series.forEach(function (s) {
                    ids.push(s.id)
                    var chartSeries = chart.get(s.id);
                    if (chartSeries) {
                        chartSeries.update(angular.copy(s), false);
                    } else {
                        chart.addSeries(angular.copy(s), false)
                    }
                });
            }

            //Now remove any missing series
            chart.series.forEach(function (s) {
                if (ids.indexOf(s.options.id) < 0) {
                    s.remove(false);
                }
            });
        }

        var initialiseChart = function(scope, element, config) {
            var mergedOptions = getMergedOptions(scope, element, config);
            var chart = new Highcharts.Chart(mergedOptions);
            if(config.xAxis) {
                processExtremes(chart, config.xAxis);
            }
            processSeries(chart, config.series);
            chart.redraw();
            return chart;
        }


        return {
            restrict: 'EC',
            replace: true,
            template: '<div></div>',
            scope: {
                config: '='
            },
            link: function (scope, element, attrs) {

                var chart = initialiseChart(scope, element, scope.config);

                scope.$watch("config.series", function (newSeries, oldSeries) {
                    //do nothing when called on registration
                    if (newSeries === oldSeries) return;
                    processSeries(chart, newSeries);
                    chart.redraw();
                }, true);

                scope.$watch("config.title", function (newTitle) {
                    chart.setTitle(newTitle, true);
                }, true);

                scope.$watch("config.loading", function (loading) {
                    if(loading === false) {
                        chart.hideLoading()
                    } else {
                        chart.showLoading()
                    }
                }, true);

                scope.$watch("config.xAxis", function (newAxes, oldAxes) {
                    if (newAxes === oldAxes) return;
                    if(newAxes) {
                        chart.xAxis[0].update(newAxes);
                        updateZoom(chart.xAxis[0], angular.copy(newAxes));
                        chart.redraw();
                    }
                }, true);
                scope.$watch("config.options", function (newOptions, oldOptions, scope) {
                    //do nothing when called on registration
                    if (newOptions === oldOptions) return;
                    chart.destroy();
                    chart = initialiseChart(scope, element, scope.config);

                }, true);
            }
        }
    });