angular-chart-morris
Version:
[](https://travis-ci.org/st1s/angular-morris) [](http://commitizen.github.io/cz-cli/)
381 lines (348 loc) • 19 kB
JavaScript
(function () {
'use strict';
/**
* @ngdoc object
* @name angular.morris.chart
**/
angular.module('angular.morris.chart', []);
})();
(function () {
'use strict';
/**
* @ngdoc object
* @name angular.morris.chart.factory
* @description
* Utility functions
**/
angular.module('angular.morris.chart').factory('angularMorris', /*@ngInject*/ function angularMorris($injector) {
var s = {
/**
* Takes a morris.js option key and converts it to an attribute name.
* @param prefix {string}
* @param key {string}
* @returns {string}
*/
keyToAttr: function (prefix, key) {
return prefix + key.substring(0, 1).toUpperCase() + key.substring(1);
},
/**
* Populates a directive scope definition object from a given set of option keys
* @param scopeDefinition {object}
* @param prefix {string}
* @param optionKeys {string[]}
* @param [atKey] {string}
* @returns {object}
*/
populateScopeDefinition: function (scopeDefinition, prefix, optionKeys, atKey) {
angular.forEach(optionKeys, function (key) {
// Prefix the option key
scopeDefinition[s.keyToAttr(prefix, key)] = key === atKey ? '@' : '=';
});
return scopeDefinition;
},
/**
* Populates an options object for a Morris chart using a set of option keys and a scope object.
* @param options {object}
* @param optionKeys {string[]}
* @param prefix {string}
* @param scope {object}
* @returns {object}
*/
populateOptions: function (options, optionKeys, prefix, scope) {
// Apply known optons from morris.js doco
angular.forEach(optionKeys, function (key) {
var attrKey = s.keyToAttr(prefix, key);
if (scope.hasOwnProperty(attrKey) && typeof scope[attrKey] !== 'undefined') {
options[key] = scope[attrKey];
}
});
return options;
},
/**
* Tries to apply certain options as names for angular filters
* @param filterKeys {string[]}
* @param options {object}
*/
processFilterOptions: function (filterKeys, options) {
angular.forEach(filterKeys, function (key) {
// If the formatter is a string, check for a matching filter
if (typeof options[key] === 'string' && $injector.has(options[key] + 'Filter')) {
var filter = $injector.get(options[key] + 'Filter');
options[key] = function (input) {
return filter.call(this, input);
};
}
});
}
};
return s;
});
})();
;
/* global Morris */
(function () {
angular.module("angular.morris.chart").directive('areaChart',
/*@ngInject*/function (angularMorris) {
// List of known option keys for areaChart according to morris.js docs:
// http://morrisjs.github.io/morris.js/lines.html
var OPTION_KEYS = [
'data', 'xkey', 'ykeys', 'labels', 'lineColors', 'lineWidth', 'pointSize',
'pointFillColors', 'pointStrokeColors', 'ymax', 'ymin', 'smooth', 'hideHover',
'hoverCallback', 'parseTime', 'units', 'postUnits', 'preUnits', 'dateFormat',
'xLabels', 'xLabelFormat', 'xLabelAngle', 'yLabelFormat', 'goals', 'goalStrokeWidth',
'goalLineColors', 'events', 'eventStrokeWidth', 'eventLineColors', 'continuousLine',
'axes', 'grid', 'gridTextColor', 'gridTextSize', 'gridTextFamily', 'gridTextWeight',
'fillOpacity', 'resize', 'behaveLikeLine'
];
return {
restrict: 'A',
scope: angularMorris.populateScopeDefinition({ lineColors: '=' }, 'area', OPTION_KEYS, 'xkey'),
link: function (scope, elem) {
scope.$watchCollection('areaData', function (nv, ov) {
if (scope.areaData) {
if (typeof scope.areaData === 'string')
scope.areaData = JSON.parse(scope.areaData);
if (typeof scope.areaYkeys === 'string')
scope.areaYkeys = JSON.parse(scope.areaYkeys);
if (typeof scope.areaLabels === 'string')
scope.areaLabels = JSON.parse(scope.areaLabels);
if (typeof scope.lineColors === 'string')
scope.lineColors = JSON.parse(scope.lineColors);
if (!scope.areaInstance) {
// Generate Morris chart options
var options = angularMorris.populateOptions({
element: elem,
lineColors: scope.lineColors || ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed']
}, OPTION_KEYS, 'area', scope);
// Checks if there are angular filters available for certain options
angularMorris.processFilterOptions(['dateFormat', 'xLabelFormat', 'yLabelFormat'], options);
scope.areaInstance = new Morris.Area(options);
} else {
scope.areaInstance.setData(scope.areaData);
}
}
}, true);
}
}
});
})();
;
/* global Morris */
(function () {
angular.module("angular.morris.chart").directive('barChart', /*@ngInject*/function (angularMorris) {
// List of known option keys for barChart according to morris.js docs:
// http://morrisjs.github.io/morris.js/bars.html
var OPTION_KEYS = [
'data', 'xkey', 'ykeys', 'labels', 'barColors', 'stacked', 'hideHover',
'hoverCallback', 'axes', 'grid', 'gridTextColor', 'gridTextSize', 'gridTextFamily',
'gridTextWeight', 'resize',
// In spite of being missing in the documentation, these do exist
// They are part of the base grid: https://github.com/morrisjs/morris.js/blob/master/lib/morris.grid.coffee
'ymax', 'ymin', 'goals', 'goalStrokeWidth',
'goalLineColors', 'yLabelAlign', 'parseTime', 'postUnits', 'preUnits',
'xLabelAngle', 'yLabelFormat', 'events', 'eventStrokeWidth', 'eventLineColors'
];
return {
restrict: 'A',
scope: angularMorris.populateScopeDefinition({ barLabels: '=' , barColors: '=', barX: '@', barY: '=' }, 'bar', OPTION_KEYS),
link: function (scope, elem) {
scope.$watchCollection('barLabels', function (newData, oldData) {
if(!scope.barInstance) return
scope.barInstance.options.labels = newData;
setData(scope.barData)
})
scope.$watchCollection('barColors', function (newData, oldData) {
if(!scope.barInstance) return
scope.barInstance.options.barColors = newData;
setData(scope.barData)
})
scope.$watchCollection('barY', function (newData, oldData) {
if(!scope.barInstance) return
scope.barInstance.options.ykeys = newData;
setData(scope.barData)
})
scope.$watchCollection('barData', function (nv, ov) {
if (scope.barData) {
if (typeof scope.barY === 'string')
scope.barY = JSON.parse(scope.barY);
if (typeof scope.barLabels === 'string')
scope.barLabels = JSON.parse(scope.barLabels);
if (typeof scope.barData === 'string')
scope.barData = JSON.parse(scope.barData);
if (typeof scope.barColors === 'string')
scope.barColors = JSON.parse(scope.barColors);
if (typeof scope.barStacked === 'string')
scope.barStacked = JSON.parse(scope.barStacked);
if (typeof scope.barResize === 'string')
scope.barResize = JSON.parse(scope.barResize);
if (!scope.barInstance) {
// Default options
var options = angularMorris.populateOptions({
element: elem,
barColors: scope.barColors || ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
stacked: false,
resize: true,
xkey: scope.barX,
ykeys: scope.barY,
xLabelMargin: 1,
yLabelFormat: function(y){
if (y != Math.round(y)){
return '';
} else{
return y;
}
}
}, OPTION_KEYS, 'bar', scope);
scope.barInstance = new Morris.Bar(options);
} else {
setData(scope.barData)
}
}
}, true)
function setData(data){
scope.barInstance.setData(data);
}
}
}
})
})();
;
/* global Morris */
(function() {
angular.module("angular.morris.chart").directive('donutChart', /*@ngInject*/function(angularMorris) {
// List of known option keys for donutChart according to morris.js docs:
// http://morrisjs.github.io/morris.js/donuts.html
var OPTION_KEYS = ['data', 'colors', 'formatter', 'resize', 'backgroundColor', 'labelColor'];
return {
restrict: 'A',
scope: angularMorris.populateScopeDefinition({}, 'donut', OPTION_KEYS),
link: function(scope, elem) {
scope.$watch('donutData', function() {
if (scope.donutData) {
if (typeof scope.donutData === 'string')
scope.donutData = JSON.parse(scope.donutData);
if (typeof scope.donutColors === 'string')
scope.donutColors = JSON.parse(scope.donutColors);
if (!scope.donutInstance) {
// Generate Morris chart options
var options = angularMorris.populateOptions({
element: elem,
colors: ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed']
}, OPTION_KEYS, 'donut', scope);
// Checks if there are angular filters available for certain options
angularMorris.processFilterOptions(['formatter'], options);
scope.donutInstance = new Morris.Donut(options);
} else {
scope.donutInstance.setData(scope.donutData);
}
}
})
}
}
})
})();
;
/* global Morris */
(function () {
angular.module("angular.morris.chart").directive('lineChart', /*@ngInject*/function (angularMorris) {
// List of known option keys for lineChart according to morris.js docs:
// http://morrisjs.github.io/morris.js/lines.html
var OPTION_KEYS = [
'data', 'xkey', 'ykeys', 'labels', 'lineColors', 'lineWidth', 'pointSize',
'pointFillColors', 'pointStrokeColors', 'ymax', 'ymin', 'smooth', 'hideHover',
'hoverCallback', 'parseTime', 'units', 'postUnits', 'preUnits', 'dateFormat',
'xLabels', 'xLabelFormat', 'xLabelAngle', 'yLabelFormat', 'goals', 'goalStrokeWidth',
'goalLineColors', 'events', 'eventStrokeWidth', 'eventLineColors', 'continuousLine',
'axes', 'grid', 'gridTextColor', 'gridTextSize', 'gridTextFamily', 'gridTextWeight',
'fillOpacity', 'resize'
];
return {
restrict: 'A',
scope: angularMorris.populateScopeDefinition({ lineColors: '=', parseTime: '=', lineXkey: '=', lineYkeys: '=', lineLabels: '=' }, 'line', OPTION_KEYS, 'xkey', 'ykeys', 'colors', 'labels'),
link: function (scope, elem) {
scope.$watchCollection('lineLabels', function (newData, oldData) {
if(!scope.lineInstance) return
scope.lineInstance.options.labels = newData;
setData(scope.lineData)
})
scope.$watchCollection('lineColors', function (newData, oldData) {
if(!scope.lineInstance) return
scope.lineInstance.options.lineColors = newData;
setData(scope.lineData)
})
scope.$watchCollection('lineYkeys', function (newData, oldData) {
if(!scope.lineInstance) return
scope.lineInstance.options.ykeys = newData;
setData(scope.lineData)
})
scope.$watch('lineData', function () {
if (scope.lineData) {
if (typeof scope.lineData === 'string')
scope.lineData = JSON.parse(scope.lineData);
// this is causing scope changing issues
// if (typeof scope.lineXkey === 'string')
// scope.lineXkey = JSON.parse(scope.lineXkey);
// if (typeof scope.lineYkeys === 'string')
// scope.lineYkeys = JSON.parse(scope.lineYkeys);
if (typeof scope.lineLabels === 'string')
scope.lineLabels = JSON.parse(scope.lineLabels);
if (typeof scope.lineColors === 'string')
scope.lineColors = JSON.parse(scope.lineColors);
if (typeof scope.parseTime === 'boolean')
scope.parseTime = JSON.parse(scope.parseTime);
if (!scope.lineInstance) {
// Default options
var options = angularMorris.populateOptions({
element: elem,
xkey: scope.lineXkey,
ykeys: scope.lineYkeys,
trendLineColors: scope.lineColors,
resize: true,
lineColors: scope.lineColors || ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'],
xLabelFormat: function(d) {
var day=d.getDate(),
mounth=d.getMonth()+1;
return (day<10 ? '0' : '') + day + '.'+
(mounth<10 ? '0' : '') + mounth + '.' +
d.getFullYear();
},
xLabels:'day',
dateFormat: function (ts) {
var d= new Date(ts),
day = d.getDate(),
mounth=d.getMonth()+1,
year = d.getFullYear();
return (day<10 ? '0' : '') + day + '.'+
(mounth<10 ? '0' : '') + mounth + '.' +
year;
},
yLabelFormat: function(y){
if (y != Math.round(y)){
return '';
} else{
return y;
}
}
}, OPTION_KEYS, 'line', scope);
// Checks if there are angular filters available for certain options
angularMorris.processFilterOptions(['dateFormat','xLabelFormat', 'yLabelFormat'], options);
scope.lineInstance = new Morris.Line(options);
} else {
// this is causing scope changing issues
// scope.lineInstance.options.xkey = scope.lineXkey;
// scope.lineInstance.options.ykeys = scope.lineYkeys;
// scope.lineInstance.options.labels = scope.lineLabels;
// scope.lineInstance.options.preUnits = scope.linePreUnits;
// scope.lineInstance.options.postUnits = scope.linePostUnits;
// scope.lineInstance.options.parseTime = scope.parseTime;
// scope.lineInstance.options.lineColors = scope.lineColors || ['#0b62a4', '#7a92a3', '#4da74d', '#afd8f8', '#edc240', '#cb4b4b', '#9440ed'];
setData(scope.lineData) }
}
});
function setData(data){
scope.lineInstance.setData(data);
}
}
}
})
})();