diff --git a/www/js/vendor/Chart.js b/www/js/vendor/Chart.js
index 4f896dba11a1d641ef88e2f9663288e958493147..0825ec7b53f52fb4dd425b898277e1135f4d04b4 100644
--- a/www/js/vendor/Chart.js
+++ b/www/js/vendor/Chart.js
@@ -1,7 +1,7 @@
 /*!
  * Chart.js
  * http://chartjs.org/
- * Version: 2.7.0
+ * Version: 2.7.1
  *
  * Copyright 2017 Nick Downie
  * Released under the MIT license
@@ -4060,6 +4060,14 @@ module.exports = function(Chart) {
 
 			me.updateDatasets();
 
+			// Need to reset tooltip in case it is displayed with elements that are removed
+			// after update.
+			me.tooltip.initialize();
+
+			// Last active contains items that were previously in the tooltip.
+			// When we reset the tooltip, we need to clear it
+			me.lastActive = [];
+
 			// Do this before render so that any plugins that need final scale updates can use it
 			plugins.notify(me, 'afterUpdate');
 
@@ -4217,9 +4225,7 @@ module.exports = function(Chart) {
 			}
 
 			me.drawDatasets(easingValue);
-
-			// Finally draw the tooltip
-			me.tooltip.draw();
+			me._drawTooltip(easingValue);
 
 			plugins.notify(me, 'afterDraw', [easingValue]);
 		},
@@ -4284,6 +4290,28 @@ module.exports = function(Chart) {
 			plugins.notify(me, 'afterDatasetDraw', [args]);
 		},
 
+		/**
+		 * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
+		 * hook, in which case, plugins will not be called on `afterTooltipDraw`.
+		 * @private
+		 */
+		_drawTooltip: function(easingValue) {
+			var me = this;
+			var tooltip = me.tooltip;
+			var args = {
+				tooltip: tooltip,
+				easingValue: easingValue
+			};
+
+			if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
+				return;
+			}
+
+			tooltip.draw();
+
+			plugins.notify(me, 'afterTooltipDraw', [args]);
+		},
+
 		// Get the single element that was clicked on
 		// @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
 		getElementAtEvent: function(e) {
@@ -5040,16 +5068,6 @@ module.exports = function(Chart) {
 
 	// -- Basic js utility methods
 
-	helpers.extend = function(base) {
-		var setFn = function(value, key) {
-			base[key] = value;
-		};
-		for (var i = 1, ilen = arguments.length; i < ilen; i++) {
-			helpers.each(arguments[i], setFn);
-		}
-		return base;
-	};
-
 	helpers.configMerge = function(/* objects ... */) {
 		return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
 			merger: function(key, target, source, options) {
@@ -5155,29 +5173,7 @@ module.exports = function(Chart) {
 			}
 		}
 	};
-	helpers.inherits = function(extensions) {
-		// Basic javascript inheritance based on the model created in Backbone.js
-		var me = this;
-		var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
-			return me.apply(this, arguments);
-		};
 
-		var Surrogate = function() {
-			this.constructor = ChartElement;
-		};
-		Surrogate.prototype = me.prototype;
-		ChartElement.prototype = new Surrogate();
-
-		ChartElement.extend = helpers.inherits;
-
-		if (extensions) {
-			helpers.extend(ChartElement.prototype, extensions);
-		}
-
-		ChartElement.__super__ = me.prototype;
-
-		return ChartElement;
-	};
 	// -- Math methods
 	helpers.isNumber = function(n) {
 		return !isNaN(parseFloat(n)) && isFinite(n);
@@ -5882,7 +5878,7 @@ module.exports = {
 		 * @private
 		 */
 		'x-axis': function(chart, e) {
-			return indexMode(chart, e, {intersect: true});
+			return indexMode(chart, e, {intersect: false});
 		},
 
 		/**
@@ -6797,6 +6793,27 @@ module.exports = function(Chart) {
 	 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
 	 * @param {Object} options - The plugin options.
 	 */
+	/**
+  	 * @method IPlugin#beforeTooltipDraw
+	 * @desc Called before drawing the `tooltip`. If any plugin returns `false`,
+	 * the tooltip drawing is cancelled until another `render` is triggered.
+	 * @param {Chart} chart - The chart instance.
+	 * @param {Object} args - The call arguments.
+	 * @param {Object} args.tooltip - The tooltip.
+	 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
+	 * @param {Object} options - The plugin options.
+	 * @returns {Boolean} `false` to cancel the chart tooltip drawing.
+  	 */
+	/**
+ 	 * @method IPlugin#afterTooltipDraw
+  	 * @desc Called after drawing the `tooltip`. Note that this hook will not
+ 	 * be called if the tooltip drawing has been previously cancelled.
+ 	 * @param {Chart} chart - The chart instance.
+ 	 * @param {Object} args - The call arguments.
+ 	 * @param {Object} args.tooltip - The tooltip.
+	 * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
+ 	 * @param {Object} options - The plugin options.
+ 	 */
 	/**
 	 * @method IPlugin#beforeEvent
  	 * @desc Called before processing the specified `event`. If any plugin returns `false`,
@@ -7388,17 +7405,33 @@ module.exports = function(Chart) {
 			return rawValue;
 		},
 
-		// Used to get the value to display in the tooltip for the data at the given index
-		// function getLabelForIndex(index, datasetIndex)
+		/**
+		 * Used to get the value to display in the tooltip for the data at the given index
+		 * @param index
+		 * @param datasetIndex
+		 */
 		getLabelForIndex: helpers.noop,
 
-		// Used to get data value locations.  Value can either be an index or a numerical value
+		/**
+		 * Returns the location of the given data point. Value can either be an index or a numerical value
+		 * The coordinate (0, 0) is at the upper-left corner of the canvas
+		 * @param value
+		 * @param index
+		 * @param datasetIndex
+		 */
 		getPixelForValue: helpers.noop,
 
-		// Used to get the data value from a given pixel. This is the inverse of getPixelForValue
+		/**
+		 * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
+		 * The coordinate (0, 0) is at the upper-left corner of the canvas
+		 * @param pixel
+		 */
 		getValueForPixel: helpers.noop,
 
-		// Used for tick location, should
+		/**
+		 * Returns the location of the tick at the given index
+		 * The coordinate (0, 0) is at the upper-left corner of the canvas
+		 */
 		getPixelForTick: function(index) {
 			var me = this;
 			var offset = me.options.offset;
@@ -7419,7 +7452,10 @@ module.exports = function(Chart) {
 			return me.top + (index * (innerHeight / (me._ticks.length - 1)));
 		},
 
-		// Utility for getting the pixel location of a percentage of scale
+		/**
+		 * Utility for getting the pixel location of a percentage of scale
+		 * The coordinate (0, 0) is at the upper-left corner of the canvas
+		 */
 		getPixelForDecimal: function(decimal) {
 			var me = this;
 			if (me.isHorizontal()) {
@@ -7433,6 +7469,10 @@ module.exports = function(Chart) {
 			return me.top + (decimal * me.height);
 		},
 
+		/**
+		 * Returns the pixel for the minimum chart value
+		 * The coordinate (0, 0) is at the upper-left corner of the canvas
+		 */
 		getBasePixel: function() {
 			return this.getPixelForValue(this.getBaseValue());
 		},
@@ -7489,7 +7529,7 @@ module.exports = function(Chart) {
 
 				// Since we always show the last tick,we need may need to hide the last shown one before
 				shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount);
-				if (shouldSkip && i !== tickCount - 1 || helpers.isNullOrUndef(tick.label)) {
+				if (shouldSkip && i !== tickCount - 1) {
 					// leave tick in place but make sure it's not displayed (#4635)
 					delete tick.label;
 				}
@@ -7539,7 +7579,7 @@ module.exports = function(Chart) {
 
 			helpers.each(ticks, function(tick, index) {
 				// autoskipper skipped this tick (#4635)
-				if (tick.label === undefined) {
+				if (helpers.isNullOrUndef(tick.label)) {
 					return;
 				}
 
@@ -8397,6 +8437,7 @@ module.exports = function(Chart) {
 	Chart.Tooltip = Element.extend({
 		initialize: function() {
 			this._model = getBaseModel(this._options);
+			this._lastActive = [];
 		},
 
 		// Get the title
@@ -8508,7 +8549,7 @@ module.exports = function(Chart) {
 
 				var labelColors = [];
 				var labelTextColors = [];
-				tooltipPosition = Chart.Tooltip.positioners[opts.position](active, me._eventPosition);
+				tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition);
 
 				var tooltipItems = [];
 				for (i = 0, len = active.length; i < len; ++i) {
@@ -8690,6 +8731,7 @@ module.exports = function(Chart) {
 			};
 
 			// Before body lines
+			ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity);
 			helpers.each(vm.beforeBody, fillLineOfText);
 
 			var drawColorBoxes = vm.displayColors;
@@ -8697,6 +8739,8 @@ module.exports = function(Chart) {
 
 			// Draw body lines now
 			helpers.each(body, function(bodyItem, i) {
+				var textColor = mergeOpacity(vm.labelTextColors[i], opacity);
+				ctx.fillStyle = textColor;
 				helpers.each(bodyItem.before, fillLineOfText);
 
 				helpers.each(bodyItem.lines, function(line) {
@@ -8714,7 +8758,6 @@ module.exports = function(Chart) {
 						// Inner square
 						ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
 						ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
-						var textColor = mergeOpacity(vm.labelTextColors[i], opacity);
 						ctx.fillStyle = textColor;
 					}
 
@@ -9545,7 +9588,7 @@ var exports = module.exports = {
 	drawPoint: function(ctx, style, radius, x, y) {
 		var type, edgeLength, xOffset, yOffset, height, size;
 
-		if (typeof style === 'object') {
+		if (style && typeof style === 'object') {
 			type = style.toString();
 			if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
 				ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
@@ -9964,6 +10007,48 @@ var helpers = {
 	 */
 	mergeIf: function(target, source) {
 		return helpers.merge(target, source, {merger: helpers._mergerIf});
+	},
+
+	/**
+	 * Applies the contents of two or more objects together into the first object.
+	 * @param {Object} target - The target object in which all objects are merged into.
+	 * @param {Object} arg1 - Object containing additional properties to merge in target.
+	 * @param {Object} argN - Additional objects containing properties to merge in target.
+	 * @returns {Object} The `target` object.
+	 */
+	extend: function(target) {
+		var setFn = function(value, key) {
+			target[key] = value;
+		};
+		for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
+			helpers.each(arguments[i], setFn);
+		}
+		return target;
+	},
+
+	/**
+	 * Basic javascript inheritance based on the model created in Backbone.js
+	 */
+	inherits: function(extensions) {
+		var me = this;
+		var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
+			return me.apply(this, arguments);
+		};
+
+		var Surrogate = function() {
+			this.constructor = ChartElement;
+		};
+
+		Surrogate.prototype = me.prototype;
+		ChartElement.prototype = new Surrogate();
+		ChartElement.extend = helpers.inherits;
+
+		if (extensions) {
+			helpers.extend(ChartElement.prototype, extensions);
+		}
+
+		ChartElement.__super__ = me.prototype;
+		return ChartElement;
 	}
 };
 
@@ -10624,6 +10709,13 @@ function watchForRender(node, handler) {
 		addEventListener(node, type, proxy);
 	});
 
+	// #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
+	// is removed then added back immediately (same animation frame?). Accessing the
+	// `offsetParent` property will force a reflow and re-evaluate the CSS animation.
+	// https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
+	// https://github.com/chartjs/Chart.js/issues/4737
+	expando.reflow = !!node.offsetParent;
+
 	node.classList.add(CSS_RENDER_MONITOR);
 }
 
@@ -13307,47 +13399,47 @@ var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
 
 var INTERVALS = {
 	millisecond: {
-		major: true,
+		common: true,
 		size: 1,
 		steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
 	},
 	second: {
-		major: true,
+		common: true,
 		size: 1000,
 		steps: [1, 2, 5, 10, 30]
 	},
 	minute: {
-		major: true,
+		common: true,
 		size: 60000,
 		steps: [1, 2, 5, 10, 30]
 	},
 	hour: {
-		major: true,
+		common: true,
 		size: 3600000,
 		steps: [1, 2, 3, 6, 12]
 	},
 	day: {
-		major: true,
+		common: true,
 		size: 86400000,
 		steps: [1, 2, 5]
 	},
 	week: {
-		major: false,
+		common: false,
 		size: 604800000,
 		steps: [1, 2, 3, 4]
 	},
 	month: {
-		major: true,
+		common: true,
 		size: 2.628e9,
 		steps: [1, 2, 3]
 	},
 	quarter: {
-		major: false,
+		common: false,
 		size: 7.884e9,
 		steps: [1, 2, 3, 4]
 	},
 	year: {
-		major: true,
+		common: true,
 		size: 3.154e10
 	}
 };
@@ -13547,7 +13639,10 @@ function determineStepSize(min, max, unit, capacity) {
 	return factor;
 }
 
-function determineUnit(minUnit, min, max, capacity) {
+/**
+ * Figures out what unit results in an appropriate number of auto-generated ticks
+ */
+function determineUnitForAutoTicks(minUnit, min, max, capacity) {
 	var ilen = UNITS.length;
 	var i, interval, factor;
 
@@ -13555,7 +13650,7 @@ function determineUnit(minUnit, min, max, capacity) {
 		interval = INTERVALS[UNITS[i]];
 		factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;
 
-		if (Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
+		if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
 			return UNITS[i];
 		}
 	}
@@ -13563,9 +13658,27 @@ function determineUnit(minUnit, min, max, capacity) {
 	return UNITS[ilen - 1];
 }
 
+/**
+ * Figures out what unit to format a set of ticks with
+ */
+function determineUnitForFormatting(ticks, minUnit, min, max) {
+	var duration = moment.duration(moment(max).diff(moment(min)));
+	var ilen = UNITS.length;
+	var i, unit;
+
+	for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
+		unit = UNITS[i];
+		if (INTERVALS[unit].common && duration.as(unit) >= ticks.length) {
+			return unit;
+		}
+	}
+
+	return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
+}
+
 function determineMajorUnit(unit) {
 	for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
-		if (INTERVALS[UNITS[i]].major) {
+		if (INTERVALS[UNITS[i]].common) {
 			return UNITS[i];
 		}
 	}
@@ -13577,8 +13690,10 @@ function determineMajorUnit(unit) {
  * Important: this method can return ticks outside the min and max range, it's the
  * responsibility of the calling code to clamp values if needed.
  */
-function generate(min, max, minor, major, capacity, options) {
+function generate(min, max, capacity, options) {
 	var timeOpts = options.time;
+	var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
+	var major = determineMajorUnit(minor);
 	var stepSize = helpers.valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize);
 	var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
 	var majorTicksEnabled = options.ticks.major.enabled;
@@ -13775,8 +13890,8 @@ module.exports = function(Chart) {
 			var me = this;
 			var chart = me.chart;
 			var timeOpts = me.options.time;
-			var min = parse(timeOpts.min, me) || MAX_INTEGER;
-			var max = parse(timeOpts.max, me) || MIN_INTEGER;
+			var min = MAX_INTEGER;
+			var max = MIN_INTEGER;
 			var timestamps = [];
 			var datasets = [];
 			var labels = [];
@@ -13823,6 +13938,9 @@ module.exports = function(Chart) {
 				max = Math.max(max, timestamps[timestamps.length - 1]);
 			}
 
+			min = parse(timeOpts.min, me) || min;
+			max = parse(timeOpts.max, me) || max;
+
 			// In case there is no valid min/max, let's use today limits
 			min = min === MAX_INTEGER ? +moment().startOf('day') : min;
 			max = max === MIN_INTEGER ? +moment().endOf('day') + 1 : max;
@@ -13847,10 +13965,6 @@ module.exports = function(Chart) {
 			var max = me.max;
 			var options = me.options;
 			var timeOpts = options.time;
-			var formats = timeOpts.displayFormats;
-			var capacity = me.getLabelCapacity(min);
-			var unit = timeOpts.unit || determineUnit(timeOpts.minUnit, min, max, capacity);
-			var majorUnit = determineMajorUnit(unit);
 			var timestamps = [];
 			var ticks = [];
 			var i, ilen, timestamp;
@@ -13864,7 +13978,7 @@ module.exports = function(Chart) {
 				break;
 			case 'auto':
 			default:
-				timestamps = generate(min, max, unit, majorUnit, capacity, options);
+				timestamps = generate(min, max, me.getLabelCapacity(min), options);
 			}
 
 			if (options.bounds === 'ticks' && timestamps.length) {
@@ -13888,14 +14002,12 @@ module.exports = function(Chart) {
 			me.max = max;
 
 			// PRIVATE
-			me._unit = unit;
-			me._majorUnit = majorUnit;
-			me._minorFormat = formats[unit];
-			me._majorFormat = formats[majorUnit];
+			me._unit = timeOpts.unit || determineUnitForFormatting(ticks, timeOpts.minUnit, me.min, me.max);
+			me._majorUnit = determineMajorUnit(me._unit);
 			me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
 			me._offsets = computeOffsets(me._table, ticks, min, max, options);
 
-			return ticksFromTimestamps(ticks, majorUnit);
+			return ticksFromTimestamps(ticks, me._majorUnit);
 		},
 
 		getLabelForIndex: function(index, datasetIndex) {
@@ -13919,16 +14031,18 @@ module.exports = function(Chart) {
 		 * Function to format an individual tick mark
 		 * @private
 		 */
-		tickFormatFunction: function(tick, index, ticks) {
+		tickFormatFunction: function(tick, index, ticks, formatOverride) {
 			var me = this;
 			var options = me.options;
 			var time = tick.valueOf();
+			var formats = options.time.displayFormats;
+			var minorFormat = formats[me._unit];
 			var majorUnit = me._majorUnit;
-			var majorFormat = me._majorFormat;
-			var majorTime = tick.clone().startOf(me._majorUnit).valueOf();
+			var majorFormat = formats[majorUnit];
+			var majorTime = tick.clone().startOf(majorUnit).valueOf();
 			var majorTickOpts = options.ticks.major;
 			var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
-			var label = tick.format(major ? majorFormat : me._minorFormat);
+			var label = tick.format(formatOverride ? formatOverride : major ? majorFormat : minorFormat);
 			var tickOpts = major ? majorTickOpts : options.ticks.minor;
 			var formatter = helpers.valueOrDefault(tickOpts.callback, tickOpts.userCallback);
 
@@ -14014,9 +14128,9 @@ module.exports = function(Chart) {
 		getLabelCapacity: function(exampleTime) {
 			var me = this;
 
-			me._minorFormat = me.options.time.displayFormats.millisecond;	// Pick the longest format for guestimation
+			var formatOverride = me.options.time.displayFormats.millisecond;	// Pick the longest format for guestimation
 
-			var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, []);
+			var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, [], formatOverride);
 			var tickLabelWidth = me.getLabelWidth(exampleLabel);
 			var innerWidth = me.isHorizontal() ? me.width : me.height;
 
diff --git a/www/plugins/graph/js/controllers/account-controllers.js b/www/plugins/graph/js/controllers/account-controllers.js
index 4829b0e977ca9b09e23e6d9b3da1fd8627e99a11..ab9d2076dc6a696083df0cb1f6b8ad547df8ead4 100644
--- a/www/plugins/graph/js/controllers/account-controllers.js
+++ b/www/plugins/graph/js/controllers/account-controllers.js
@@ -206,6 +206,9 @@ function GpAccountBalanceController($scope, $controller, $q, $state, $filter, $t
             text: title
           },
           scales: {
+            xAxes: [{
+              stacked: true
+            }],
             yAxes: [
               {
                 id: 'y-axis-left',
diff --git a/www/plugins/graph/js/controllers/docstats-controllers.js b/www/plugins/graph/js/controllers/docstats-controllers.js
index a3c20f9e19118913705c58ef2e4ac5596aac8648..c2dd913634ba99a0ad27cf00b366deac5eb0d313 100644
--- a/www/plugins/graph/js/controllers/docstats-controllers.js
+++ b/www/plugins/graph/js/controllers/docstats-controllers.js
@@ -44,8 +44,8 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
         {
           key: 'user_profile',
           label: 'GRAPH.DOC_STATS.USER.USER_PROFILE',
-          color: gpColor.rgba.royal(1),
-          pointHoverBackgroundColor: gpColor.rgba.royal(1),
+          color: gpColor.rgba.royal(),
+          pointHoverBackgroundColor: gpColor.rgba.royal(),
           clickState: {
             name: 'app.document_search',
             params: {index:'user', type: 'profile'}
@@ -55,7 +55,7 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
           key: 'user_settings',
           label: 'GRAPH.DOC_STATS.USER.USER_SETTINGS',
           color: gpColor.rgba.gray(0.5),
-          pointHoverBackgroundColor: gpColor.rgba.gray(1),
+          pointHoverBackgroundColor: gpColor.rgba.gray(),
           clickState: {
             name: 'app.document_search',
             params: {index:'user', type: 'settings'}
@@ -72,8 +72,8 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
         {
           key: 'message_inbox',
           label: 'GRAPH.DOC_STATS.MESSAGE.MESSAGE_INBOX',
-          color: gpColor.rgba.royal(1),
-          pointHoverBackgroundColor: gpColor.rgba.royal(1),
+          color: gpColor.rgba.royal(),
+          pointHoverBackgroundColor: gpColor.rgba.royal(),
           clickState: {
             name: 'app.document_search',
             params: {index:'message', type: 'inbox'}
@@ -82,8 +82,8 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
         {
           key: 'message_outbox',
           label: 'GRAPH.DOC_STATS.MESSAGE.MESSAGE_OUTBOX',
-          color: gpColor.rgba.calm(1),
-          pointHoverBackgroundColor: gpColor.rgba.calm(1),
+          color: gpColor.rgba.calm(),
+          pointHoverBackgroundColor: gpColor.rgba.calm(),
           clickState: {
             name: 'app.document_search',
             params: {index:'message', type: 'outbox'}
@@ -93,7 +93,7 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
           key: 'invitation_certification',
           label: 'GRAPH.DOC_STATS.MESSAGE.INVITATION_CERTIFICATION',
           color: gpColor.rgba.gray(0.5),
-          pointHoverBackgroundColor: gpColor.rgba.gray(1),
+          pointHoverBackgroundColor: gpColor.rgba.gray(),
           clickState: {
             name: 'app.document_search',
             params: {index:'invitation', type: 'certification'}
@@ -110,8 +110,8 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
         {
           key: 'page_record',
           label: 'GRAPH.DOC_STATS.SOCIAL.PAGE_RECORD',
-          color: gpColor.rgba.royal(1),
-          pointHoverBackgroundColor: gpColor.rgba.royal(1),
+          color: gpColor.rgba.royal(),
+          pointHoverBackgroundColor: gpColor.rgba.royal(),
           clickState: {
             name: 'app.document_search',
             params: {index:'page', type: 'record'}
@@ -120,8 +120,8 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
         {
           key: 'group_record',
           label: 'GRAPH.DOC_STATS.SOCIAL.GROUP_RECORD',
-          color: gpColor.rgba.calm(1),
-          pointHoverBackgroundColor: gpColor.rgba.calm(1),
+          color: gpColor.rgba.calm(),
+          pointHoverBackgroundColor: gpColor.rgba.calm(),
           clickState: {
             name: 'app.document_search',
             params: {index:'group', type: 'record'}
@@ -131,7 +131,7 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
           key: 'page_comment',
           label: 'GRAPH.DOC_STATS.SOCIAL.PAGE_COMMENT',
           color: gpColor.rgba.gray(0.5),
-          pointHoverBackgroundColor: gpColor.rgba.gray(1),
+          pointHoverBackgroundColor: gpColor.rgba.gray(),
           clickState: {
             name: 'app.document_search',
             params: {index:'page', type: 'comment'}
@@ -149,7 +149,7 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
           key: 'history_delete',
           label: 'GRAPH.DOC_STATS.OTHER.HISTORY_DELETE',
           color: gpColor.rgba.gray(0.5),
-          pointHoverBackgroundColor: gpColor.rgba.gray(1),
+          pointHoverBackgroundColor: gpColor.rgba.gray(),
           clickState: {
             name: 'app.document_search',
             params: {index:'history', type: 'delete'}
@@ -172,6 +172,9 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
       onClick: $scope.onLegendClick
     },
     scales: {
+      xAxes: [{
+        stacked: true
+      }],
       yAxes: [
         {
           stacked: true,
@@ -254,17 +257,19 @@ function GpDocStatsController($scope, $state, $controller, $q, $translate, gpCol
         chart.datasetOverride = chart.series.reduce(function(res, serie) {
           return res.concat({
             yAxisID: 'y-axis',
-            type: 'line',
+            type: serie.type || 'line',
             label: translations[serie.label],
             fill: true,
-            borderColor: serie.color,
             borderWidth: 2,
+            pointRadius: 0,
+            pointHitRadius: 4,
+            pointHoverRadius: 3,
+            borderColor: serie.color,
             backgroundColor: serie.color,
             pointBackgroundColor: serie.color,
-            pointBorderColor: gpColor.rgba.white(),
+            pointBorderColor: serie.color,
             pointHoverBackgroundColor: serie.pointHoverBackgroundColor||serie.color,
-            pointHoverBorderColor: gpColor.rgba.translucent(),
-            pointRadius: 3
+            pointHoverBorderColor: serie.pointHoverBorderColor||gpColor.rgba.white()
           });
         }, []);
       });
diff --git a/www/plugins/graph/js/controllers/synchro-controllers.js b/www/plugins/graph/js/controllers/synchro-controllers.js
index b770cef3f15449c7bd9fabd9bbcf0dd6c023f4c2..9349f546d4fe3c74e3b76325af89a93ab1d7b9bd 100644
--- a/www/plugins/graph/js/controllers/synchro-controllers.js
+++ b/www/plugins/graph/js/controllers/synchro-controllers.js
@@ -42,21 +42,24 @@ function GpSynchroController($scope, $controller, $q, $translate, gpColor, gpDat
       series: [
         {
           key: 'inserts',
+          type: 'bar',
           label: 'GRAPH.SYNCHRO.COUNT.INSERTS',
-          color: gpColor.rgba.royal(1),
-          pointHoverBackgroundColor: gpColor.rgba.royal(1)
+          color: gpColor.rgba.royal(),
+          pointHoverBackgroundColor: gpColor.rgba.royal()
         },
         {
           key: 'updates',
+          type: 'bar',
           label: 'GRAPH.SYNCHRO.COUNT.UPDATES',
-          color: gpColor.rgba.calm(1),
-          pointHoverBackgroundColor: gpColor.rgba.calm(1)
+          color: gpColor.rgba.calm(),
+          pointHoverBackgroundColor: gpColor.rgba.calm()
         },
         {
           key: 'deletes',
+          type: 'bar',
           label: 'GRAPH.SYNCHRO.COUNT.DELETES',
           color: gpColor.rgba.assertive(0.5),
-          pointHoverBackgroundColor: gpColor.rgba.assertive(1)
+          pointHoverBackgroundColor: gpColor.rgba.assertive()
         }
       ]
     },
@@ -69,14 +72,14 @@ function GpSynchroController($scope, $controller, $q, $translate, gpColor, gpDat
         {
           key: 'ES_USER_API',
           label: 'GRAPH.SYNCHRO.PEER.ES_USER_API',
-          color: gpColor.rgba.royal(1),
-          pointHoverBackgroundColor: gpColor.rgba.royal(1)
+          color: gpColor.rgba.royal(),
+          pointHoverBackgroundColor: gpColor.rgba.royal()
         },
         {
           key: 'ES_SUBSCRIPTION_API',
           label: 'GRAPH.SYNCHRO.PEER.ES_SUBSCRIPTION_API',
           color: gpColor.rgba.gray(0.5),
-          pointHoverBackgroundColor: gpColor.rgba.gray(1)
+          pointHoverBackgroundColor: gpColor.rgba.gray()
         }
       ]
     },
@@ -88,9 +91,10 @@ function GpSynchroController($scope, $controller, $q, $translate, gpColor, gpDat
       series: [
         {
           key: 'duration',
+          type: 'bar',
           label: 'GRAPH.SYNCHRO.PERFORMANCE.DURATION',
           color: gpColor.rgba.gray(0.5),
-          pointHoverBackgroundColor: gpColor.rgba.gray(1)
+          pointHoverBackgroundColor: gpColor.rgba.gray()
         }
       ]
     }
@@ -109,6 +113,9 @@ function GpSynchroController($scope, $controller, $q, $translate, gpColor, gpDat
       onClick: $scope.onLegendClick
     },
     scales: {
+      xAxes: [{
+        stacked: true
+      }],
       yAxes: [
         {
           stacked: true,
@@ -191,17 +198,19 @@ function GpSynchroController($scope, $controller, $q, $translate, gpColor, gpDat
         chart.datasetOverride = chart.series.reduce(function(res, serie) {
           return res.concat({
             yAxisID: 'y-axis',
-            type: 'bar',
+            type: serie.type || 'line',
             label: translations[serie.label],
             fill: true,
-            borderColor: serie.color,
             borderWidth: 2,
+            pointRadius: 0,
+            pointHitRadius: 4,
+            pointHoverRadius: 3,
+            borderColor: serie.color,
             backgroundColor: serie.color,
             pointBackgroundColor: serie.color,
-            pointBorderColor: gpColor.rgba.white(),
+            pointBorderColor: serie.color,
             pointHoverBackgroundColor: serie.pointHoverBackgroundColor||serie.color,
-            pointHoverBorderColor: gpColor.rgba.translucent(),
-            pointRadius: 3
+            pointHoverBorderColor: serie.pointHoverBorderColor||gpColor.rgba.white()
           });
         }, []);
       });