<!DOCTYPE html>
<html ng-app="myApp">
<head>
<link rel="stylesheet" href="style.css">
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<!--script data-require="angular.js@1.2.x" src="https://code.angularjs.org/1.2.16/angular.js" data-semver="1.2.16"></script-->
<script src="http://cdn.staticfile.org/angular.js/1.2.6/angular.js"></script>
<script src="highcharts-ng.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="MyController">
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
<hr />
<highchart config="chartConfig" class="span10"></highchart>
</div>
</body>
</html>
var myApp = angular.module('myApp', ['highcharts-ng']);
myApp.controller('MyController', ['$scope', function($scope) {
var chartConfig = {
chart: {
type: 'column'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: {
min: 0,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -70,
verticalAlign: 'top',
y: 20,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
formatter: function() {
return '<b>'+ this.x +'</b><br/>'+
this.series.name +': '+ this.y +'<br/>'+
'Total: '+ this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black, 0 0 3px black'
}
}
}
},
series: [{
name: 'John',
data: [5, 3, 4, 7, 2]
}, {
name: 'Jane',
data: [2, 2, 3, 2, 1]
}, {
name: 'Joe',
data: [3, 4, 4, 2, 5]
}]
};
$scope.chartConfig = chartConfig;
$('#container').highcharts(chartConfig);
}]);
/* Styles go here */
//https://github.com/pablojim/highcharts-ng
'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(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
for(var i = chart.series.length - 1; i >= 0; i--) {
var s = chart.series[i];
if (ids.indexOf(s.options.id) < 0) {
s.remove(false);
}
};
}
var initialiseChart = function(scope, element, config) {
config || (config = {});
var mergedOptions = getMergedOptions(scope, element, config);
var chart = config.useHighStocks ? new Highcharts.StockChart(mergedOptions) : new Highcharts.Chart(mergedOptions);
if(config.xAxis) {
processExtremes(chart, config.xAxis);
}
processSeries(chart, config.series);
if(config.loading) {
chart.showLoading()
}
chart.redraw();
return chart;
}
return {
restrict: 'EAC',
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) {
chart.showLoading()
} else {
chart.hideLoading()
}
});
scope.$watch("config.useHighStocks", function (useHighStocks) {
chart.destroy();
chart = initialiseChart(scope, element, scope.config);
});
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);
}
}
});