From 8d225016a989d44db0f6862916bac086e582d1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=99=8E?= Date: Wed, 4 Mar 2020 18:46:56 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oneself/chartjs/Chart.PieceLabel.js | 312 + .../static/oneself/chartjs/Chart.bundle.js | 18608 ++++++++++++++++ .../chartjs/Chart.roundedBarCharts.min.js | 1 + .../chartjs/chartjs-plugin-datalabels.js | 1017 + .../oneself/chartjs/chartjs-plugin-zoom.js | 583 + .../static/oneself/chartjs/customer_utils.js | 349 + .../static/oneself/chartjs/hammer.min.js | 7 + .../resources/static/oneself/images/b1.gif | Bin 0 -> 9084 bytes .../resources/static/oneself/images/b2.gif | Bin 0 -> 4987 bytes .../resources/static/oneself/images/b3.gif | Bin 0 -> 6049 bytes .../resources/static/oneself/images/b4.gif | Bin 0 -> 4240 bytes .../resources/static/oneself/images/b5.gif | Bin 0 -> 5418 bytes .../resources/static/oneself/images/b6.gif | Bin 0 -> 50223 bytes .../static/oneself/images/body_dl.jpg | Bin 0 -> 66401 bytes .../static/oneself/images/body_dl2.jpg | Bin 0 -> 151307 bytes .../resources/static/oneself/images/close.gif | Bin 0 -> 70 bytes .../resources/static/oneself/images/close.png | Bin 0 -> 820 bytes .../static/oneself/images/close_hover.png | Bin 0 -> 794 bytes .../oneself/images/grid-18px-masked.png | Bin 0 -> 405 bytes .../resources/static/oneself/images/input.png | Bin 0 -> 903 bytes .../images/jobResultShow_imgStep/step1.png | Bin 0 -> 6062 bytes .../images/jobResultShow_imgStep/step2.png | Bin 0 -> 20949 bytes .../static/oneself/images/loading.gif | Bin 0 -> 3413 bytes .../resources/static/oneself/images/logo.gif | Bin 0 -> 4785 bytes .../static/oneself/images/logo_dl.png | Bin 0 -> 7158 bytes .../static/oneself/images/logo_x.png | Bin 0 -> 1357 bytes .../resources/static/oneself/images/new1.gif | Bin 0 -> 277 bytes .../static/oneself/images/openclose.png | Bin 0 -> 3666 bytes .../static/oneself/images/openclose2 .gif | Bin 0 -> 1093 bytes .../static/oneself/images/openclose2.gif | Bin 0 -> 1093 bytes .../resources/static/oneself/images/ruler.gif | Bin 0 -> 291 bytes .../resources/static/oneself/images/so.gif | Bin 0 -> 221 bytes .../resources/static/oneself/images/tmt1.png | Bin 0 -> 346 bytes .../resources/static/oneself/images/tmt10.png | Bin 0 -> 1181 bytes .../resources/static/oneself/images/tmt11.png | Bin 0 -> 725 bytes .../resources/static/oneself/images/tmt2.png | Bin 0 -> 333 bytes .../resources/static/oneself/images/tmt3.png | Bin 0 -> 432 bytes .../resources/static/oneself/images/tmt4.png | Bin 0 -> 343 bytes .../resources/static/oneself/images/tmt5.png | Bin 0 -> 407 bytes .../resources/static/oneself/images/tmt6.png | Bin 0 -> 484 bytes .../resources/static/oneself/images/tmt7.png | Bin 0 -> 647 bytes .../resources/static/oneself/images/tmt8.png | Bin 0 -> 1239 bytes .../resources/static/oneself/images/tmt9.png | Bin 0 -> 1596 bytes .../resources/static/oneself/images/tu1.png | Bin 0 -> 2018 bytes .../static/oneself/images/userinfo.jpg | Bin 0 -> 3139 bytes .../static/oneself/images/userinfobig.jpg | Bin 0 -> 9659 bytes .../resources/static/oneself/images/xtb.gif | Bin 0 -> 152 bytes .../resources/static/oneself/images/xtb2.gif | Bin 0 -> 183 bytes .../resources/static/oneself/images/xtb3.gif | Bin 0 -> 84 bytes .../resources/static/oneself/images/xtb4.gif | Bin 0 -> 133 bytes .../static/oneself/images/xuxian.gif | Bin 0 -> 47 bytes .../src/main/resources/templates/main.html | 2 +- .../defaultIndex/DefaultIndexController.java | 204 + 53 files changed, 21082 insertions(+), 1 deletion(-) create mode 100644 infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.PieceLabel.js create mode 100644 infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.bundle.js create mode 100644 infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.roundedBarCharts.min.js create mode 100644 infosouth-admin/src/main/resources/static/oneself/chartjs/chartjs-plugin-datalabels.js create mode 100644 infosouth-admin/src/main/resources/static/oneself/chartjs/chartjs-plugin-zoom.js create mode 100644 infosouth-admin/src/main/resources/static/oneself/chartjs/customer_utils.js create mode 100644 infosouth-admin/src/main/resources/static/oneself/chartjs/hammer.min.js create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/b1.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/b2.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/b3.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/b4.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/b5.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/b6.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/body_dl.jpg create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/body_dl2.jpg create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/close.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/close.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/close_hover.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/grid-18px-masked.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/input.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/jobResultShow_imgStep/step1.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/jobResultShow_imgStep/step2.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/loading.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/logo.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/logo_dl.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/logo_x.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/new1.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/openclose.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/openclose2 .gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/openclose2.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/ruler.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/so.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt1.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt10.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt11.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt2.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt3.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt4.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt5.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt6.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt7.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt8.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tmt9.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/tu1.png create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/userinfo.jpg create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/userinfobig.jpg create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/xtb.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/xtb2.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/xtb3.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/xtb4.gif create mode 100644 infosouth-admin/src/main/resources/static/oneself/images/xuxian.gif create mode 100644 infosouth-arj21/src/main/java/cn/com/infosouth/arj21/controller/defaultIndex/DefaultIndexController.java diff --git a/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.PieceLabel.js b/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.PieceLabel.js new file mode 100644 index 000000000..1378c558b --- /dev/null +++ b/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.PieceLabel.js @@ -0,0 +1,312 @@ +/** + * [Chart.PieceLabel.js]{@link https://github.com/emn178/Chart.PieceLabel.js} + * + * @version 0.9.0 + * @author Chen, Yi-Cyuan [emn178@gmail.com] + * @copyright Chen, Yi-Cyuan 2017 + * @license MIT + */ +(function () { + if (typeof Chart === 'undefined') { + console.warn('Can not find Chart object.'); + return; + } + + function PieceLabel() { + this.drawDataset = this.drawDataset.bind(this); + } + + PieceLabel.prototype.beforeDatasetsUpdate = function (chartInstance) { + if (this.parseOptions(chartInstance) && this.position === 'outside') { + var padding = this.fontSize * 1.5 + 2; + chartInstance.chartArea.top += padding; + chartInstance.chartArea.bottom -= padding; + } + }; + + PieceLabel.prototype.afterDatasetsDraw = function (chartInstance) { + if (!this.parseOptions(chartInstance)) { + return; + } + this.labelBounds = []; + chartInstance.config.data.datasets.forEach(this.drawDataset); + }; + + PieceLabel.prototype.drawDataset = function (dataset) { + var ctx = this.ctx; + var chartInstance = this.chartInstance; + var meta = dataset._meta[Object.keys(dataset._meta)[0]]; + var totalPercentage = 0; + for (var i = 0; i < meta.data.length; i++) { + var element = meta.data[i], + view = element._view, text; + + //Skips label creation if value is zero and showZero is set + if (view.circumference === 0 && !this.showZero) { + continue; + } + switch (this.render) { + case 'value': + var value = dataset.data[i]; + if (this.format) { + value = this.format(value); + } + text = value.toString(); + break; + case 'label': + text = chartInstance.config.data.labels[i]; + break; + case 'image': + text = this.images[i] ? this.loadImage(this.images[i]) : ''; + break; + case 'percentage': + default: + var percentage = view.circumference / this.options.circumference * 100; + percentage = parseFloat(percentage.toFixed(this.precision)); + if (!this.showActualPercentages) { + totalPercentage += percentage; + if (totalPercentage > 100) { + percentage -= totalPercentage - 100; + // After adjusting the percentage, need to trim the numbers after decimal points again, otherwise it may not show + // on chart due to very long number after decimal point. + percentage = parseFloat(percentage.toFixed(this.precision)); + } + } + text = percentage + '%'; + break; + } + if (typeof this.render === 'function') { + text = this.render({ + label: chartInstance.config.data.labels[i], + value: dataset.data[i], + percentage: percentage, + dataset: dataset, + index: i + }); + + if (typeof text === 'object') { + text = this.loadImage(text); + } + } + if (!text) { + return; + } + ctx.save(); + ctx.beginPath(); + ctx.font = Chart.helpers.fontString(this.fontSize, this.fontStyle, this.fontFamily); + var position, innerRadius, arcOffset; + if (this.position === 'outside' || + this.position === 'border' && chartInstance.config.type === 'pie') { + innerRadius = view.outerRadius / 2; + var rangeFromCentre, offset = this.fontSize + 2, + centreAngle = view.startAngle + ((view.endAngle - view.startAngle) / 2); + if (this.position === 'border') { + rangeFromCentre = (view.outerRadius - innerRadius) / 2 + innerRadius; + } else if (this.position === 'outside') { + rangeFromCentre = (view.outerRadius - innerRadius) + innerRadius + offset; + } + position = { + x: view.x + (Math.cos(centreAngle) * rangeFromCentre), + y: view.y + (Math.sin(centreAngle) * rangeFromCentre) + }; + if (this.position === 'outside') { + if (position.x < view.x) { + position.x -= offset; + } else { + position.x += offset; + } + arcOffset = view.outerRadius + offset; + } + } else { + innerRadius = view.innerRadius; + position = element.tooltipPosition(); + } + + var fontColor = this.fontColor; + if (typeof fontColor === 'function') { + fontColor = fontColor({ + label: chartInstance.config.data.labels[i], + value: dataset.data[i], + percentage: percentage, + text: text, + backgroundColor: dataset.backgroundColor[i], + dataset: dataset, + index: i + }); + } else if (typeof fontColor !== 'string') { + fontColor = fontColor[i] || this.options.defaultFontColor; + } + if (this.arc) { + if (!arcOffset) { + arcOffset = (innerRadius + view.outerRadius) / 2; + } + ctx.fillStyle = fontColor; + ctx.textBaseline = 'middle'; + this.drawArcText(text, arcOffset, view, this.overlap); + } else { + var drawable, mertrics = this.measureText(text), + left = position.x - mertrics.width / 2, + right = position.x + mertrics.width / 2, + top = position.y - this.fontSize / 2, + bottom = position.y + this.fontSize / 2; + if (this.overlap) { + drawable = true; + } else if (this.position === 'outside') { + drawable = this.checkTextBound(left, right, top, bottom); + } else { + drawable = element.inRange(left, top) && element.inRange(left, bottom) && + element.inRange(right, top) && element.inRange(right, bottom); + } + if (drawable) { + this.fillText(text, position, fontColor); + } + } + ctx.restore(); + } + }; + + PieceLabel.prototype.parseOptions = function (chartInstance) { + var pieceLabel = chartInstance.options.pieceLabel; + if (pieceLabel) { + this.chartInstance = chartInstance; + this.ctx = chartInstance.chart.ctx; + this.options = chartInstance.config.options; + this.render = pieceLabel.render || pieceLabel.mode; + this.position = pieceLabel.position || 'default'; + this.arc = pieceLabel.arc; + this.format = pieceLabel.format; + this.precision = pieceLabel.precision || 0; + this.fontSize = pieceLabel.fontSize || this.options.defaultFontSize; + this.fontColor = pieceLabel.fontColor || this.options.defaultFontColor; + this.fontStyle = pieceLabel.fontStyle || this.options.defaultFontStyle; + this.fontFamily = pieceLabel.fontFamily || this.options.defaultFontFamily; + this.hasTooltip = chartInstance.tooltip._active && chartInstance.tooltip._active.length; + this.showZero = pieceLabel.showZero; + this.overlap = pieceLabel.overlap; + this.images = pieceLabel.images || []; + this.showActualPercentages = pieceLabel.showActualPercentages || false; + return true; + } else { + return false; + } + }; + + PieceLabel.prototype.checkTextBound = function (left, right, top, bottom) { + var labelBounds = this.labelBounds; + for (var i = 0;i < labelBounds.length;++i) { + var bound = labelBounds[i]; + var potins = [ + [left, top], + [left, bottom], + [right, top], + [right, bottom] + ]; + for (var j = 0;j < potins.length;++j) { + var x = potins[j][0]; + var y = potins[j][1]; + if (x >= bound.left && x <= bound.right && y >= bound.top && y <= bound.bottom) { + return false; + } + } + potins = [ + [bound.left, bound.top], + [bound.left, bound.bottom], + [bound.right, bound.top], + [bound.right, bound.bottom] + ]; + for (var j = 0;j < potins.length;++j) { + var x = potins[j][0]; + var y = potins[j][1]; + if (x >= left && x <= right && y >= top && y <= bottom) { + return false; + } + } + } + labelBounds.push({ + left: left, + right: right, + top: top, + bottom: bottom + }); + return true; + }; + + PieceLabel.prototype.measureText = function (text) { + if (typeof text === 'object') { + return { width: text.width, height: text.height }; + } else { + return this.ctx.measureText(text); + } + }; + + PieceLabel.prototype.fillText = function (text, position, fontColor) { + var ctx = this.ctx; + if (typeof text === 'object') { + ctx.drawImage(text, position.x - text.width / 2, position.y - text.height / 2, text.width, text.height); + } else { + ctx.fillStyle = fontColor; + ctx.textBaseline = 'top'; + ctx.textAlign = 'center'; + ctx.fillText(text, position.x, position.y - this.fontSize / 2); + } + }; + + PieceLabel.prototype.loadImage = function (obj) { + var image = new Image(); + image.src = obj.src; + image.width = obj.width; + image.height = obj.height; + return image; + }; + + PieceLabel.prototype.drawArcText = function (str, radius, view, overlap) { + var ctx = this.ctx, + centerX = view.x, + centerY = view.y, + startAngle = view.startAngle, + endAngle = view.endAngle; + + ctx.save(); + ctx.translate(centerX, centerY); + var angleSize = endAngle - startAngle; + startAngle += Math.PI / 2; + endAngle += Math.PI / 2; + var origStartAngle = startAngle; + var mertrics = this.measureText(str); + startAngle += (endAngle - (mertrics.width / radius + startAngle)) / 2; + if (!overlap && endAngle - startAngle > angleSize) { + ctx.restore(); + return; + } + + if (typeof str === 'string') { + ctx.rotate(startAngle); + for (var i = 0; i < str.length; i++) { + var char = str.charAt(i); + mertrics = ctx.measureText(char); + ctx.save(); + ctx.translate(0, -1 * radius); + ctx.fillText(char, 0, 0); + ctx.restore(); + ctx.rotate(mertrics.width / radius); + } + } else { + ctx.rotate((origStartAngle + endAngle) / 2); + ctx.translate(0, -1 * radius); + this.fillText(str, { x: 0, y: 0 }); + } + ctx.restore(); + }; + + Chart.pluginService.register({ + beforeInit: function(chartInstance) { + chartInstance.pieceLabel = new PieceLabel(); + }, + beforeDatasetsUpdate: function (chartInstance) { + chartInstance.pieceLabel.beforeDatasetsUpdate(chartInstance); + }, + afterDatasetsDraw: function (chartInstance) { + chartInstance.pieceLabel.afterDatasetsDraw(chartInstance); + } + }); +})(); diff --git a/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.bundle.js b/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.bundle.js new file mode 100644 index 000000000..aa0a9cafd --- /dev/null +++ b/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.bundle.js @@ -0,0 +1,18608 @@ +/*! + * Chart.js + * http://chartjs.org/ + * Version: 2.7.1 + * + * Copyright 2017 Nick Downie + * Released under the MIT license + * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md + */ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o lum2) { + return (lum1 + 0.05) / (lum2 + 0.05); + } + return (lum2 + 0.05) / (lum1 + 0.05); + }, + + level: function (color2) { + var contrastRatio = this.contrast(color2); + if (contrastRatio >= 7.1) { + return 'AAA'; + } + + return (contrastRatio >= 4.5) ? 'AA' : ''; + }, + + dark: function () { + // YIQ equation from http://24ways.org/2010/calculating-color-contrast + var rgb = this.values.rgb; + var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000; + return yiq < 128; + }, + + light: function () { + return !this.dark(); + }, + + negate: function () { + var rgb = []; + for (var i = 0; i < 3; i++) { + rgb[i] = 255 - this.values.rgb[i]; + } + this.setValues('rgb', rgb); + return this; + }, + + lighten: function (ratio) { + var hsl = this.values.hsl; + hsl[2] += hsl[2] * ratio; + this.setValues('hsl', hsl); + return this; + }, + + darken: function (ratio) { + var hsl = this.values.hsl; + hsl[2] -= hsl[2] * ratio; + this.setValues('hsl', hsl); + return this; + }, + + saturate: function (ratio) { + var hsl = this.values.hsl; + hsl[1] += hsl[1] * ratio; + this.setValues('hsl', hsl); + return this; + }, + + desaturate: function (ratio) { + var hsl = this.values.hsl; + hsl[1] -= hsl[1] * ratio; + this.setValues('hsl', hsl); + return this; + }, + + whiten: function (ratio) { + var hwb = this.values.hwb; + hwb[1] += hwb[1] * ratio; + this.setValues('hwb', hwb); + return this; + }, + + blacken: function (ratio) { + var hwb = this.values.hwb; + hwb[2] += hwb[2] * ratio; + this.setValues('hwb', hwb); + return this; + }, + + greyscale: function () { + var rgb = this.values.rgb; + // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale + var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11; + this.setValues('rgb', [val, val, val]); + return this; + }, + + clearer: function (ratio) { + var alpha = this.values.alpha; + this.setValues('alpha', alpha - (alpha * ratio)); + return this; + }, + + opaquer: function (ratio) { + var alpha = this.values.alpha; + this.setValues('alpha', alpha + (alpha * ratio)); + return this; + }, + + rotate: function (degrees) { + var hsl = this.values.hsl; + var hue = (hsl[0] + degrees) % 360; + hsl[0] = hue < 0 ? 360 + hue : hue; + this.setValues('hsl', hsl); + return this; + }, + + /** + * Ported from sass implementation in C + * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209 + */ + mix: function (mixinColor, weight) { + var color1 = this; + var color2 = mixinColor; + var p = weight === undefined ? 0.5 : weight; + + var w = 2 * p - 1; + var a = color1.alpha() - color2.alpha(); + + var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + var w2 = 1 - w1; + + return this + .rgb( + w1 * color1.red() + w2 * color2.red(), + w1 * color1.green() + w2 * color2.green(), + w1 * color1.blue() + w2 * color2.blue() + ) + .alpha(color1.alpha() * p + color2.alpha() * (1 - p)); + }, + + toJSON: function () { + return this.rgb(); + }, + + clone: function () { + // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify, + // making the final build way to big to embed in Chart.js. So let's do it manually, + // assuming that values to clone are 1 dimension arrays containing only numbers, + // except 'alpha' which is a number. + var result = new Color(); + var source = this.values; + var target = result.values; + var value, type; + + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + value = source[prop]; + type = ({}).toString.call(value); + if (type === '[object Array]') { + target[prop] = value.slice(0); + } else if (type === '[object Number]') { + target[prop] = value; + } else { + console.error('unexpected color value:', value); + } + } + } + + return result; + } +}; + +Color.prototype.spaces = { + rgb: ['red', 'green', 'blue'], + hsl: ['hue', 'saturation', 'lightness'], + hsv: ['hue', 'saturation', 'value'], + hwb: ['hue', 'whiteness', 'blackness'], + cmyk: ['cyan', 'magenta', 'yellow', 'black'] +}; + +Color.prototype.maxes = { + rgb: [255, 255, 255], + hsl: [360, 100, 100], + hsv: [360, 100, 100], + hwb: [360, 100, 100], + cmyk: [100, 100, 100, 100] +}; + +Color.prototype.getValues = function (space) { + var values = this.values; + var vals = {}; + + for (var i = 0; i < space.length; i++) { + vals[space.charAt(i)] = values[space][i]; + } + + if (values.alpha !== 1) { + vals.a = values.alpha; + } + + // {r: 255, g: 255, b: 255, a: 0.4} + return vals; +}; + +Color.prototype.setValues = function (space, vals) { + var values = this.values; + var spaces = this.spaces; + var maxes = this.maxes; + var alpha = 1; + var i; + + this.valid = true; + + if (space === 'alpha') { + alpha = vals; + } else if (vals.length) { + // [10, 10, 10] + values[space] = vals.slice(0, space.length); + alpha = vals[space.length]; + } else if (vals[space.charAt(0)] !== undefined) { + // {r: 10, g: 10, b: 10} + for (i = 0; i < space.length; i++) { + values[space][i] = vals[space.charAt(i)]; + } + + alpha = vals.a; + } else if (vals[spaces[space][0]] !== undefined) { + // {red: 10, green: 10, blue: 10} + var chans = spaces[space]; + + for (i = 0; i < space.length; i++) { + values[space][i] = vals[chans[i]]; + } + + alpha = vals.alpha; + } + + values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha))); + + if (space === 'alpha') { + return false; + } + + var capped; + + // cap values of the space prior converting all values + for (i = 0; i < space.length; i++) { + capped = Math.max(0, Math.min(maxes[space][i], values[space][i])); + values[space][i] = Math.round(capped); + } + + // convert to all the other color spaces + for (var sname in spaces) { + if (sname !== space) { + values[sname] = convert[space][sname](values[space]); + } + } + + return true; +}; + +Color.prototype.setSpace = function (space, args) { + var vals = args[0]; + + if (vals === undefined) { + // color.rgb() + return this.getValues(space); + } + + // color.rgb(10, 10, 10) + if (typeof vals === 'number') { + vals = Array.prototype.slice.call(args); + } + + this.setValues(space, vals); + return this; +}; + +Color.prototype.setChannel = function (space, index, val) { + var svalues = this.values[space]; + if (val === undefined) { + // color.red() + return svalues[index]; + } else if (val === svalues[index]) { + // color.red(color.red()) + return this; + } + + // color.red(100) + svalues[index] = val; + this.setValues(space, svalues); + + return this; +}; + +if (typeof window !== 'undefined') { + window.Color = Color; +} + +module.exports = Color; + +},{"1":1,"4":4}],3:[function(require,module,exports){ +/* MIT license */ + +module.exports = { + rgb2hsl: rgb2hsl, + rgb2hsv: rgb2hsv, + rgb2hwb: rgb2hwb, + rgb2cmyk: rgb2cmyk, + rgb2keyword: rgb2keyword, + rgb2xyz: rgb2xyz, + rgb2lab: rgb2lab, + rgb2lch: rgb2lch, + + hsl2rgb: hsl2rgb, + hsl2hsv: hsl2hsv, + hsl2hwb: hsl2hwb, + hsl2cmyk: hsl2cmyk, + hsl2keyword: hsl2keyword, + + hsv2rgb: hsv2rgb, + hsv2hsl: hsv2hsl, + hsv2hwb: hsv2hwb, + hsv2cmyk: hsv2cmyk, + hsv2keyword: hsv2keyword, + + hwb2rgb: hwb2rgb, + hwb2hsl: hwb2hsl, + hwb2hsv: hwb2hsv, + hwb2cmyk: hwb2cmyk, + hwb2keyword: hwb2keyword, + + cmyk2rgb: cmyk2rgb, + cmyk2hsl: cmyk2hsl, + cmyk2hsv: cmyk2hsv, + cmyk2hwb: cmyk2hwb, + cmyk2keyword: cmyk2keyword, + + keyword2rgb: keyword2rgb, + keyword2hsl: keyword2hsl, + keyword2hsv: keyword2hsv, + keyword2hwb: keyword2hwb, + keyword2cmyk: keyword2cmyk, + keyword2lab: keyword2lab, + keyword2xyz: keyword2xyz, + + xyz2rgb: xyz2rgb, + xyz2lab: xyz2lab, + xyz2lch: xyz2lch, + + lab2xyz: lab2xyz, + lab2rgb: lab2rgb, + lab2lch: lab2lch, + + lch2lab: lch2lab, + lch2xyz: lch2xyz, + lch2rgb: lch2rgb +} + + +function rgb2hsl(rgb) { + var r = rgb[0]/255, + g = rgb[1]/255, + b = rgb[2]/255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s, l; + + if (max == min) + h = 0; + else if (r == max) + h = (g - b) / delta; + else if (g == max) + h = 2 + (b - r) / delta; + else if (b == max) + h = 4 + (r - g)/ delta; + + h = Math.min(h * 60, 360); + + if (h < 0) + h += 360; + + l = (min + max) / 2; + + if (max == min) + s = 0; + else if (l <= 0.5) + s = delta / (max + min); + else + s = delta / (2 - max - min); + + return [h, s * 100, l * 100]; +} + +function rgb2hsv(rgb) { + var r = rgb[0], + g = rgb[1], + b = rgb[2], + min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s, v; + + if (max == 0) + s = 0; + else + s = (delta/max * 1000)/10; + + if (max == min) + h = 0; + else if (r == max) + h = (g - b) / delta; + else if (g == max) + h = 2 + (b - r) / delta; + else if (b == max) + h = 4 + (r - g) / delta; + + h = Math.min(h * 60, 360); + + if (h < 0) + h += 360; + + v = ((max / 255) * 1000) / 10; + + return [h, s, v]; +} + +function rgb2hwb(rgb) { + var r = rgb[0], + g = rgb[1], + b = rgb[2], + h = rgb2hsl(rgb)[0], + w = 1/255 * Math.min(r, Math.min(g, b)), + b = 1 - 1/255 * Math.max(r, Math.max(g, b)); + + return [h, w * 100, b * 100]; +} + +function rgb2cmyk(rgb) { + var r = rgb[0] / 255, + g = rgb[1] / 255, + b = rgb[2] / 255, + c, m, y, k; + + k = Math.min(1 - r, 1 - g, 1 - b); + c = (1 - r - k) / (1 - k) || 0; + m = (1 - g - k) / (1 - k) || 0; + y = (1 - b - k) / (1 - k) || 0; + return [c * 100, m * 100, y * 100, k * 100]; +} + +function rgb2keyword(rgb) { + return reverseKeywords[JSON.stringify(rgb)]; +} + +function rgb2xyz(rgb) { + var r = rgb[0] / 255, + g = rgb[1] / 255, + b = rgb[2] / 255; + + // assume sRGB + r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92); + g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92); + b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92); + + var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); + var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); + var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); + + return [x * 100, y *100, z * 100]; +} + +function rgb2lab(rgb) { + var xyz = rgb2xyz(rgb), + x = xyz[0], + y = xyz[1], + z = xyz[2], + l, a, b; + + x /= 95.047; + y /= 100; + z /= 108.883; + + x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); + y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); + z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); + + l = (116 * y) - 16; + a = 500 * (x - y); + b = 200 * (y - z); + + return [l, a, b]; +} + +function rgb2lch(args) { + return lab2lch(rgb2lab(args)); +} + +function hsl2rgb(hsl) { + var h = hsl[0] / 360, + s = hsl[1] / 100, + l = hsl[2] / 100, + t1, t2, t3, rgb, val; + + if (s == 0) { + val = l * 255; + return [val, val, val]; + } + + if (l < 0.5) + t2 = l * (1 + s); + else + t2 = l + s - l * s; + t1 = 2 * l - t2; + + rgb = [0, 0, 0]; + for (var i = 0; i < 3; i++) { + t3 = h + 1 / 3 * - (i - 1); + t3 < 0 && t3++; + t3 > 1 && t3--; + + if (6 * t3 < 1) + val = t1 + (t2 - t1) * 6 * t3; + else if (2 * t3 < 1) + val = t2; + else if (3 * t3 < 2) + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + else + val = t1; + + rgb[i] = val * 255; + } + + return rgb; +} + +function hsl2hsv(hsl) { + var h = hsl[0], + s = hsl[1] / 100, + l = hsl[2] / 100, + sv, v; + + if(l === 0) { + // no need to do calc on black + // also avoids divide by 0 error + return [0, 0, 0]; + } + + l *= 2; + s *= (l <= 1) ? l : 2 - l; + v = (l + s) / 2; + sv = (2 * s) / (l + s); + return [h, sv * 100, v * 100]; +} + +function hsl2hwb(args) { + return rgb2hwb(hsl2rgb(args)); +} + +function hsl2cmyk(args) { + return rgb2cmyk(hsl2rgb(args)); +} + +function hsl2keyword(args) { + return rgb2keyword(hsl2rgb(args)); +} + + +function hsv2rgb(hsv) { + var h = hsv[0] / 60, + s = hsv[1] / 100, + v = hsv[2] / 100, + hi = Math.floor(h) % 6; + + var f = h - Math.floor(h), + p = 255 * v * (1 - s), + q = 255 * v * (1 - (s * f)), + t = 255 * v * (1 - (s * (1 - f))), + v = 255 * v; + + switch(hi) { + case 0: + return [v, t, p]; + case 1: + return [q, v, p]; + case 2: + return [p, v, t]; + case 3: + return [p, q, v]; + case 4: + return [t, p, v]; + case 5: + return [v, p, q]; + } +} + +function hsv2hsl(hsv) { + var h = hsv[0], + s = hsv[1] / 100, + v = hsv[2] / 100, + sl, l; + + l = (2 - s) * v; + sl = s * v; + sl /= (l <= 1) ? l : 2 - l; + sl = sl || 0; + l /= 2; + return [h, sl * 100, l * 100]; +} + +function hsv2hwb(args) { + return rgb2hwb(hsv2rgb(args)) +} + +function hsv2cmyk(args) { + return rgb2cmyk(hsv2rgb(args)); +} + +function hsv2keyword(args) { + return rgb2keyword(hsv2rgb(args)); +} + +// http://dev.w3.org/csswg/css-color/#hwb-to-rgb +function hwb2rgb(hwb) { + var h = hwb[0] / 360, + wh = hwb[1] / 100, + bl = hwb[2] / 100, + ratio = wh + bl, + i, v, f, n; + + // wh + bl cant be > 1 + if (ratio > 1) { + wh /= ratio; + bl /= ratio; + } + + i = Math.floor(6 * h); + v = 1 - bl; + f = 6 * h - i; + if ((i & 0x01) != 0) { + f = 1 - f; + } + n = wh + f * (v - wh); // linear interpolation + + switch (i) { + default: + case 6: + case 0: r = v; g = n; b = wh; break; + case 1: r = n; g = v; b = wh; break; + case 2: r = wh; g = v; b = n; break; + case 3: r = wh; g = n; b = v; break; + case 4: r = n; g = wh; b = v; break; + case 5: r = v; g = wh; b = n; break; + } + + return [r * 255, g * 255, b * 255]; +} + +function hwb2hsl(args) { + return rgb2hsl(hwb2rgb(args)); +} + +function hwb2hsv(args) { + return rgb2hsv(hwb2rgb(args)); +} + +function hwb2cmyk(args) { + return rgb2cmyk(hwb2rgb(args)); +} + +function hwb2keyword(args) { + return rgb2keyword(hwb2rgb(args)); +} + +function cmyk2rgb(cmyk) { + var c = cmyk[0] / 100, + m = cmyk[1] / 100, + y = cmyk[2] / 100, + k = cmyk[3] / 100, + r, g, b; + + r = 1 - Math.min(1, c * (1 - k) + k); + g = 1 - Math.min(1, m * (1 - k) + k); + b = 1 - Math.min(1, y * (1 - k) + k); + return [r * 255, g * 255, b * 255]; +} + +function cmyk2hsl(args) { + return rgb2hsl(cmyk2rgb(args)); +} + +function cmyk2hsv(args) { + return rgb2hsv(cmyk2rgb(args)); +} + +function cmyk2hwb(args) { + return rgb2hwb(cmyk2rgb(args)); +} + +function cmyk2keyword(args) { + return rgb2keyword(cmyk2rgb(args)); +} + + +function xyz2rgb(xyz) { + var x = xyz[0] / 100, + y = xyz[1] / 100, + z = xyz[2] / 100, + r, g, b; + + r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); + g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); + b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); + + // assume sRGB + r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055) + : r = (r * 12.92); + + g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055) + : g = (g * 12.92); + + b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055) + : b = (b * 12.92); + + r = Math.min(Math.max(0, r), 1); + g = Math.min(Math.max(0, g), 1); + b = Math.min(Math.max(0, b), 1); + + return [r * 255, g * 255, b * 255]; +} + +function xyz2lab(xyz) { + var x = xyz[0], + y = xyz[1], + z = xyz[2], + l, a, b; + + x /= 95.047; + y /= 100; + z /= 108.883; + + x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116); + y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116); + z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116); + + l = (116 * y) - 16; + a = 500 * (x - y); + b = 200 * (y - z); + + return [l, a, b]; +} + +function xyz2lch(args) { + return lab2lch(xyz2lab(args)); +} + +function lab2xyz(lab) { + var l = lab[0], + a = lab[1], + b = lab[2], + x, y, z, y2; + + if (l <= 8) { + y = (l * 100) / 903.3; + y2 = (7.787 * (y / 100)) + (16 / 116); + } else { + y = 100 * Math.pow((l + 16) / 116, 3); + y2 = Math.pow(y / 100, 1/3); + } + + x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3); + + z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3); + + return [x, y, z]; +} + +function lab2lch(lab) { + var l = lab[0], + a = lab[1], + b = lab[2], + hr, h, c; + + hr = Math.atan2(b, a); + h = hr * 360 / 2 / Math.PI; + if (h < 0) { + h += 360; + } + c = Math.sqrt(a * a + b * b); + return [l, c, h]; +} + +function lab2rgb(args) { + return xyz2rgb(lab2xyz(args)); +} + +function lch2lab(lch) { + var l = lch[0], + c = lch[1], + h = lch[2], + a, b, hr; + + hr = h / 360 * 2 * Math.PI; + a = c * Math.cos(hr); + b = c * Math.sin(hr); + return [l, a, b]; +} + +function lch2xyz(args) { + return lab2xyz(lch2lab(args)); +} + +function lch2rgb(args) { + return lab2rgb(lch2lab(args)); +} + +function keyword2rgb(keyword) { + return cssKeywords[keyword]; +} + +function keyword2hsl(args) { + return rgb2hsl(keyword2rgb(args)); +} + +function keyword2hsv(args) { + return rgb2hsv(keyword2rgb(args)); +} + +function keyword2hwb(args) { + return rgb2hwb(keyword2rgb(args)); +} + +function keyword2cmyk(args) { + return rgb2cmyk(keyword2rgb(args)); +} + +function keyword2lab(args) { + return rgb2lab(keyword2rgb(args)); +} + +function keyword2xyz(args) { + return rgb2xyz(keyword2rgb(args)); +} + +var cssKeywords = { + aliceblue: [240,248,255], + antiquewhite: [250,235,215], + aqua: [0,255,255], + aquamarine: [127,255,212], + azure: [240,255,255], + beige: [245,245,220], + bisque: [255,228,196], + black: [0,0,0], + blanchedalmond: [255,235,205], + blue: [0,0,255], + blueviolet: [138,43,226], + brown: [165,42,42], + burlywood: [222,184,135], + cadetblue: [95,158,160], + chartreuse: [127,255,0], + chocolate: [210,105,30], + coral: [255,127,80], + cornflowerblue: [100,149,237], + cornsilk: [255,248,220], + crimson: [220,20,60], + cyan: [0,255,255], + darkblue: [0,0,139], + darkcyan: [0,139,139], + darkgoldenrod: [184,134,11], + darkgray: [169,169,169], + darkgreen: [0,100,0], + darkgrey: [169,169,169], + darkkhaki: [189,183,107], + darkmagenta: [139,0,139], + darkolivegreen: [85,107,47], + darkorange: [255,140,0], + darkorchid: [153,50,204], + darkred: [139,0,0], + darksalmon: [233,150,122], + darkseagreen: [143,188,143], + darkslateblue: [72,61,139], + darkslategray: [47,79,79], + darkslategrey: [47,79,79], + darkturquoise: [0,206,209], + darkviolet: [148,0,211], + deeppink: [255,20,147], + deepskyblue: [0,191,255], + dimgray: [105,105,105], + dimgrey: [105,105,105], + dodgerblue: [30,144,255], + firebrick: [178,34,34], + floralwhite: [255,250,240], + forestgreen: [34,139,34], + fuchsia: [255,0,255], + gainsboro: [220,220,220], + ghostwhite: [248,248,255], + gold: [255,215,0], + goldenrod: [218,165,32], + gray: [128,128,128], + green: [0,128,0], + greenyellow: [173,255,47], + grey: [128,128,128], + honeydew: [240,255,240], + hotpink: [255,105,180], + indianred: [205,92,92], + indigo: [75,0,130], + ivory: [255,255,240], + khaki: [240,230,140], + lavender: [230,230,250], + lavenderblush: [255,240,245], + lawngreen: [124,252,0], + lemonchiffon: [255,250,205], + lightblue: [173,216,230], + lightcoral: [240,128,128], + lightcyan: [224,255,255], + lightgoldenrodyellow: [250,250,210], + lightgray: [211,211,211], + lightgreen: [144,238,144], + lightgrey: [211,211,211], + lightpink: [255,182,193], + lightsalmon: [255,160,122], + lightseagreen: [32,178,170], + lightskyblue: [135,206,250], + lightslategray: [119,136,153], + lightslategrey: [119,136,153], + lightsteelblue: [176,196,222], + lightyellow: [255,255,224], + lime: [0,255,0], + limegreen: [50,205,50], + linen: [250,240,230], + magenta: [255,0,255], + maroon: [128,0,0], + mediumaquamarine: [102,205,170], + mediumblue: [0,0,205], + mediumorchid: [186,85,211], + mediumpurple: [147,112,219], + mediumseagreen: [60,179,113], + mediumslateblue: [123,104,238], + mediumspringgreen: [0,250,154], + mediumturquoise: [72,209,204], + mediumvioletred: [199,21,133], + midnightblue: [25,25,112], + mintcream: [245,255,250], + mistyrose: [255,228,225], + moccasin: [255,228,181], + navajowhite: [255,222,173], + navy: [0,0,128], + oldlace: [253,245,230], + olive: [128,128,0], + olivedrab: [107,142,35], + orange: [255,165,0], + orangered: [255,69,0], + orchid: [218,112,214], + palegoldenrod: [238,232,170], + palegreen: [152,251,152], + paleturquoise: [175,238,238], + palevioletred: [219,112,147], + papayawhip: [255,239,213], + peachpuff: [255,218,185], + peru: [205,133,63], + pink: [255,192,203], + plum: [221,160,221], + powderblue: [176,224,230], + purple: [128,0,128], + rebeccapurple: [102, 51, 153], + red: [255,0,0], + rosybrown: [188,143,143], + royalblue: [65,105,225], + saddlebrown: [139,69,19], + salmon: [250,128,114], + sandybrown: [244,164,96], + seagreen: [46,139,87], + seashell: [255,245,238], + sienna: [160,82,45], + silver: [192,192,192], + skyblue: [135,206,235], + slateblue: [106,90,205], + slategray: [112,128,144], + slategrey: [112,128,144], + snow: [255,250,250], + springgreen: [0,255,127], + steelblue: [70,130,180], + tan: [210,180,140], + teal: [0,128,128], + thistle: [216,191,216], + tomato: [255,99,71], + turquoise: [64,224,208], + violet: [238,130,238], + wheat: [245,222,179], + white: [255,255,255], + whitesmoke: [245,245,245], + yellow: [255,255,0], + yellowgreen: [154,205,50] +}; + +var reverseKeywords = {}; +for (var key in cssKeywords) { + reverseKeywords[JSON.stringify(cssKeywords[key])] = key; +} + +},{}],4:[function(require,module,exports){ +var conversions = require(3); + +var convert = function() { + return new Converter(); +} + +for (var func in conversions) { + // export Raw versions + convert[func + "Raw"] = (function(func) { + // accept array or plain args + return function(arg) { + if (typeof arg == "number") + arg = Array.prototype.slice.call(arguments); + return conversions[func](arg); + } + })(func); + + var pair = /(\w+)2(\w+)/.exec(func), + from = pair[1], + to = pair[2]; + + // export rgb2hsl and ["rgb"]["hsl"] + convert[from] = convert[from] || {}; + + convert[from][to] = convert[func] = (function(func) { + return function(arg) { + if (typeof arg == "number") + arg = Array.prototype.slice.call(arguments); + + var val = conversions[func](arg); + if (typeof val == "string" || val === undefined) + return val; // keyword + + for (var i = 0; i < val.length; i++) + val[i] = Math.round(val[i]); + return val; + } + })(func); +} + + +/* Converter does lazy conversion and caching */ +var Converter = function() { + this.convs = {}; +}; + +/* Either get the values for a space or + set the values for a space, depending on args */ +Converter.prototype.routeSpace = function(space, args) { + var values = args[0]; + if (values === undefined) { + // color.rgb() + return this.getValues(space); + } + // color.rgb(10, 10, 10) + if (typeof values == "number") { + values = Array.prototype.slice.call(args); + } + + return this.setValues(space, values); +}; + +/* Set the values for a space, invalidating cache */ +Converter.prototype.setValues = function(space, values) { + this.space = space; + this.convs = {}; + this.convs[space] = values; + return this; +}; + +/* Get the values for a space. If there's already + a conversion for the space, fetch it, otherwise + compute it */ +Converter.prototype.getValues = function(space) { + var vals = this.convs[space]; + if (!vals) { + var fspace = this.space, + from = this.convs[fspace]; + vals = convert[fspace][space](from); + + this.convs[space] = vals; + } + return vals; +}; + +["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) { + Converter.prototype[space] = function(vals) { + return this.routeSpace(space, arguments); + } +}); + +module.exports = convert; +},{"3":3}],5:[function(require,module,exports){ +'use strict' + +module.exports = { + "aliceblue": [240, 248, 255], + "antiquewhite": [250, 235, 215], + "aqua": [0, 255, 255], + "aquamarine": [127, 255, 212], + "azure": [240, 255, 255], + "beige": [245, 245, 220], + "bisque": [255, 228, 196], + "black": [0, 0, 0], + "blanchedalmond": [255, 235, 205], + "blue": [0, 0, 255], + "blueviolet": [138, 43, 226], + "brown": [165, 42, 42], + "burlywood": [222, 184, 135], + "cadetblue": [95, 158, 160], + "chartreuse": [127, 255, 0], + "chocolate": [210, 105, 30], + "coral": [255, 127, 80], + "cornflowerblue": [100, 149, 237], + "cornsilk": [255, 248, 220], + "crimson": [220, 20, 60], + "cyan": [0, 255, 255], + "darkblue": [0, 0, 139], + "darkcyan": [0, 139, 139], + "darkgoldenrod": [184, 134, 11], + "darkgray": [169, 169, 169], + "darkgreen": [0, 100, 0], + "darkgrey": [169, 169, 169], + "darkkhaki": [189, 183, 107], + "darkmagenta": [139, 0, 139], + "darkolivegreen": [85, 107, 47], + "darkorange": [255, 140, 0], + "darkorchid": [153, 50, 204], + "darkred": [139, 0, 0], + "darksalmon": [233, 150, 122], + "darkseagreen": [143, 188, 143], + "darkslateblue": [72, 61, 139], + "darkslategray": [47, 79, 79], + "darkslategrey": [47, 79, 79], + "darkturquoise": [0, 206, 209], + "darkviolet": [148, 0, 211], + "deeppink": [255, 20, 147], + "deepskyblue": [0, 191, 255], + "dimgray": [105, 105, 105], + "dimgrey": [105, 105, 105], + "dodgerblue": [30, 144, 255], + "firebrick": [178, 34, 34], + "floralwhite": [255, 250, 240], + "forestgreen": [34, 139, 34], + "fuchsia": [255, 0, 255], + "gainsboro": [220, 220, 220], + "ghostwhite": [248, 248, 255], + "gold": [255, 215, 0], + "goldenrod": [218, 165, 32], + "gray": [128, 128, 128], + "green": [0, 128, 0], + "greenyellow": [173, 255, 47], + "grey": [128, 128, 128], + "honeydew": [240, 255, 240], + "hotpink": [255, 105, 180], + "indianred": [205, 92, 92], + "indigo": [75, 0, 130], + "ivory": [255, 255, 240], + "khaki": [240, 230, 140], + "lavender": [230, 230, 250], + "lavenderblush": [255, 240, 245], + "lawngreen": [124, 252, 0], + "lemonchiffon": [255, 250, 205], + "lightblue": [173, 216, 230], + "lightcoral": [240, 128, 128], + "lightcyan": [224, 255, 255], + "lightgoldenrodyellow": [250, 250, 210], + "lightgray": [211, 211, 211], + "lightgreen": [144, 238, 144], + "lightgrey": [211, 211, 211], + "lightpink": [255, 182, 193], + "lightsalmon": [255, 160, 122], + "lightseagreen": [32, 178, 170], + "lightskyblue": [135, 206, 250], + "lightslategray": [119, 136, 153], + "lightslategrey": [119, 136, 153], + "lightsteelblue": [176, 196, 222], + "lightyellow": [255, 255, 224], + "lime": [0, 255, 0], + "limegreen": [50, 205, 50], + "linen": [250, 240, 230], + "magenta": [255, 0, 255], + "maroon": [128, 0, 0], + "mediumaquamarine": [102, 205, 170], + "mediumblue": [0, 0, 205], + "mediumorchid": [186, 85, 211], + "mediumpurple": [147, 112, 219], + "mediumseagreen": [60, 179, 113], + "mediumslateblue": [123, 104, 238], + "mediumspringgreen": [0, 250, 154], + "mediumturquoise": [72, 209, 204], + "mediumvioletred": [199, 21, 133], + "midnightblue": [25, 25, 112], + "mintcream": [245, 255, 250], + "mistyrose": [255, 228, 225], + "moccasin": [255, 228, 181], + "navajowhite": [255, 222, 173], + "navy": [0, 0, 128], + "oldlace": [253, 245, 230], + "olive": [128, 128, 0], + "olivedrab": [107, 142, 35], + "orange": [255, 165, 0], + "orangered": [255, 69, 0], + "orchid": [218, 112, 214], + "palegoldenrod": [238, 232, 170], + "palegreen": [152, 251, 152], + "paleturquoise": [175, 238, 238], + "palevioletred": [219, 112, 147], + "papayawhip": [255, 239, 213], + "peachpuff": [255, 218, 185], + "peru": [205, 133, 63], + "pink": [255, 192, 203], + "plum": [221, 160, 221], + "powderblue": [176, 224, 230], + "purple": [128, 0, 128], + "rebeccapurple": [102, 51, 153], + "red": [255, 0, 0], + "rosybrown": [188, 143, 143], + "royalblue": [65, 105, 225], + "saddlebrown": [139, 69, 19], + "salmon": [250, 128, 114], + "sandybrown": [244, 164, 96], + "seagreen": [46, 139, 87], + "seashell": [255, 245, 238], + "sienna": [160, 82, 45], + "silver": [192, 192, 192], + "skyblue": [135, 206, 235], + "slateblue": [106, 90, 205], + "slategray": [112, 128, 144], + "slategrey": [112, 128, 144], + "snow": [255, 250, 250], + "springgreen": [0, 255, 127], + "steelblue": [70, 130, 180], + "tan": [210, 180, 140], + "teal": [0, 128, 128], + "thistle": [216, 191, 216], + "tomato": [255, 99, 71], + "turquoise": [64, 224, 208], + "violet": [238, 130, 238], + "wheat": [245, 222, 179], + "white": [255, 255, 255], + "whitesmoke": [245, 245, 245], + "yellow": [255, 255, 0], + "yellowgreen": [154, 205, 50] +}; + +},{}],6:[function(require,module,exports){ +//! moment.js +//! version : 2.18.1 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + global.moment = factory() +}(this, (function () { 'use strict'; + +var hookCallback; + +function hooks () { + return hookCallback.apply(null, arguments); +} + +// This is done to register the method called with moment() +// without creating circular dependencies. +function setHookCallback (callback) { + hookCallback = callback; +} + +function isArray(input) { + return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]'; +} + +function isObject(input) { + // IE8 will treat undefined and null as object if it wasn't for + // input != null + return input != null && Object.prototype.toString.call(input) === '[object Object]'; +} + +function isObjectEmpty(obj) { + var k; + for (k in obj) { + // even if its not own property I'd still call it non-empty + return false; + } + return true; +} + +function isUndefined(input) { + return input === void 0; +} + +function isNumber(input) { + return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]'; +} + +function isDate(input) { + return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]'; +} + +function map(arr, fn) { + var res = [], i; + for (i = 0; i < arr.length; ++i) { + res.push(fn(arr[i], i)); + } + return res; +} + +function hasOwnProp(a, b) { + return Object.prototype.hasOwnProperty.call(a, b); +} + +function extend(a, b) { + for (var i in b) { + if (hasOwnProp(b, i)) { + a[i] = b[i]; + } + } + + if (hasOwnProp(b, 'toString')) { + a.toString = b.toString; + } + + if (hasOwnProp(b, 'valueOf')) { + a.valueOf = b.valueOf; + } + + return a; +} + +function createUTC (input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, true).utc(); +} + +function defaultParsingFlags() { + // We need to deep clone this object. + return { + empty : false, + unusedTokens : [], + unusedInput : [], + overflow : -2, + charsLeftOver : 0, + nullInput : false, + invalidMonth : null, + invalidFormat : false, + userInvalidated : false, + iso : false, + parsedDateParts : [], + meridiem : null, + rfc2822 : false, + weekdayMismatch : false + }; +} + +function getParsingFlags(m) { + if (m._pf == null) { + m._pf = defaultParsingFlags(); + } + return m._pf; +} + +var some; +if (Array.prototype.some) { + some = Array.prototype.some; +} else { + some = function (fun) { + var t = Object(this); + var len = t.length >>> 0; + + for (var i = 0; i < len; i++) { + if (i in t && fun.call(this, t[i], i, t)) { + return true; + } + } + + return false; + }; +} + +var some$1 = some; + +function isValid(m) { + if (m._isValid == null) { + var flags = getParsingFlags(m); + var parsedParts = some$1.call(flags.parsedDateParts, function (i) { + return i != null; + }); + var isNowValid = !isNaN(m._d.getTime()) && + flags.overflow < 0 && + !flags.empty && + !flags.invalidMonth && + !flags.invalidWeekday && + !flags.nullInput && + !flags.invalidFormat && + !flags.userInvalidated && + (!flags.meridiem || (flags.meridiem && parsedParts)); + + if (m._strict) { + isNowValid = isNowValid && + flags.charsLeftOver === 0 && + flags.unusedTokens.length === 0 && + flags.bigHour === undefined; + } + + if (Object.isFrozen == null || !Object.isFrozen(m)) { + m._isValid = isNowValid; + } + else { + return isNowValid; + } + } + return m._isValid; +} + +function createInvalid (flags) { + var m = createUTC(NaN); + if (flags != null) { + extend(getParsingFlags(m), flags); + } + else { + getParsingFlags(m).userInvalidated = true; + } + + return m; +} + +// Plugins that add properties should also add the key here (null value), +// so we can properly clone ourselves. +var momentProperties = hooks.momentProperties = []; + +function copyConfig(to, from) { + var i, prop, val; + + if (!isUndefined(from._isAMomentObject)) { + to._isAMomentObject = from._isAMomentObject; + } + if (!isUndefined(from._i)) { + to._i = from._i; + } + if (!isUndefined(from._f)) { + to._f = from._f; + } + if (!isUndefined(from._l)) { + to._l = from._l; + } + if (!isUndefined(from._strict)) { + to._strict = from._strict; + } + if (!isUndefined(from._tzm)) { + to._tzm = from._tzm; + } + if (!isUndefined(from._isUTC)) { + to._isUTC = from._isUTC; + } + if (!isUndefined(from._offset)) { + to._offset = from._offset; + } + if (!isUndefined(from._pf)) { + to._pf = getParsingFlags(from); + } + if (!isUndefined(from._locale)) { + to._locale = from._locale; + } + + if (momentProperties.length > 0) { + for (i = 0; i < momentProperties.length; i++) { + prop = momentProperties[i]; + val = from[prop]; + if (!isUndefined(val)) { + to[prop] = val; + } + } + } + + return to; +} + +var updateInProgress = false; + +// Moment prototype object +function Moment(config) { + copyConfig(this, config); + this._d = new Date(config._d != null ? config._d.getTime() : NaN); + if (!this.isValid()) { + this._d = new Date(NaN); + } + // Prevent infinite loop in case updateOffset creates new moment + // objects. + if (updateInProgress === false) { + updateInProgress = true; + hooks.updateOffset(this); + updateInProgress = false; + } +} + +function isMoment (obj) { + return obj instanceof Moment || (obj != null && obj._isAMomentObject != null); +} + +function absFloor (number) { + if (number < 0) { + // -0 -> 0 + return Math.ceil(number) || 0; + } else { + return Math.floor(number); + } +} + +function toInt(argumentForCoercion) { + var coercedNumber = +argumentForCoercion, + value = 0; + + if (coercedNumber !== 0 && isFinite(coercedNumber)) { + value = absFloor(coercedNumber); + } + + return value; +} + +// compare two arrays, return the number of differences +function compareArrays(array1, array2, dontConvert) { + var len = Math.min(array1.length, array2.length), + lengthDiff = Math.abs(array1.length - array2.length), + diffs = 0, + i; + for (i = 0; i < len; i++) { + if ((dontConvert && array1[i] !== array2[i]) || + (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { + diffs++; + } + } + return diffs + lengthDiff; +} + +function warn(msg) { + if (hooks.suppressDeprecationWarnings === false && + (typeof console !== 'undefined') && console.warn) { + console.warn('Deprecation warning: ' + msg); + } +} + +function deprecate(msg, fn) { + var firstTime = true; + + return extend(function () { + if (hooks.deprecationHandler != null) { + hooks.deprecationHandler(null, msg); + } + if (firstTime) { + var args = []; + var arg; + for (var i = 0; i < arguments.length; i++) { + arg = ''; + if (typeof arguments[i] === 'object') { + arg += '\n[' + i + '] '; + for (var key in arguments[0]) { + arg += key + ': ' + arguments[0][key] + ', '; + } + arg = arg.slice(0, -2); // Remove trailing comma and space + } else { + arg = arguments[i]; + } + args.push(arg); + } + warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack); + firstTime = false; + } + return fn.apply(this, arguments); + }, fn); +} + +var deprecations = {}; + +function deprecateSimple(name, msg) { + if (hooks.deprecationHandler != null) { + hooks.deprecationHandler(name, msg); + } + if (!deprecations[name]) { + warn(msg); + deprecations[name] = true; + } +} + +hooks.suppressDeprecationWarnings = false; +hooks.deprecationHandler = null; + +function isFunction(input) { + return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]'; +} + +function set (config) { + var prop, i; + for (i in config) { + prop = config[i]; + if (isFunction(prop)) { + this[i] = prop; + } else { + this['_' + i] = prop; + } + } + this._config = config; + // Lenient ordinal parsing accepts just a number in addition to + // number + (possibly) stuff coming from _dayOfMonthOrdinalParse. + // TODO: Remove "ordinalParse" fallback in next major release. + this._dayOfMonthOrdinalParseLenient = new RegExp( + (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) + + '|' + (/\d{1,2}/).source); +} + +function mergeConfigs(parentConfig, childConfig) { + var res = extend({}, parentConfig), prop; + for (prop in childConfig) { + if (hasOwnProp(childConfig, prop)) { + if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) { + res[prop] = {}; + extend(res[prop], parentConfig[prop]); + extend(res[prop], childConfig[prop]); + } else if (childConfig[prop] != null) { + res[prop] = childConfig[prop]; + } else { + delete res[prop]; + } + } + } + for (prop in parentConfig) { + if (hasOwnProp(parentConfig, prop) && + !hasOwnProp(childConfig, prop) && + isObject(parentConfig[prop])) { + // make sure changes to properties don't modify parent config + res[prop] = extend({}, res[prop]); + } + } + return res; +} + +function Locale(config) { + if (config != null) { + this.set(config); + } +} + +var keys; + +if (Object.keys) { + keys = Object.keys; +} else { + keys = function (obj) { + var i, res = []; + for (i in obj) { + if (hasOwnProp(obj, i)) { + res.push(i); + } + } + return res; + }; +} + +var keys$1 = keys; + +var defaultCalendar = { + sameDay : '[Today at] LT', + nextDay : '[Tomorrow at] LT', + nextWeek : 'dddd [at] LT', + lastDay : '[Yesterday at] LT', + lastWeek : '[Last] dddd [at] LT', + sameElse : 'L' +}; + +function calendar (key, mom, now) { + var output = this._calendar[key] || this._calendar['sameElse']; + return isFunction(output) ? output.call(mom, now) : output; +} + +var defaultLongDateFormat = { + LTS : 'h:mm:ss A', + LT : 'h:mm A', + L : 'MM/DD/YYYY', + LL : 'MMMM D, YYYY', + LLL : 'MMMM D, YYYY h:mm A', + LLLL : 'dddd, MMMM D, YYYY h:mm A' +}; + +function longDateFormat (key) { + var format = this._longDateFormat[key], + formatUpper = this._longDateFormat[key.toUpperCase()]; + + if (format || !formatUpper) { + return format; + } + + this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + + return this._longDateFormat[key]; +} + +var defaultInvalidDate = 'Invalid date'; + +function invalidDate () { + return this._invalidDate; +} + +var defaultOrdinal = '%d'; +var defaultDayOfMonthOrdinalParse = /\d{1,2}/; + +function ordinal (number) { + return this._ordinal.replace('%d', number); +} + +var defaultRelativeTime = { + future : 'in %s', + past : '%s ago', + s : 'a few seconds', + ss : '%d seconds', + m : 'a minute', + mm : '%d minutes', + h : 'an hour', + hh : '%d hours', + d : 'a day', + dd : '%d days', + M : 'a month', + MM : '%d months', + y : 'a year', + yy : '%d years' +}; + +function relativeTime (number, withoutSuffix, string, isFuture) { + var output = this._relativeTime[string]; + return (isFunction(output)) ? + output(number, withoutSuffix, string, isFuture) : + output.replace(/%d/i, number); +} + +function pastFuture (diff, output) { + var format = this._relativeTime[diff > 0 ? 'future' : 'past']; + return isFunction(format) ? format(output) : format.replace(/%s/i, output); +} + +var aliases = {}; + +function addUnitAlias (unit, shorthand) { + var lowerCase = unit.toLowerCase(); + aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit; +} + +function normalizeUnits(units) { + return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined; +} + +function normalizeObjectUnits(inputObject) { + var normalizedInput = {}, + normalizedProp, + prop; + + for (prop in inputObject) { + if (hasOwnProp(inputObject, prop)) { + normalizedProp = normalizeUnits(prop); + if (normalizedProp) { + normalizedInput[normalizedProp] = inputObject[prop]; + } + } + } + + return normalizedInput; +} + +var priorities = {}; + +function addUnitPriority(unit, priority) { + priorities[unit] = priority; +} + +function getPrioritizedUnits(unitsObj) { + var units = []; + for (var u in unitsObj) { + units.push({unit: u, priority: priorities[u]}); + } + units.sort(function (a, b) { + return a.priority - b.priority; + }); + return units; +} + +function makeGetSet (unit, keepTime) { + return function (value) { + if (value != null) { + set$1(this, unit, value); + hooks.updateOffset(this, keepTime); + return this; + } else { + return get(this, unit); + } + }; +} + +function get (mom, unit) { + return mom.isValid() ? + mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN; +} + +function set$1 (mom, unit, value) { + if (mom.isValid()) { + mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); + } +} + +// MOMENTS + +function stringGet (units) { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](); + } + return this; +} + + +function stringSet (units, value) { + if (typeof units === 'object') { + units = normalizeObjectUnits(units); + var prioritized = getPrioritizedUnits(units); + for (var i = 0; i < prioritized.length; i++) { + this[prioritized[i].unit](units[prioritized[i].unit]); + } + } else { + units = normalizeUnits(units); + if (isFunction(this[units])) { + return this[units](value); + } + } + return this; +} + +function zeroFill(number, targetLength, forceSign) { + var absNumber = '' + Math.abs(number), + zerosToFill = targetLength - absNumber.length, + sign = number >= 0; + return (sign ? (forceSign ? '+' : '') : '-') + + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber; +} + +var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g; + +var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g; + +var formatFunctions = {}; + +var formatTokenFunctions = {}; + +// token: 'M' +// padded: ['MM', 2] +// ordinal: 'Mo' +// callback: function () { this.month() + 1 } +function addFormatToken (token, padded, ordinal, callback) { + var func = callback; + if (typeof callback === 'string') { + func = function () { + return this[callback](); + }; + } + if (token) { + formatTokenFunctions[token] = func; + } + if (padded) { + formatTokenFunctions[padded[0]] = function () { + return zeroFill(func.apply(this, arguments), padded[1], padded[2]); + }; + } + if (ordinal) { + formatTokenFunctions[ordinal] = function () { + return this.localeData().ordinal(func.apply(this, arguments), token); + }; + } +} + +function removeFormattingTokens(input) { + if (input.match(/\[[\s\S]/)) { + return input.replace(/^\[|\]$/g, ''); + } + return input.replace(/\\/g, ''); +} + +function makeFormatFunction(format) { + var array = format.match(formattingTokens), i, length; + + for (i = 0, length = array.length; i < length; i++) { + if (formatTokenFunctions[array[i]]) { + array[i] = formatTokenFunctions[array[i]]; + } else { + array[i] = removeFormattingTokens(array[i]); + } + } + + return function (mom) { + var output = '', i; + for (i = 0; i < length; i++) { + output += isFunction(array[i]) ? array[i].call(mom, format) : array[i]; + } + return output; + }; +} + +// format date using native date object +function formatMoment(m, format) { + if (!m.isValid()) { + return m.localeData().invalidDate(); + } + + format = expandFormat(format, m.localeData()); + formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format); + + return formatFunctions[format](m); +} + +function expandFormat(format, locale) { + var i = 5; + + function replaceLongDateFormatTokens(input) { + return locale.longDateFormat(input) || input; + } + + localFormattingTokens.lastIndex = 0; + while (i >= 0 && localFormattingTokens.test(format)) { + format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); + localFormattingTokens.lastIndex = 0; + i -= 1; + } + + return format; +} + +var match1 = /\d/; // 0 - 9 +var match2 = /\d\d/; // 00 - 99 +var match3 = /\d{3}/; // 000 - 999 +var match4 = /\d{4}/; // 0000 - 9999 +var match6 = /[+-]?\d{6}/; // -999999 - 999999 +var match1to2 = /\d\d?/; // 0 - 99 +var match3to4 = /\d\d\d\d?/; // 999 - 9999 +var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999 +var match1to3 = /\d{1,3}/; // 0 - 999 +var match1to4 = /\d{1,4}/; // 0 - 9999 +var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999 + +var matchUnsigned = /\d+/; // 0 - inf +var matchSigned = /[+-]?\d+/; // -inf - inf + +var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z +var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z + +var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123 + +// any word (or two) characters or numbers including two/three word month in arabic. +// includes scottish gaelic two word and hyphenated months +var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i; + + +var regexes = {}; + +function addRegexToken (token, regex, strictRegex) { + regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) { + return (isStrict && strictRegex) ? strictRegex : regex; + }; +} + +function getParseRegexForToken (token, config) { + if (!hasOwnProp(regexes, token)) { + return new RegExp(unescapeFormat(token)); + } + + return regexes[token](config._strict, config._locale); +} + +// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript +function unescapeFormat(s) { + return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { + return p1 || p2 || p3 || p4; + })); +} + +function regexEscape(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); +} + +var tokens = {}; + +function addParseToken (token, callback) { + var i, func = callback; + if (typeof token === 'string') { + token = [token]; + } + if (isNumber(callback)) { + func = function (input, array) { + array[callback] = toInt(input); + }; + } + for (i = 0; i < token.length; i++) { + tokens[token[i]] = func; + } +} + +function addWeekParseToken (token, callback) { + addParseToken(token, function (input, array, config, token) { + config._w = config._w || {}; + callback(input, config._w, config, token); + }); +} + +function addTimeToArrayFromToken(token, input, config) { + if (input != null && hasOwnProp(tokens, token)) { + tokens[token](input, config._a, config, token); + } +} + +var YEAR = 0; +var MONTH = 1; +var DATE = 2; +var HOUR = 3; +var MINUTE = 4; +var SECOND = 5; +var MILLISECOND = 6; +var WEEK = 7; +var WEEKDAY = 8; + +var indexOf; + +if (Array.prototype.indexOf) { + indexOf = Array.prototype.indexOf; +} else { + indexOf = function (o) { + // I know + var i; + for (i = 0; i < this.length; ++i) { + if (this[i] === o) { + return i; + } + } + return -1; + }; +} + +var indexOf$1 = indexOf; + +function daysInMonth(year, month) { + return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); +} + +// FORMATTING + +addFormatToken('M', ['MM', 2], 'Mo', function () { + return this.month() + 1; +}); + +addFormatToken('MMM', 0, 0, function (format) { + return this.localeData().monthsShort(this, format); +}); + +addFormatToken('MMMM', 0, 0, function (format) { + return this.localeData().months(this, format); +}); + +// ALIASES + +addUnitAlias('month', 'M'); + +// PRIORITY + +addUnitPriority('month', 8); + +// PARSING + +addRegexToken('M', match1to2); +addRegexToken('MM', match1to2, match2); +addRegexToken('MMM', function (isStrict, locale) { + return locale.monthsShortRegex(isStrict); +}); +addRegexToken('MMMM', function (isStrict, locale) { + return locale.monthsRegex(isStrict); +}); + +addParseToken(['M', 'MM'], function (input, array) { + array[MONTH] = toInt(input) - 1; +}); + +addParseToken(['MMM', 'MMMM'], function (input, array, config, token) { + var month = config._locale.monthsParse(input, token, config._strict); + // if we didn't find a month name, mark the date as invalid. + if (month != null) { + array[MONTH] = month; + } else { + getParsingFlags(config).invalidMonth = input; + } +}); + +// LOCALES + +var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/; +var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'); +function localeMonths (m, format) { + if (!m) { + return isArray(this._months) ? this._months : + this._months['standalone']; + } + return isArray(this._months) ? this._months[m.month()] : + this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()]; +} + +var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'); +function localeMonthsShort (m, format) { + if (!m) { + return isArray(this._monthsShort) ? this._monthsShort : + this._monthsShort['standalone']; + } + return isArray(this._monthsShort) ? this._monthsShort[m.month()] : + this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()]; +} + +function handleStrictParse(monthName, format, strict) { + var i, ii, mom, llc = monthName.toLocaleLowerCase(); + if (!this._monthsParse) { + // this is not used + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + for (i = 0; i < 12; ++i) { + mom = createUTC([2000, i]); + this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase(); + this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase(); + } + } + + if (strict) { + if (format === 'MMM') { + ii = indexOf$1.call(this._shortMonthsParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf$1.call(this._longMonthsParse, llc); + return ii !== -1 ? ii : null; + } + } else { + if (format === 'MMM') { + ii = indexOf$1.call(this._shortMonthsParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf$1.call(this._longMonthsParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf$1.call(this._longMonthsParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf$1.call(this._shortMonthsParse, llc); + return ii !== -1 ? ii : null; + } + } +} + +function localeMonthsParse (monthName, format, strict) { + var i, mom, regex; + + if (this._monthsParseExact) { + return handleStrictParse.call(this, monthName, format, strict); + } + + if (!this._monthsParse) { + this._monthsParse = []; + this._longMonthsParse = []; + this._shortMonthsParse = []; + } + + // TODO: add sorting + // Sorting makes sure if one month (or abbr) is a prefix of another + // see sorting in computeMonthsParse + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, i]); + if (strict && !this._longMonthsParse[i]) { + this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i'); + this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i'); + } + if (!strict && !this._monthsParse[i]) { + regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); + this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) { + return i; + } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) { + return i; + } else if (!strict && this._monthsParse[i].test(monthName)) { + return i; + } + } +} + +// MOMENTS + +function setMonth (mom, value) { + var dayOfMonth; + + if (!mom.isValid()) { + // No op + return mom; + } + + if (typeof value === 'string') { + if (/^\d+$/.test(value)) { + value = toInt(value); + } else { + value = mom.localeData().monthsParse(value); + // TODO: Another silent failure? + if (!isNumber(value)) { + return mom; + } + } + } + + dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value)); + mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); + return mom; +} + +function getSetMonth (value) { + if (value != null) { + setMonth(this, value); + hooks.updateOffset(this, true); + return this; + } else { + return get(this, 'Month'); + } +} + +function getDaysInMonth () { + return daysInMonth(this.year(), this.month()); +} + +var defaultMonthsShortRegex = matchWord; +function monthsShortRegex (isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsShortStrictRegex; + } else { + return this._monthsShortRegex; + } + } else { + if (!hasOwnProp(this, '_monthsShortRegex')) { + this._monthsShortRegex = defaultMonthsShortRegex; + } + return this._monthsShortStrictRegex && isStrict ? + this._monthsShortStrictRegex : this._monthsShortRegex; + } +} + +var defaultMonthsRegex = matchWord; +function monthsRegex (isStrict) { + if (this._monthsParseExact) { + if (!hasOwnProp(this, '_monthsRegex')) { + computeMonthsParse.call(this); + } + if (isStrict) { + return this._monthsStrictRegex; + } else { + return this._monthsRegex; + } + } else { + if (!hasOwnProp(this, '_monthsRegex')) { + this._monthsRegex = defaultMonthsRegex; + } + return this._monthsStrictRegex && isStrict ? + this._monthsStrictRegex : this._monthsRegex; + } +} + +function computeMonthsParse () { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var shortPieces = [], longPieces = [], mixedPieces = [], + i, mom; + for (i = 0; i < 12; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, i]); + shortPieces.push(this.monthsShort(mom, '')); + longPieces.push(this.months(mom, '')); + mixedPieces.push(this.months(mom, '')); + mixedPieces.push(this.monthsShort(mom, '')); + } + // Sorting makes sure if one month (or abbr) is a prefix of another it + // will match the longer piece. + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + for (i = 0; i < 12; i++) { + shortPieces[i] = regexEscape(shortPieces[i]); + longPieces[i] = regexEscape(longPieces[i]); + } + for (i = 0; i < 24; i++) { + mixedPieces[i] = regexEscape(mixedPieces[i]); + } + + this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._monthsShortRegex = this._monthsRegex; + this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i'); + this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i'); +} + +// FORMATTING + +addFormatToken('Y', 0, 0, function () { + var y = this.year(); + return y <= 9999 ? '' + y : '+' + y; +}); + +addFormatToken(0, ['YY', 2], 0, function () { + return this.year() % 100; +}); + +addFormatToken(0, ['YYYY', 4], 0, 'year'); +addFormatToken(0, ['YYYYY', 5], 0, 'year'); +addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); + +// ALIASES + +addUnitAlias('year', 'y'); + +// PRIORITIES + +addUnitPriority('year', 1); + +// PARSING + +addRegexToken('Y', matchSigned); +addRegexToken('YY', match1to2, match2); +addRegexToken('YYYY', match1to4, match4); +addRegexToken('YYYYY', match1to6, match6); +addRegexToken('YYYYYY', match1to6, match6); + +addParseToken(['YYYYY', 'YYYYYY'], YEAR); +addParseToken('YYYY', function (input, array) { + array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input); +}); +addParseToken('YY', function (input, array) { + array[YEAR] = hooks.parseTwoDigitYear(input); +}); +addParseToken('Y', function (input, array) { + array[YEAR] = parseInt(input, 10); +}); + +// HELPERS + +function daysInYear(year) { + return isLeapYear(year) ? 366 : 365; +} + +function isLeapYear(year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; +} + +// HOOKS + +hooks.parseTwoDigitYear = function (input) { + return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); +}; + +// MOMENTS + +var getSetYear = makeGetSet('FullYear', true); + +function getIsLeapYear () { + return isLeapYear(this.year()); +} + +function createDate (y, m, d, h, M, s, ms) { + // can't just apply() to create a date: + // https://stackoverflow.com/q/181348 + var date = new Date(y, m, d, h, M, s, ms); + + // the date constructor remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0 && isFinite(date.getFullYear())) { + date.setFullYear(y); + } + return date; +} + +function createUTCDate (y) { + var date = new Date(Date.UTC.apply(null, arguments)); + + // the Date.UTC function remaps years 0-99 to 1900-1999 + if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) { + date.setUTCFullYear(y); + } + return date; +} + +// start-of-first-week - start-of-year +function firstWeekOffset(year, dow, doy) { + var // first-week day -- which january is always in the first week (4 for iso, 1 for other) + fwd = 7 + dow - doy, + // first-week day local weekday -- which local weekday is fwd + fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7; + + return -fwdlw + fwd - 1; +} + +// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday +function dayOfYearFromWeeks(year, week, weekday, dow, doy) { + var localWeekday = (7 + weekday - dow) % 7, + weekOffset = firstWeekOffset(year, dow, doy), + dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, + resYear, resDayOfYear; + + if (dayOfYear <= 0) { + resYear = year - 1; + resDayOfYear = daysInYear(resYear) + dayOfYear; + } else if (dayOfYear > daysInYear(year)) { + resYear = year + 1; + resDayOfYear = dayOfYear - daysInYear(year); + } else { + resYear = year; + resDayOfYear = dayOfYear; + } + + return { + year: resYear, + dayOfYear: resDayOfYear + }; +} + +function weekOfYear(mom, dow, doy) { + var weekOffset = firstWeekOffset(mom.year(), dow, doy), + week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1, + resWeek, resYear; + + if (week < 1) { + resYear = mom.year() - 1; + resWeek = week + weeksInYear(resYear, dow, doy); + } else if (week > weeksInYear(mom.year(), dow, doy)) { + resWeek = week - weeksInYear(mom.year(), dow, doy); + resYear = mom.year() + 1; + } else { + resYear = mom.year(); + resWeek = week; + } + + return { + week: resWeek, + year: resYear + }; +} + +function weeksInYear(year, dow, doy) { + var weekOffset = firstWeekOffset(year, dow, doy), + weekOffsetNext = firstWeekOffset(year + 1, dow, doy); + return (daysInYear(year) - weekOffset + weekOffsetNext) / 7; +} + +// FORMATTING + +addFormatToken('w', ['ww', 2], 'wo', 'week'); +addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); + +// ALIASES + +addUnitAlias('week', 'w'); +addUnitAlias('isoWeek', 'W'); + +// PRIORITIES + +addUnitPriority('week', 5); +addUnitPriority('isoWeek', 5); + +// PARSING + +addRegexToken('w', match1to2); +addRegexToken('ww', match1to2, match2); +addRegexToken('W', match1to2); +addRegexToken('WW', match1to2, match2); + +addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) { + week[token.substr(0, 1)] = toInt(input); +}); + +// HELPERS + +// LOCALES + +function localeWeek (mom) { + return weekOfYear(mom, this._week.dow, this._week.doy).week; +} + +var defaultLocaleWeek = { + dow : 0, // Sunday is the first day of the week. + doy : 6 // The week that contains Jan 1st is the first week of the year. +}; + +function localeFirstDayOfWeek () { + return this._week.dow; +} + +function localeFirstDayOfYear () { + return this._week.doy; +} + +// MOMENTS + +function getSetWeek (input) { + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); +} + +function getSetISOWeek (input) { + var week = weekOfYear(this, 1, 4).week; + return input == null ? week : this.add((input - week) * 7, 'd'); +} + +// FORMATTING + +addFormatToken('d', 0, 'do', 'day'); + +addFormatToken('dd', 0, 0, function (format) { + return this.localeData().weekdaysMin(this, format); +}); + +addFormatToken('ddd', 0, 0, function (format) { + return this.localeData().weekdaysShort(this, format); +}); + +addFormatToken('dddd', 0, 0, function (format) { + return this.localeData().weekdays(this, format); +}); + +addFormatToken('e', 0, 0, 'weekday'); +addFormatToken('E', 0, 0, 'isoWeekday'); + +// ALIASES + +addUnitAlias('day', 'd'); +addUnitAlias('weekday', 'e'); +addUnitAlias('isoWeekday', 'E'); + +// PRIORITY +addUnitPriority('day', 11); +addUnitPriority('weekday', 11); +addUnitPriority('isoWeekday', 11); + +// PARSING + +addRegexToken('d', match1to2); +addRegexToken('e', match1to2); +addRegexToken('E', match1to2); +addRegexToken('dd', function (isStrict, locale) { + return locale.weekdaysMinRegex(isStrict); +}); +addRegexToken('ddd', function (isStrict, locale) { + return locale.weekdaysShortRegex(isStrict); +}); +addRegexToken('dddd', function (isStrict, locale) { + return locale.weekdaysRegex(isStrict); +}); + +addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) { + var weekday = config._locale.weekdaysParse(input, token, config._strict); + // if we didn't get a weekday name, mark the date as invalid + if (weekday != null) { + week.d = weekday; + } else { + getParsingFlags(config).invalidWeekday = input; + } +}); + +addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) { + week[token] = toInt(input); +}); + +// HELPERS + +function parseWeekday(input, locale) { + if (typeof input !== 'string') { + return input; + } + + if (!isNaN(input)) { + return parseInt(input, 10); + } + + input = locale.weekdaysParse(input); + if (typeof input === 'number') { + return input; + } + + return null; +} + +function parseIsoWeekday(input, locale) { + if (typeof input === 'string') { + return locale.weekdaysParse(input) % 7 || 7; + } + return isNaN(input) ? null : input; +} + +// LOCALES + +var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'); +function localeWeekdays (m, format) { + if (!m) { + return isArray(this._weekdays) ? this._weekdays : + this._weekdays['standalone']; + } + return isArray(this._weekdays) ? this._weekdays[m.day()] : + this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()]; +} + +var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'); +function localeWeekdaysShort (m) { + return (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort; +} + +var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'); +function localeWeekdaysMin (m) { + return (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin; +} + +function handleStrictParse$1(weekdayName, format, strict) { + var i, ii, mom, llc = weekdayName.toLocaleLowerCase(); + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._shortWeekdaysParse = []; + this._minWeekdaysParse = []; + + for (i = 0; i < 7; ++i) { + mom = createUTC([2000, 1]).day(i); + this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase(); + this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase(); + this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase(); + } + } + + if (strict) { + if (format === 'dddd') { + ii = indexOf$1.call(this._weekdaysParse, llc); + return ii !== -1 ? ii : null; + } else if (format === 'ddd') { + ii = indexOf$1.call(this._shortWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf$1.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } + } else { + if (format === 'dddd') { + ii = indexOf$1.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf$1.call(this._shortWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf$1.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else if (format === 'ddd') { + ii = indexOf$1.call(this._shortWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf$1.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf$1.call(this._minWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } else { + ii = indexOf$1.call(this._minWeekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf$1.call(this._weekdaysParse, llc); + if (ii !== -1) { + return ii; + } + ii = indexOf$1.call(this._shortWeekdaysParse, llc); + return ii !== -1 ? ii : null; + } + } +} + +function localeWeekdaysParse (weekdayName, format, strict) { + var i, mom, regex; + + if (this._weekdaysParseExact) { + return handleStrictParse$1.call(this, weekdayName, format, strict); + } + + if (!this._weekdaysParse) { + this._weekdaysParse = []; + this._minWeekdaysParse = []; + this._shortWeekdaysParse = []; + this._fullWeekdaysParse = []; + } + + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + + mom = createUTC([2000, 1]).day(i); + if (strict && !this._fullWeekdaysParse[i]) { + this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i'); + this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i'); + this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i'); + } + if (!this._weekdaysParse[i]) { + regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); + this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); + } + // test the regex + if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) { + return i; + } else if (!strict && this._weekdaysParse[i].test(weekdayName)) { + return i; + } + } +} + +// MOMENTS + +function getSetDayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); + if (input != null) { + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); + } else { + return day; + } +} + +function getSetLocaleDayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); +} + +function getSetISODayOfWeek (input) { + if (!this.isValid()) { + return input != null ? this : NaN; + } + + // behaves the same as moment#day except + // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) + // as a setter, sunday should belong to the previous week. + + if (input != null) { + var weekday = parseIsoWeekday(input, this.localeData()); + return this.day(this.day() % 7 ? weekday : weekday - 7); + } else { + return this.day() || 7; + } +} + +var defaultWeekdaysRegex = matchWord; +function weekdaysRegex (isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysStrictRegex; + } else { + return this._weekdaysRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysRegex')) { + this._weekdaysRegex = defaultWeekdaysRegex; + } + return this._weekdaysStrictRegex && isStrict ? + this._weekdaysStrictRegex : this._weekdaysRegex; + } +} + +var defaultWeekdaysShortRegex = matchWord; +function weekdaysShortRegex (isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysShortStrictRegex; + } else { + return this._weekdaysShortRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysShortRegex')) { + this._weekdaysShortRegex = defaultWeekdaysShortRegex; + } + return this._weekdaysShortStrictRegex && isStrict ? + this._weekdaysShortStrictRegex : this._weekdaysShortRegex; + } +} + +var defaultWeekdaysMinRegex = matchWord; +function weekdaysMinRegex (isStrict) { + if (this._weekdaysParseExact) { + if (!hasOwnProp(this, '_weekdaysRegex')) { + computeWeekdaysParse.call(this); + } + if (isStrict) { + return this._weekdaysMinStrictRegex; + } else { + return this._weekdaysMinRegex; + } + } else { + if (!hasOwnProp(this, '_weekdaysMinRegex')) { + this._weekdaysMinRegex = defaultWeekdaysMinRegex; + } + return this._weekdaysMinStrictRegex && isStrict ? + this._weekdaysMinStrictRegex : this._weekdaysMinRegex; + } +} + + +function computeWeekdaysParse () { + function cmpLenRev(a, b) { + return b.length - a.length; + } + + var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [], + i, mom, minp, shortp, longp; + for (i = 0; i < 7; i++) { + // make the regex if we don't have it already + mom = createUTC([2000, 1]).day(i); + minp = this.weekdaysMin(mom, ''); + shortp = this.weekdaysShort(mom, ''); + longp = this.weekdays(mom, ''); + minPieces.push(minp); + shortPieces.push(shortp); + longPieces.push(longp); + mixedPieces.push(minp); + mixedPieces.push(shortp); + mixedPieces.push(longp); + } + // Sorting makes sure if one weekday (or abbr) is a prefix of another it + // will match the longer piece. + minPieces.sort(cmpLenRev); + shortPieces.sort(cmpLenRev); + longPieces.sort(cmpLenRev); + mixedPieces.sort(cmpLenRev); + for (i = 0; i < 7; i++) { + shortPieces[i] = regexEscape(shortPieces[i]); + longPieces[i] = regexEscape(longPieces[i]); + mixedPieces[i] = regexEscape(mixedPieces[i]); + } + + this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i'); + this._weekdaysShortRegex = this._weekdaysRegex; + this._weekdaysMinRegex = this._weekdaysRegex; + + this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i'); + this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i'); + this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i'); +} + +// FORMATTING + +function hFormat() { + return this.hours() % 12 || 12; +} + +function kFormat() { + return this.hours() || 24; +} + +addFormatToken('H', ['HH', 2], 0, 'hour'); +addFormatToken('h', ['hh', 2], 0, hFormat); +addFormatToken('k', ['kk', 2], 0, kFormat); + +addFormatToken('hmm', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2); +}); + +addFormatToken('hmmss', 0, 0, function () { + return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2); +}); + +addFormatToken('Hmm', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2); +}); + +addFormatToken('Hmmss', 0, 0, function () { + return '' + this.hours() + zeroFill(this.minutes(), 2) + + zeroFill(this.seconds(), 2); +}); + +function meridiem (token, lowercase) { + addFormatToken(token, 0, 0, function () { + return this.localeData().meridiem(this.hours(), this.minutes(), lowercase); + }); +} + +meridiem('a', true); +meridiem('A', false); + +// ALIASES + +addUnitAlias('hour', 'h'); + +// PRIORITY +addUnitPriority('hour', 13); + +// PARSING + +function matchMeridiem (isStrict, locale) { + return locale._meridiemParse; +} + +addRegexToken('a', matchMeridiem); +addRegexToken('A', matchMeridiem); +addRegexToken('H', match1to2); +addRegexToken('h', match1to2); +addRegexToken('k', match1to2); +addRegexToken('HH', match1to2, match2); +addRegexToken('hh', match1to2, match2); +addRegexToken('kk', match1to2, match2); + +addRegexToken('hmm', match3to4); +addRegexToken('hmmss', match5to6); +addRegexToken('Hmm', match3to4); +addRegexToken('Hmmss', match5to6); + +addParseToken(['H', 'HH'], HOUR); +addParseToken(['k', 'kk'], function (input, array, config) { + var kInput = toInt(input); + array[HOUR] = kInput === 24 ? 0 : kInput; +}); +addParseToken(['a', 'A'], function (input, array, config) { + config._isPm = config._locale.isPM(input); + config._meridiem = input; +}); +addParseToken(['h', 'hh'], function (input, array, config) { + array[HOUR] = toInt(input); + getParsingFlags(config).bigHour = true; +}); +addParseToken('hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); + getParsingFlags(config).bigHour = true; +}); +addParseToken('hmmss', function (input, array, config) { + var pos1 = input.length - 4; + var pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); + getParsingFlags(config).bigHour = true; +}); +addParseToken('Hmm', function (input, array, config) { + var pos = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos)); + array[MINUTE] = toInt(input.substr(pos)); +}); +addParseToken('Hmmss', function (input, array, config) { + var pos1 = input.length - 4; + var pos2 = input.length - 2; + array[HOUR] = toInt(input.substr(0, pos1)); + array[MINUTE] = toInt(input.substr(pos1, 2)); + array[SECOND] = toInt(input.substr(pos2)); +}); + +// LOCALES + +function localeIsPM (input) { + // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays + // Using charAt should be more compatible. + return ((input + '').toLowerCase().charAt(0) === 'p'); +} + +var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i; +function localeMeridiem (hours, minutes, isLower) { + if (hours > 11) { + return isLower ? 'pm' : 'PM'; + } else { + return isLower ? 'am' : 'AM'; + } +} + + +// MOMENTS + +// Setting the hour should keep the time, because the user explicitly +// specified which hour he wants. So trying to maintain the same hour (in +// a new timezone) makes sense. Adding/subtracting hours does not follow +// this rule. +var getSetHour = makeGetSet('Hours', true); + +// months +// week +// weekdays +// meridiem +var baseConfig = { + calendar: defaultCalendar, + longDateFormat: defaultLongDateFormat, + invalidDate: defaultInvalidDate, + ordinal: defaultOrdinal, + dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse, + relativeTime: defaultRelativeTime, + + months: defaultLocaleMonths, + monthsShort: defaultLocaleMonthsShort, + + week: defaultLocaleWeek, + + weekdays: defaultLocaleWeekdays, + weekdaysMin: defaultLocaleWeekdaysMin, + weekdaysShort: defaultLocaleWeekdaysShort, + + meridiemParse: defaultLocaleMeridiemParse +}; + +// internal storage for locale config files +var locales = {}; +var localeFamilies = {}; +var globalLocale; + +function normalizeLocale(key) { + return key ? key.toLowerCase().replace('_', '-') : key; +} + +// pick the locale from the array +// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each +// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root +function chooseLocale(names) { + var i = 0, j, next, locale, split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return null; +} + +function loadLocale(name) { + var oldLocale = null; + // TODO: Find a better way to register and load all the locales in Node + if (!locales[name] && (typeof module !== 'undefined') && + module && module.exports) { + try { + oldLocale = globalLocale._abbr; + require('./locale/' + name); + // because defineLocale currently also sets the global locale, we + // want to undo that for lazy loaded locales + getSetGlobalLocale(oldLocale); + } catch (e) { } + } + return locales[name]; +} + +// This function will load locale and then set the global locale. If +// no arguments are passed in, it will simply return the current global +// locale key. +function getSetGlobalLocale (key, values) { + var data; + if (key) { + if (isUndefined(values)) { + data = getLocale(key); + } + else { + data = defineLocale(key, values); + } + + if (data) { + // moment.duration._locale = moment._locale = data; + globalLocale = data; + } + } + + return globalLocale._abbr; +} + +function defineLocale (name, config) { + if (config !== null) { + var parentConfig = baseConfig; + config.abbr = name; + if (locales[name] != null) { + deprecateSimple('defineLocaleOverride', + 'use moment.updateLocale(localeName, config) to change ' + + 'an existing locale. moment.defineLocale(localeName, ' + + 'config) should only be used for creating a new locale ' + + 'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.'); + parentConfig = locales[name]._config; + } else if (config.parentLocale != null) { + if (locales[config.parentLocale] != null) { + parentConfig = locales[config.parentLocale]._config; + } else { + if (!localeFamilies[config.parentLocale]) { + localeFamilies[config.parentLocale] = []; + } + localeFamilies[config.parentLocale].push({ + name: name, + config: config + }); + return null; + } + } + locales[name] = new Locale(mergeConfigs(parentConfig, config)); + + if (localeFamilies[name]) { + localeFamilies[name].forEach(function (x) { + defineLocale(x.name, x.config); + }); + } + + // backwards compat for now: also set the locale + // make sure we set the locale AFTER all child locales have been + // created, so we won't end up with the child locale set. + getSetGlobalLocale(name); + + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } +} + +function updateLocale(name, config) { + if (config != null) { + var locale, parentConfig = baseConfig; + // MERGE + if (locales[name] != null) { + parentConfig = locales[name]._config; + } + config = mergeConfigs(parentConfig, config); + locale = new Locale(config); + locale.parentLocale = locales[name]; + locales[name] = locale; + + // backwards compat for now: also set the locale + getSetGlobalLocale(name); + } else { + // pass null for config to unupdate, useful for tests + if (locales[name] != null) { + if (locales[name].parentLocale != null) { + locales[name] = locales[name].parentLocale; + } else if (locales[name] != null) { + delete locales[name]; + } + } + } + return locales[name]; +} + +// returns locale data +function getLocale (key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return globalLocale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); +} + +function listLocales() { + return keys$1(locales); +} + +function checkOverflow (m) { + var overflow; + var a = m._a; + + if (a && getParsingFlags(m).overflow === -2) { + overflow = + a[MONTH] < 0 || a[MONTH] > 11 ? MONTH : + a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE : + a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR : + a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE : + a[SECOND] < 0 || a[SECOND] > 59 ? SECOND : + a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND : + -1; + + if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { + overflow = DATE; + } + if (getParsingFlags(m)._overflowWeeks && overflow === -1) { + overflow = WEEK; + } + if (getParsingFlags(m)._overflowWeekday && overflow === -1) { + overflow = WEEKDAY; + } + + getParsingFlags(m).overflow = overflow; + } + + return m; +} + +// iso 8601 regex +// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) +var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/; +var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/; + +var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/; + +var isoDates = [ + ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/], + ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/], + ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/], + ['GGGG-[W]WW', /\d{4}-W\d\d/, false], + ['YYYY-DDD', /\d{4}-\d{3}/], + ['YYYY-MM', /\d{4}-\d\d/, false], + ['YYYYYYMMDD', /[+-]\d{10}/], + ['YYYYMMDD', /\d{8}/], + // YYYYMM is NOT allowed by the standard + ['GGGG[W]WWE', /\d{4}W\d{3}/], + ['GGGG[W]WW', /\d{4}W\d{2}/, false], + ['YYYYDDD', /\d{7}/] +]; + +// iso time formats and regexes +var isoTimes = [ + ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/], + ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/], + ['HH:mm:ss', /\d\d:\d\d:\d\d/], + ['HH:mm', /\d\d:\d\d/], + ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/], + ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/], + ['HHmmss', /\d\d\d\d\d\d/], + ['HHmm', /\d\d\d\d/], + ['HH', /\d\d/] +]; + +var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; + +// date from iso format +function configFromISO(config) { + var i, l, + string = config._i, + match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string), + allowTime, dateFormat, timeFormat, tzFormat; + + if (match) { + getParsingFlags(config).iso = true; + + for (i = 0, l = isoDates.length; i < l; i++) { + if (isoDates[i][1].exec(match[1])) { + dateFormat = isoDates[i][0]; + allowTime = isoDates[i][2] !== false; + break; + } + } + if (dateFormat == null) { + config._isValid = false; + return; + } + if (match[3]) { + for (i = 0, l = isoTimes.length; i < l; i++) { + if (isoTimes[i][1].exec(match[3])) { + // match[2] should be 'T' or space + timeFormat = (match[2] || ' ') + isoTimes[i][0]; + break; + } + } + if (timeFormat == null) { + config._isValid = false; + return; + } + } + if (!allowTime && timeFormat != null) { + config._isValid = false; + return; + } + if (match[4]) { + if (tzRegex.exec(match[4])) { + tzFormat = 'Z'; + } else { + config._isValid = false; + return; + } + } + config._f = dateFormat + (timeFormat || '') + (tzFormat || ''); + configFromStringAndFormat(config); + } else { + config._isValid = false; + } +} + +// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3 +var basicRfcRegex = /^((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d?\d\s(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?:\d\d)?\d\d\s)(\d\d:\d\d)(\:\d\d)?(\s(?:UT|GMT|[ECMP][SD]T|[A-IK-Za-ik-z]|[+-]\d{4}))$/; + +// date and time from ref 2822 format +function configFromRFC2822(config) { + var string, match, dayFormat, + dateFormat, timeFormat, tzFormat; + var timezones = { + ' GMT': ' +0000', + ' EDT': ' -0400', + ' EST': ' -0500', + ' CDT': ' -0500', + ' CST': ' -0600', + ' MDT': ' -0600', + ' MST': ' -0700', + ' PDT': ' -0700', + ' PST': ' -0800' + }; + var military = 'YXWVUTSRQPONZABCDEFGHIKLM'; + var timezone, timezoneIndex; + + string = config._i + .replace(/\([^\)]*\)|[\n\t]/g, ' ') // Remove comments and folding whitespace + .replace(/(\s\s+)/g, ' ') // Replace multiple-spaces with a single space + .replace(/^\s|\s$/g, ''); // Remove leading and trailing spaces + match = basicRfcRegex.exec(string); + + if (match) { + dayFormat = match[1] ? 'ddd' + ((match[1].length === 5) ? ', ' : ' ') : ''; + dateFormat = 'D MMM ' + ((match[2].length > 10) ? 'YYYY ' : 'YY '); + timeFormat = 'HH:mm' + (match[4] ? ':ss' : ''); + + // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check. + if (match[1]) { // day of week given + var momentDate = new Date(match[2]); + var momentDay = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][momentDate.getDay()]; + + if (match[1].substr(0,3) !== momentDay) { + getParsingFlags(config).weekdayMismatch = true; + config._isValid = false; + return; + } + } + + switch (match[5].length) { + case 2: // military + if (timezoneIndex === 0) { + timezone = ' +0000'; + } else { + timezoneIndex = military.indexOf(match[5][1].toUpperCase()) - 12; + timezone = ((timezoneIndex < 0) ? ' -' : ' +') + + (('' + timezoneIndex).replace(/^-?/, '0')).match(/..$/)[0] + '00'; + } + break; + case 4: // Zone + timezone = timezones[match[5]]; + break; + default: // UT or +/-9999 + timezone = timezones[' GMT']; + } + match[5] = timezone; + config._i = match.splice(1).join(''); + tzFormat = ' ZZ'; + config._f = dayFormat + dateFormat + timeFormat + tzFormat; + configFromStringAndFormat(config); + getParsingFlags(config).rfc2822 = true; + } else { + config._isValid = false; + } +} + +// date from iso format or fallback +function configFromString(config) { + var matched = aspNetJsonRegex.exec(config._i); + + if (matched !== null) { + config._d = new Date(+matched[1]); + return; + } + + configFromISO(config); + if (config._isValid === false) { + delete config._isValid; + } else { + return; + } + + configFromRFC2822(config); + if (config._isValid === false) { + delete config._isValid; + } else { + return; + } + + // Final attempt, use Input Fallback + hooks.createFromInputFallback(config); +} + +hooks.createFromInputFallback = deprecate( + 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' + + 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' + + 'discouraged and will be removed in an upcoming major release. Please refer to ' + + 'http://momentjs.com/guides/#/warnings/js-date/ for more info.', + function (config) { + config._d = new Date(config._i + (config._useUTC ? ' UTC' : '')); + } +); + +// Pick the first defined of two or three arguments. +function defaults(a, b, c) { + if (a != null) { + return a; + } + if (b != null) { + return b; + } + return c; +} + +function currentDateArray(config) { + // hooks is actually the exported moment object + var nowValue = new Date(hooks.now()); + if (config._useUTC) { + return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()]; + } + return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()]; +} + +// convert an array to a date. +// the array should mirror the parameters below +// note: all values past the year are optional and will default to the lowest possible value. +// [year, month, day , hour, minute, second, millisecond] +function configFromArray (config) { + var i, date, input = [], currentDate, yearToUse; + + if (config._d) { + return; + } + + currentDate = currentDateArray(config); + + //compute day of the year from weeks and weekdays + if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { + dayOfYearFromWeekInfo(config); + } + + //if the day of the year is set, figure out what it is + if (config._dayOfYear != null) { + yearToUse = defaults(config._a[YEAR], currentDate[YEAR]); + + if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) { + getParsingFlags(config)._overflowDayOfYear = true; + } + + date = createUTCDate(yearToUse, 0, config._dayOfYear); + config._a[MONTH] = date.getUTCMonth(); + config._a[DATE] = date.getUTCDate(); + } + + // Default to current date. + // * if no year, month, day of month are given, default to today + // * if day of month is given, default month and year + // * if month is given, default only year + // * if year is given, don't default anything + for (i = 0; i < 3 && config._a[i] == null; ++i) { + config._a[i] = input[i] = currentDate[i]; + } + + // Zero out whatever was not defaulted, including time + for (; i < 7; i++) { + config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; + } + + // Check for 24:00:00.000 + if (config._a[HOUR] === 24 && + config._a[MINUTE] === 0 && + config._a[SECOND] === 0 && + config._a[MILLISECOND] === 0) { + config._nextDay = true; + config._a[HOUR] = 0; + } + + config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input); + // Apply timezone offset from input. The actual utcOffset can be changed + // with parseZone. + if (config._tzm != null) { + config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm); + } + + if (config._nextDay) { + config._a[HOUR] = 24; + } +} + +function dayOfYearFromWeekInfo(config) { + var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow; + + w = config._w; + if (w.GG != null || w.W != null || w.E != null) { + dow = 1; + doy = 4; + + // TODO: We need to take the current isoWeekYear, but that depends on + // how we interpret now (local, utc, fixed offset). So create + // a now version of current config (take local/utc/offset flags, and + // create now). + weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year); + week = defaults(w.W, 1); + weekday = defaults(w.E, 1); + if (weekday < 1 || weekday > 7) { + weekdayOverflow = true; + } + } else { + dow = config._locale._week.dow; + doy = config._locale._week.doy; + + var curWeek = weekOfYear(createLocal(), dow, doy); + + weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); + + // Default to current week. + week = defaults(w.w, curWeek.week); + + if (w.d != null) { + // weekday -- low day numbers are considered next week + weekday = w.d; + if (weekday < 0 || weekday > 6) { + weekdayOverflow = true; + } + } else if (w.e != null) { + // local weekday -- counting starts from begining of week + weekday = w.e + dow; + if (w.e < 0 || w.e > 6) { + weekdayOverflow = true; + } + } else { + // default to begining of week + weekday = dow; + } + } + if (week < 1 || week > weeksInYear(weekYear, dow, doy)) { + getParsingFlags(config)._overflowWeeks = true; + } else if (weekdayOverflow != null) { + getParsingFlags(config)._overflowWeekday = true; + } else { + temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy); + config._a[YEAR] = temp.year; + config._dayOfYear = temp.dayOfYear; + } +} + +// constant that refers to the ISO standard +hooks.ISO_8601 = function () {}; + +// constant that refers to the RFC 2822 form +hooks.RFC_2822 = function () {}; + +// date from string and format string +function configFromStringAndFormat(config) { + // TODO: Move this to another part of the creation flow to prevent circular deps + if (config._f === hooks.ISO_8601) { + configFromISO(config); + return; + } + if (config._f === hooks.RFC_2822) { + configFromRFC2822(config); + return; + } + config._a = []; + getParsingFlags(config).empty = true; + + // This array is used to make a Date, either with `new Date` or `Date.UTC` + var string = '' + config._i, + i, parsedInput, tokens, token, skipped, + stringLength = string.length, + totalParsedInputLength = 0; + + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; + // console.log('token', token, 'parsedInput', parsedInput, + // 'regex', getParseRegexForToken(token, config)); + if (parsedInput) { + skipped = string.substr(0, string.indexOf(parsedInput)); + if (skipped.length > 0) { + getParsingFlags(config).unusedInput.push(skipped); + } + string = string.slice(string.indexOf(parsedInput) + parsedInput.length); + totalParsedInputLength += parsedInput.length; + } + // don't parse if it's not a known token + if (formatTokenFunctions[token]) { + if (parsedInput) { + getParsingFlags(config).empty = false; + } + else { + getParsingFlags(config).unusedTokens.push(token); + } + addTimeToArrayFromToken(token, parsedInput, config); + } + else if (config._strict && !parsedInput) { + getParsingFlags(config).unusedTokens.push(token); + } + } + + // add remaining unparsed input length to the string + getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength; + if (string.length > 0) { + getParsingFlags(config).unusedInput.push(string); + } + + // clear _12h flag if hour is <= 12 + if (config._a[HOUR] <= 12 && + getParsingFlags(config).bigHour === true && + config._a[HOUR] > 0) { + getParsingFlags(config).bigHour = undefined; + } + + getParsingFlags(config).parsedDateParts = config._a.slice(0); + getParsingFlags(config).meridiem = config._meridiem; + // handle meridiem + config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem); + + configFromArray(config); + checkOverflow(config); +} + + +function meridiemFixWrap (locale, hour, meridiem) { + var isPm; + + if (meridiem == null) { + // nothing to do + return hour; + } + if (locale.meridiemHour != null) { + return locale.meridiemHour(hour, meridiem); + } else if (locale.isPM != null) { + // Fallback + isPm = locale.isPM(meridiem); + if (isPm && hour < 12) { + hour += 12; + } + if (!isPm && hour === 12) { + hour = 0; + } + return hour; + } else { + // this is not supposed to happen + return hour; + } +} + +// date from string and array of format strings +function configFromStringAndArray(config) { + var tempConfig, + bestMoment, + + scoreToBeat, + i, + currentScore; + + if (config._f.length === 0) { + getParsingFlags(config).invalidFormat = true; + config._d = new Date(NaN); + return; + } + + for (i = 0; i < config._f.length; i++) { + currentScore = 0; + tempConfig = copyConfig({}, config); + if (config._useUTC != null) { + tempConfig._useUTC = config._useUTC; + } + tempConfig._f = config._f[i]; + configFromStringAndFormat(tempConfig); + + if (!isValid(tempConfig)) { + continue; + } + + // if there is any input that was not parsed add a penalty for that format + currentScore += getParsingFlags(tempConfig).charsLeftOver; + + //or tokens + currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10; + + getParsingFlags(tempConfig).score = currentScore; + + if (scoreToBeat == null || currentScore < scoreToBeat) { + scoreToBeat = currentScore; + bestMoment = tempConfig; + } + } + + extend(config, bestMoment || tempConfig); +} + +function configFromObject(config) { + if (config._d) { + return; + } + + var i = normalizeObjectUnits(config._i); + config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) { + return obj && parseInt(obj, 10); + }); + + configFromArray(config); +} + +function createFromConfig (config) { + var res = new Moment(checkOverflow(prepareConfig(config))); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; +} + +function prepareConfig (config) { + var input = config._i, + format = config._f; + + config._locale = config._locale || getLocale(config._l); + + if (input === null || (format === undefined && input === '')) { + return createInvalid({nullInput: true}); + } + + if (typeof input === 'string') { + config._i = input = config._locale.preparse(input); + } + + if (isMoment(input)) { + return new Moment(checkOverflow(input)); + } else if (isDate(input)) { + config._d = input; + } else if (isArray(format)) { + configFromStringAndArray(config); + } else if (format) { + configFromStringAndFormat(config); + } else { + configFromInput(config); + } + + if (!isValid(config)) { + config._d = null; + } + + return config; +} + +function configFromInput(config) { + var input = config._i; + if (isUndefined(input)) { + config._d = new Date(hooks.now()); + } else if (isDate(input)) { + config._d = new Date(input.valueOf()); + } else if (typeof input === 'string') { + configFromString(config); + } else if (isArray(input)) { + config._a = map(input.slice(0), function (obj) { + return parseInt(obj, 10); + }); + configFromArray(config); + } else if (isObject(input)) { + configFromObject(config); + } else if (isNumber(input)) { + // from milliseconds + config._d = new Date(input); + } else { + hooks.createFromInputFallback(config); + } +} + +function createLocalOrUTC (input, format, locale, strict, isUTC) { + var c = {}; + + if (locale === true || locale === false) { + strict = locale; + locale = undefined; + } + + if ((isObject(input) && isObjectEmpty(input)) || + (isArray(input) && input.length === 0)) { + input = undefined; + } + // object construction must be done this way. + // https://github.com/moment/moment/issues/1423 + c._isAMomentObject = true; + c._useUTC = c._isUTC = isUTC; + c._l = locale; + c._i = input; + c._f = format; + c._strict = strict; + + return createFromConfig(c); +} + +function createLocal (input, format, locale, strict) { + return createLocalOrUTC(input, format, locale, strict, false); +} + +var prototypeMin = deprecate( + 'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/', + function () { + var other = createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other < this ? this : other; + } else { + return createInvalid(); + } + } +); + +var prototypeMax = deprecate( + 'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/', + function () { + var other = createLocal.apply(null, arguments); + if (this.isValid() && other.isValid()) { + return other > this ? this : other; + } else { + return createInvalid(); + } + } +); + +// Pick a moment m from moments so that m[fn](other) is true for all +// other. This relies on the function fn to be transitive. +// +// moments should either be an array of moment objects or an array, whose +// first element is an array of moment objects. +function pickBy(fn, moments) { + var res, i; + if (moments.length === 1 && isArray(moments[0])) { + moments = moments[0]; + } + if (!moments.length) { + return createLocal(); + } + res = moments[0]; + for (i = 1; i < moments.length; ++i) { + if (!moments[i].isValid() || moments[i][fn](res)) { + res = moments[i]; + } + } + return res; +} + +// TODO: Use [].sort instead? +function min () { + var args = [].slice.call(arguments, 0); + + return pickBy('isBefore', args); +} + +function max () { + var args = [].slice.call(arguments, 0); + + return pickBy('isAfter', args); +} + +var now = function () { + return Date.now ? Date.now() : +(new Date()); +}; + +var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond']; + +function isDurationValid(m) { + for (var key in m) { + if (!(ordering.indexOf(key) !== -1 && (m[key] == null || !isNaN(m[key])))) { + return false; + } + } + + var unitHasDecimal = false; + for (var i = 0; i < ordering.length; ++i) { + if (m[ordering[i]]) { + if (unitHasDecimal) { + return false; // only allow non-integers for smallest unit + } + if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) { + unitHasDecimal = true; + } + } + } + + return true; +} + +function isValid$1() { + return this._isValid; +} + +function createInvalid$1() { + return createDuration(NaN); +} + +function Duration (duration) { + var normalizedInput = normalizeObjectUnits(duration), + years = normalizedInput.year || 0, + quarters = normalizedInput.quarter || 0, + months = normalizedInput.month || 0, + weeks = normalizedInput.week || 0, + days = normalizedInput.day || 0, + hours = normalizedInput.hour || 0, + minutes = normalizedInput.minute || 0, + seconds = normalizedInput.second || 0, + milliseconds = normalizedInput.millisecond || 0; + + this._isValid = isDurationValid(normalizedInput); + + // representation for dateAddRemove + this._milliseconds = +milliseconds + + seconds * 1e3 + // 1000 + minutes * 6e4 + // 1000 * 60 + hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978 + // Because of dateAddRemove treats 24 hours as different from a + // day when working around DST, we need to store them separately + this._days = +days + + weeks * 7; + // It is impossible translate months into days without knowing + // which months you are are talking about, so we have to store + // it separately. + this._months = +months + + quarters * 3 + + years * 12; + + this._data = {}; + + this._locale = getLocale(); + + this._bubble(); +} + +function isDuration (obj) { + return obj instanceof Duration; +} + +function absRound (number) { + if (number < 0) { + return Math.round(-1 * number) * -1; + } else { + return Math.round(number); + } +} + +// FORMATTING + +function offset (token, separator) { + addFormatToken(token, 0, 0, function () { + var offset = this.utcOffset(); + var sign = '+'; + if (offset < 0) { + offset = -offset; + sign = '-'; + } + return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2); + }); +} + +offset('Z', ':'); +offset('ZZ', ''); + +// PARSING + +addRegexToken('Z', matchShortOffset); +addRegexToken('ZZ', matchShortOffset); +addParseToken(['Z', 'ZZ'], function (input, array, config) { + config._useUTC = true; + config._tzm = offsetFromString(matchShortOffset, input); +}); + +// HELPERS + +// timezone chunker +// '+10:00' > ['10', '00'] +// '-1530' > ['-15', '30'] +var chunkOffset = /([\+\-]|\d\d)/gi; + +function offsetFromString(matcher, string) { + var matches = (string || '').match(matcher); + + if (matches === null) { + return null; + } + + var chunk = matches[matches.length - 1] || []; + var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0]; + var minutes = +(parts[1] * 60) + toInt(parts[2]); + + return minutes === 0 ? + 0 : + parts[0] === '+' ? minutes : -minutes; +} + +// Return a moment from input, that is local/utc/zone equivalent to model. +function cloneWithOffset(input, model) { + var res, diff; + if (model._isUTC) { + res = model.clone(); + diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf(); + // Use low-level api, because this fn is low-level api. + res._d.setTime(res._d.valueOf() + diff); + hooks.updateOffset(res, false); + return res; + } else { + return createLocal(input).local(); + } +} + +function getDateOffset (m) { + // On Firefox.24 Date#getTimezoneOffset returns a floating point. + // https://github.com/moment/moment/pull/1871 + return -Math.round(m._d.getTimezoneOffset() / 15) * 15; +} + +// HOOKS + +// This function will be called whenever a moment is mutated. +// It is intended to keep the offset in sync with the timezone. +hooks.updateOffset = function () {}; + +// MOMENTS + +// keepLocalTime = true means only change the timezone, without +// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--> +// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset +// +0200, so we adjust the time as needed, to be valid. +// +// Keeping the time actually adds/subtracts (one hour) +// from the actual represented time. That is why we call updateOffset +// a second time. In case it wants us to change the offset again +// _changeInProgress == true case, then we have to adjust, because +// there is no such time in the given timezone. +function getSetOffset (input, keepLocalTime, keepMinutes) { + var offset = this._offset || 0, + localAdjust; + if (!this.isValid()) { + return input != null ? this : NaN; + } + if (input != null) { + if (typeof input === 'string') { + input = offsetFromString(matchShortOffset, input); + if (input === null) { + return this; + } + } else if (Math.abs(input) < 16 && !keepMinutes) { + input = input * 60; + } + if (!this._isUTC && keepLocalTime) { + localAdjust = getDateOffset(this); + } + this._offset = input; + this._isUTC = true; + if (localAdjust != null) { + this.add(localAdjust, 'm'); + } + if (offset !== input) { + if (!keepLocalTime || this._changeInProgress) { + addSubtract(this, createDuration(input - offset, 'm'), 1, false); + } else if (!this._changeInProgress) { + this._changeInProgress = true; + hooks.updateOffset(this, true); + this._changeInProgress = null; + } + } + return this; + } else { + return this._isUTC ? offset : getDateOffset(this); + } +} + +function getSetZone (input, keepLocalTime) { + if (input != null) { + if (typeof input !== 'string') { + input = -input; + } + + this.utcOffset(input, keepLocalTime); + + return this; + } else { + return -this.utcOffset(); + } +} + +function setOffsetToUTC (keepLocalTime) { + return this.utcOffset(0, keepLocalTime); +} + +function setOffsetToLocal (keepLocalTime) { + if (this._isUTC) { + this.utcOffset(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.subtract(getDateOffset(this), 'm'); + } + } + return this; +} + +function setOffsetToParsedOffset () { + if (this._tzm != null) { + this.utcOffset(this._tzm, false, true); + } else if (typeof this._i === 'string') { + var tZone = offsetFromString(matchOffset, this._i); + if (tZone != null) { + this.utcOffset(tZone); + } + else { + this.utcOffset(0, true); + } + } + return this; +} + +function hasAlignedHourOffset (input) { + if (!this.isValid()) { + return false; + } + input = input ? createLocal(input).utcOffset() : 0; + + return (this.utcOffset() - input) % 60 === 0; +} + +function isDaylightSavingTime () { + return ( + this.utcOffset() > this.clone().month(0).utcOffset() || + this.utcOffset() > this.clone().month(5).utcOffset() + ); +} + +function isDaylightSavingTimeShifted () { + if (!isUndefined(this._isDSTShifted)) { + return this._isDSTShifted; + } + + var c = {}; + + copyConfig(c, this); + c = prepareConfig(c); + + if (c._a) { + var other = c._isUTC ? createUTC(c._a) : createLocal(c._a); + this._isDSTShifted = this.isValid() && + compareArrays(c._a, other.toArray()) > 0; + } else { + this._isDSTShifted = false; + } + + return this._isDSTShifted; +} + +function isLocal () { + return this.isValid() ? !this._isUTC : false; +} + +function isUtcOffset () { + return this.isValid() ? this._isUTC : false; +} + +function isUtc () { + return this.isValid() ? this._isUTC && this._offset === 0 : false; +} + +// ASP.NET json date format regex +var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/; + +// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html +// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere +// and further modified to allow for strings containing both week and day +var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/; + +function createDuration (input, key) { + var duration = input, + // matching against regexp is expensive, do it on demand + match = null, + sign, + ret, + diffRes; + + if (isDuration(input)) { + duration = { + ms : input._milliseconds, + d : input._days, + M : input._months + }; + } else if (isNumber(input)) { + duration = {}; + if (key) { + duration[key] = input; + } else { + duration.milliseconds = input; + } + } else if (!!(match = aspNetRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y : 0, + d : toInt(match[DATE]) * sign, + h : toInt(match[HOUR]) * sign, + m : toInt(match[MINUTE]) * sign, + s : toInt(match[SECOND]) * sign, + ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match + }; + } else if (!!(match = isoRegex.exec(input))) { + sign = (match[1] === '-') ? -1 : 1; + duration = { + y : parseIso(match[2], sign), + M : parseIso(match[3], sign), + w : parseIso(match[4], sign), + d : parseIso(match[5], sign), + h : parseIso(match[6], sign), + m : parseIso(match[7], sign), + s : parseIso(match[8], sign) + }; + } else if (duration == null) {// checks for null or undefined + duration = {}; + } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to)); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; + } + + ret = new Duration(duration); + + if (isDuration(input) && hasOwnProp(input, '_locale')) { + ret._locale = input._locale; + } + + return ret; +} + +createDuration.fn = Duration.prototype; +createDuration.invalid = createInvalid$1; + +function parseIso (inp, sign) { + // We'd normally use ~~inp for this, but unfortunately it also + // converts floats to ints. + // inp may be undefined, so careful calling replace on it. + var res = inp && parseFloat(inp.replace(',', '.')); + // apply sign while we're at it + return (isNaN(res) ? 0 : res) * sign; +} + +function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; + + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + + return res; +} + +function momentsDifference(base, other) { + var res; + if (!(base.isValid() && other.isValid())) { + return {milliseconds: 0, months: 0}; + } + + other = cloneWithOffset(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; +} + +// TODO: remove 'name' arg after deprecation is removed +function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' + + 'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.'); + tmp = val; val = period; period = tmp; + } + + val = typeof val === 'string' ? +val : val; + dur = createDuration(val, period); + addSubtract(this, dur, direction); + return this; + }; +} + +function addSubtract (mom, duration, isAdding, updateOffset) { + var milliseconds = duration._milliseconds, + days = absRound(duration._days), + months = absRound(duration._months); + + if (!mom.isValid()) { + // No op + return; + } + + updateOffset = updateOffset == null ? true : updateOffset; + + if (milliseconds) { + mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding); + } + if (days) { + set$1(mom, 'Date', get(mom, 'Date') + days * isAdding); + } + if (months) { + setMonth(mom, get(mom, 'Month') + months * isAdding); + } + if (updateOffset) { + hooks.updateOffset(mom, days || months); + } +} + +var add = createAdder(1, 'add'); +var subtract = createAdder(-1, 'subtract'); + +function getCalendarFormat(myMoment, now) { + var diff = myMoment.diff(now, 'days', true); + return diff < -6 ? 'sameElse' : + diff < -1 ? 'lastWeek' : + diff < 0 ? 'lastDay' : + diff < 1 ? 'sameDay' : + diff < 2 ? 'nextDay' : + diff < 7 ? 'nextWeek' : 'sameElse'; +} + +function calendar$1 (time, formats) { + // We want to compare the start of today, vs this. + // Getting start-of-today depends on whether we're local/utc/offset or not. + var now = time || createLocal(), + sod = cloneWithOffset(now, this).startOf('day'), + format = hooks.calendarFormat(this, sod) || 'sameElse'; + + var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]); + + return this.format(output || this.localeData().calendar(format, this, createLocal(now))); +} + +function clone () { + return new Moment(this); +} + +function isAfter (input, units) { + var localInput = isMoment(input) ? input : createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(!isUndefined(units) ? units : 'millisecond'); + if (units === 'millisecond') { + return this.valueOf() > localInput.valueOf(); + } else { + return localInput.valueOf() < this.clone().startOf(units).valueOf(); + } +} + +function isBefore (input, units) { + var localInput = isMoment(input) ? input : createLocal(input); + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(!isUndefined(units) ? units : 'millisecond'); + if (units === 'millisecond') { + return this.valueOf() < localInput.valueOf(); + } else { + return this.clone().endOf(units).valueOf() < localInput.valueOf(); + } +} + +function isBetween (from, to, units, inclusivity) { + inclusivity = inclusivity || '()'; + return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) && + (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units)); +} + +function isSame (input, units) { + var localInput = isMoment(input) ? input : createLocal(input), + inputMs; + if (!(this.isValid() && localInput.isValid())) { + return false; + } + units = normalizeUnits(units || 'millisecond'); + if (units === 'millisecond') { + return this.valueOf() === localInput.valueOf(); + } else { + inputMs = localInput.valueOf(); + return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf(); + } +} + +function isSameOrAfter (input, units) { + return this.isSame(input, units) || this.isAfter(input,units); +} + +function isSameOrBefore (input, units) { + return this.isSame(input, units) || this.isBefore(input,units); +} + +function diff (input, units, asFloat) { + var that, + zoneDelta, + delta, output; + + if (!this.isValid()) { + return NaN; + } + + that = cloneWithOffset(input, this); + + if (!that.isValid()) { + return NaN; + } + + zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4; + + units = normalizeUnits(units); + + if (units === 'year' || units === 'month' || units === 'quarter') { + output = monthDiff(this, that); + if (units === 'quarter') { + output = output / 3; + } else if (units === 'year') { + output = output / 12; + } + } else { + delta = this - that; + output = units === 'second' ? delta / 1e3 : // 1000 + units === 'minute' ? delta / 6e4 : // 1000 * 60 + units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60 + units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst + units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst + delta; + } + return asFloat ? output : absFloor(output); +} + +function monthDiff (a, b) { + // difference in months + var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()), + // b is in (anchor - 1 month, anchor + 1 month) + anchor = a.clone().add(wholeMonthDiff, 'months'), + anchor2, adjust; + + if (b - anchor < 0) { + anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor - anchor2); + } else { + anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); + // linear across the month + adjust = (b - anchor) / (anchor2 - anchor); + } + + //check for negative zero, return zero if negative zero + return -(wholeMonthDiff + adjust) || 0; +} + +hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ'; +hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]'; + +function toString () { + return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); +} + +function toISOString() { + if (!this.isValid()) { + return null; + } + var m = this.clone().utc(); + if (m.year() < 0 || m.year() > 9999) { + return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); + } + if (isFunction(Date.prototype.toISOString)) { + // native implementation is ~50x faster, use it when we can + return this.toDate().toISOString(); + } + return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); +} + +/** + * Return a human readable representation of a moment that can + * also be evaluated to get a new moment which is the same + * + * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects + */ +function inspect () { + if (!this.isValid()) { + return 'moment.invalid(/* ' + this._i + ' */)'; + } + var func = 'moment'; + var zone = ''; + if (!this.isLocal()) { + func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone'; + zone = 'Z'; + } + var prefix = '[' + func + '("]'; + var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY'; + var datetime = '-MM-DD[T]HH:mm:ss.SSS'; + var suffix = zone + '[")]'; + + return this.format(prefix + year + datetime + suffix); +} + +function format (inputString) { + if (!inputString) { + inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat; + } + var output = formatMoment(this, inputString); + return this.localeData().postformat(output); +} + +function from (time, withoutSuffix) { + if (this.isValid() && + ((isMoment(time) && time.isValid()) || + createLocal(time).isValid())) { + return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } +} + +function fromNow (withoutSuffix) { + return this.from(createLocal(), withoutSuffix); +} + +function to (time, withoutSuffix) { + if (this.isValid() && + ((isMoment(time) && time.isValid()) || + createLocal(time).isValid())) { + return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix); + } else { + return this.localeData().invalidDate(); + } +} + +function toNow (withoutSuffix) { + return this.to(createLocal(), withoutSuffix); +} + +// If passed a locale key, it will set the locale for this +// instance. Otherwise, it will return the locale configuration +// variables for this instance. +function locale (key) { + var newLocaleData; + + if (key === undefined) { + return this._locale._abbr; + } else { + newLocaleData = getLocale(key); + if (newLocaleData != null) { + this._locale = newLocaleData; + } + return this; + } +} + +var lang = deprecate( + 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.', + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + return this.locale(key); + } + } +); + +function localeData () { + return this._locale; +} + +function startOf (units) { + units = normalizeUnits(units); + // the following switch intentionally omits break keywords + // to utilize falling through the cases. + switch (units) { + case 'year': + this.month(0); + /* falls through */ + case 'quarter': + case 'month': + this.date(1); + /* falls through */ + case 'week': + case 'isoWeek': + case 'day': + case 'date': + this.hours(0); + /* falls through */ + case 'hour': + this.minutes(0); + /* falls through */ + case 'minute': + this.seconds(0); + /* falls through */ + case 'second': + this.milliseconds(0); + } + + // weeks are a special case + if (units === 'week') { + this.weekday(0); + } + if (units === 'isoWeek') { + this.isoWeekday(1); + } + + // quarters are also special + if (units === 'quarter') { + this.month(Math.floor(this.month() / 3) * 3); + } + + return this; +} + +function endOf (units) { + units = normalizeUnits(units); + if (units === undefined || units === 'millisecond') { + return this; + } + + // 'date' is an alias for 'day', so it should be considered as such. + if (units === 'date') { + units = 'day'; + } + + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); +} + +function valueOf () { + return this._d.valueOf() - ((this._offset || 0) * 60000); +} + +function unix () { + return Math.floor(this.valueOf() / 1000); +} + +function toDate () { + return new Date(this.valueOf()); +} + +function toArray () { + var m = this; + return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()]; +} + +function toObject () { + var m = this; + return { + years: m.year(), + months: m.month(), + date: m.date(), + hours: m.hours(), + minutes: m.minutes(), + seconds: m.seconds(), + milliseconds: m.milliseconds() + }; +} + +function toJSON () { + // new Date(NaN).toJSON() === null + return this.isValid() ? this.toISOString() : null; +} + +function isValid$2 () { + return isValid(this); +} + +function parsingFlags () { + return extend({}, getParsingFlags(this)); +} + +function invalidAt () { + return getParsingFlags(this).overflow; +} + +function creationData() { + return { + input: this._i, + format: this._f, + locale: this._locale, + isUTC: this._isUTC, + strict: this._strict + }; +} + +// FORMATTING + +addFormatToken(0, ['gg', 2], 0, function () { + return this.weekYear() % 100; +}); + +addFormatToken(0, ['GG', 2], 0, function () { + return this.isoWeekYear() % 100; +}); + +function addWeekYearFormatToken (token, getter) { + addFormatToken(0, [token, token.length], 0, getter); +} + +addWeekYearFormatToken('gggg', 'weekYear'); +addWeekYearFormatToken('ggggg', 'weekYear'); +addWeekYearFormatToken('GGGG', 'isoWeekYear'); +addWeekYearFormatToken('GGGGG', 'isoWeekYear'); + +// ALIASES + +addUnitAlias('weekYear', 'gg'); +addUnitAlias('isoWeekYear', 'GG'); + +// PRIORITY + +addUnitPriority('weekYear', 1); +addUnitPriority('isoWeekYear', 1); + + +// PARSING + +addRegexToken('G', matchSigned); +addRegexToken('g', matchSigned); +addRegexToken('GG', match1to2, match2); +addRegexToken('gg', match1to2, match2); +addRegexToken('GGGG', match1to4, match4); +addRegexToken('gggg', match1to4, match4); +addRegexToken('GGGGG', match1to6, match6); +addRegexToken('ggggg', match1to6, match6); + +addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) { + week[token.substr(0, 2)] = toInt(input); +}); + +addWeekParseToken(['gg', 'GG'], function (input, week, config, token) { + week[token] = hooks.parseTwoDigitYear(input); +}); + +// MOMENTS + +function getSetWeekYear (input) { + return getSetWeekYearHelper.call(this, + input, + this.week(), + this.weekday(), + this.localeData()._week.dow, + this.localeData()._week.doy); +} + +function getSetISOWeekYear (input) { + return getSetWeekYearHelper.call(this, + input, this.isoWeek(), this.isoWeekday(), 1, 4); +} + +function getISOWeeksInYear () { + return weeksInYear(this.year(), 1, 4); +} + +function getWeeksInYear () { + var weekInfo = this.localeData()._week; + return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); +} + +function getSetWeekYearHelper(input, week, weekday, dow, doy) { + var weeksTarget; + if (input == null) { + return weekOfYear(this, dow, doy).year; + } else { + weeksTarget = weeksInYear(input, dow, doy); + if (week > weeksTarget) { + week = weeksTarget; + } + return setWeekAll.call(this, input, week, weekday, dow, doy); + } +} + +function setWeekAll(weekYear, week, weekday, dow, doy) { + var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy), + date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear); + + this.year(date.getUTCFullYear()); + this.month(date.getUTCMonth()); + this.date(date.getUTCDate()); + return this; +} + +// FORMATTING + +addFormatToken('Q', 0, 'Qo', 'quarter'); + +// ALIASES + +addUnitAlias('quarter', 'Q'); + +// PRIORITY + +addUnitPriority('quarter', 7); + +// PARSING + +addRegexToken('Q', match1); +addParseToken('Q', function (input, array) { + array[MONTH] = (toInt(input) - 1) * 3; +}); + +// MOMENTS + +function getSetQuarter (input) { + return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); +} + +// FORMATTING + +addFormatToken('D', ['DD', 2], 'Do', 'date'); + +// ALIASES + +addUnitAlias('date', 'D'); + +// PRIOROITY +addUnitPriority('date', 9); + +// PARSING + +addRegexToken('D', match1to2); +addRegexToken('DD', match1to2, match2); +addRegexToken('Do', function (isStrict, locale) { + // TODO: Remove "ordinalParse" fallback in next major release. + return isStrict ? + (locale._dayOfMonthOrdinalParse || locale._ordinalParse) : + locale._dayOfMonthOrdinalParseLenient; +}); + +addParseToken(['D', 'DD'], DATE); +addParseToken('Do', function (input, array) { + array[DATE] = toInt(input.match(match1to2)[0], 10); +}); + +// MOMENTS + +var getSetDayOfMonth = makeGetSet('Date', true); + +// FORMATTING + +addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); + +// ALIASES + +addUnitAlias('dayOfYear', 'DDD'); + +// PRIORITY +addUnitPriority('dayOfYear', 4); + +// PARSING + +addRegexToken('DDD', match1to3); +addRegexToken('DDDD', match3); +addParseToken(['DDD', 'DDDD'], function (input, array, config) { + config._dayOfYear = toInt(input); +}); + +// HELPERS + +// MOMENTS + +function getSetDayOfYear (input) { + var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1; + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); +} + +// FORMATTING + +addFormatToken('m', ['mm', 2], 0, 'minute'); + +// ALIASES + +addUnitAlias('minute', 'm'); + +// PRIORITY + +addUnitPriority('minute', 14); + +// PARSING + +addRegexToken('m', match1to2); +addRegexToken('mm', match1to2, match2); +addParseToken(['m', 'mm'], MINUTE); + +// MOMENTS + +var getSetMinute = makeGetSet('Minutes', false); + +// FORMATTING + +addFormatToken('s', ['ss', 2], 0, 'second'); + +// ALIASES + +addUnitAlias('second', 's'); + +// PRIORITY + +addUnitPriority('second', 15); + +// PARSING + +addRegexToken('s', match1to2); +addRegexToken('ss', match1to2, match2); +addParseToken(['s', 'ss'], SECOND); + +// MOMENTS + +var getSetSecond = makeGetSet('Seconds', false); + +// FORMATTING + +addFormatToken('S', 0, 0, function () { + return ~~(this.millisecond() / 100); +}); + +addFormatToken(0, ['SS', 2], 0, function () { + return ~~(this.millisecond() / 10); +}); + +addFormatToken(0, ['SSS', 3], 0, 'millisecond'); +addFormatToken(0, ['SSSS', 4], 0, function () { + return this.millisecond() * 10; +}); +addFormatToken(0, ['SSSSS', 5], 0, function () { + return this.millisecond() * 100; +}); +addFormatToken(0, ['SSSSSS', 6], 0, function () { + return this.millisecond() * 1000; +}); +addFormatToken(0, ['SSSSSSS', 7], 0, function () { + return this.millisecond() * 10000; +}); +addFormatToken(0, ['SSSSSSSS', 8], 0, function () { + return this.millisecond() * 100000; +}); +addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { + return this.millisecond() * 1000000; +}); + + +// ALIASES + +addUnitAlias('millisecond', 'ms'); + +// PRIORITY + +addUnitPriority('millisecond', 16); + +// PARSING + +addRegexToken('S', match1to3, match1); +addRegexToken('SS', match1to3, match2); +addRegexToken('SSS', match1to3, match3); + +var token; +for (token = 'SSSS'; token.length <= 9; token += 'S') { + addRegexToken(token, matchUnsigned); +} + +function parseMs(input, array) { + array[MILLISECOND] = toInt(('0.' + input) * 1000); +} + +for (token = 'S'; token.length <= 9; token += 'S') { + addParseToken(token, parseMs); +} +// MOMENTS + +var getSetMillisecond = makeGetSet('Milliseconds', false); + +// FORMATTING + +addFormatToken('z', 0, 0, 'zoneAbbr'); +addFormatToken('zz', 0, 0, 'zoneName'); + +// MOMENTS + +function getZoneAbbr () { + return this._isUTC ? 'UTC' : ''; +} + +function getZoneName () { + return this._isUTC ? 'Coordinated Universal Time' : ''; +} + +var proto = Moment.prototype; + +proto.add = add; +proto.calendar = calendar$1; +proto.clone = clone; +proto.diff = diff; +proto.endOf = endOf; +proto.format = format; +proto.from = from; +proto.fromNow = fromNow; +proto.to = to; +proto.toNow = toNow; +proto.get = stringGet; +proto.invalidAt = invalidAt; +proto.isAfter = isAfter; +proto.isBefore = isBefore; +proto.isBetween = isBetween; +proto.isSame = isSame; +proto.isSameOrAfter = isSameOrAfter; +proto.isSameOrBefore = isSameOrBefore; +proto.isValid = isValid$2; +proto.lang = lang; +proto.locale = locale; +proto.localeData = localeData; +proto.max = prototypeMax; +proto.min = prototypeMin; +proto.parsingFlags = parsingFlags; +proto.set = stringSet; +proto.startOf = startOf; +proto.subtract = subtract; +proto.toArray = toArray; +proto.toObject = toObject; +proto.toDate = toDate; +proto.toISOString = toISOString; +proto.inspect = inspect; +proto.toJSON = toJSON; +proto.toString = toString; +proto.unix = unix; +proto.valueOf = valueOf; +proto.creationData = creationData; + +// Year +proto.year = getSetYear; +proto.isLeapYear = getIsLeapYear; + +// Week Year +proto.weekYear = getSetWeekYear; +proto.isoWeekYear = getSetISOWeekYear; + +// Quarter +proto.quarter = proto.quarters = getSetQuarter; + +// Month +proto.month = getSetMonth; +proto.daysInMonth = getDaysInMonth; + +// Week +proto.week = proto.weeks = getSetWeek; +proto.isoWeek = proto.isoWeeks = getSetISOWeek; +proto.weeksInYear = getWeeksInYear; +proto.isoWeeksInYear = getISOWeeksInYear; + +// Day +proto.date = getSetDayOfMonth; +proto.day = proto.days = getSetDayOfWeek; +proto.weekday = getSetLocaleDayOfWeek; +proto.isoWeekday = getSetISODayOfWeek; +proto.dayOfYear = getSetDayOfYear; + +// Hour +proto.hour = proto.hours = getSetHour; + +// Minute +proto.minute = proto.minutes = getSetMinute; + +// Second +proto.second = proto.seconds = getSetSecond; + +// Millisecond +proto.millisecond = proto.milliseconds = getSetMillisecond; + +// Offset +proto.utcOffset = getSetOffset; +proto.utc = setOffsetToUTC; +proto.local = setOffsetToLocal; +proto.parseZone = setOffsetToParsedOffset; +proto.hasAlignedHourOffset = hasAlignedHourOffset; +proto.isDST = isDaylightSavingTime; +proto.isLocal = isLocal; +proto.isUtcOffset = isUtcOffset; +proto.isUtc = isUtc; +proto.isUTC = isUtc; + +// Timezone +proto.zoneAbbr = getZoneAbbr; +proto.zoneName = getZoneName; + +// Deprecations +proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth); +proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth); +proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear); +proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone); +proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted); + +function createUnix (input) { + return createLocal(input * 1000); +} + +function createInZone () { + return createLocal.apply(null, arguments).parseZone(); +} + +function preParsePostFormat (string) { + return string; +} + +var proto$1 = Locale.prototype; + +proto$1.calendar = calendar; +proto$1.longDateFormat = longDateFormat; +proto$1.invalidDate = invalidDate; +proto$1.ordinal = ordinal; +proto$1.preparse = preParsePostFormat; +proto$1.postformat = preParsePostFormat; +proto$1.relativeTime = relativeTime; +proto$1.pastFuture = pastFuture; +proto$1.set = set; + +// Month +proto$1.months = localeMonths; +proto$1.monthsShort = localeMonthsShort; +proto$1.monthsParse = localeMonthsParse; +proto$1.monthsRegex = monthsRegex; +proto$1.monthsShortRegex = monthsShortRegex; + +// Week +proto$1.week = localeWeek; +proto$1.firstDayOfYear = localeFirstDayOfYear; +proto$1.firstDayOfWeek = localeFirstDayOfWeek; + +// Day of Week +proto$1.weekdays = localeWeekdays; +proto$1.weekdaysMin = localeWeekdaysMin; +proto$1.weekdaysShort = localeWeekdaysShort; +proto$1.weekdaysParse = localeWeekdaysParse; + +proto$1.weekdaysRegex = weekdaysRegex; +proto$1.weekdaysShortRegex = weekdaysShortRegex; +proto$1.weekdaysMinRegex = weekdaysMinRegex; + +// Hours +proto$1.isPM = localeIsPM; +proto$1.meridiem = localeMeridiem; + +function get$1 (format, index, field, setter) { + var locale = getLocale(); + var utc = createUTC().set(setter, index); + return locale[field](utc, format); +} + +function listMonthsImpl (format, index, field) { + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + + if (index != null) { + return get$1(format, index, field, 'month'); + } + + var i; + var out = []; + for (i = 0; i < 12; i++) { + out[i] = get$1(format, i, field, 'month'); + } + return out; +} + +// () +// (5) +// (fmt, 5) +// (fmt) +// (true) +// (true, 5) +// (true, fmt, 5) +// (true, fmt) +function listWeekdaysImpl (localeSorted, format, index, field) { + if (typeof localeSorted === 'boolean') { + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + } else { + format = localeSorted; + index = format; + localeSorted = false; + + if (isNumber(format)) { + index = format; + format = undefined; + } + + format = format || ''; + } + + var locale = getLocale(), + shift = localeSorted ? locale._week.dow : 0; + + if (index != null) { + return get$1(format, (index + shift) % 7, field, 'day'); + } + + var i; + var out = []; + for (i = 0; i < 7; i++) { + out[i] = get$1(format, (i + shift) % 7, field, 'day'); + } + return out; +} + +function listMonths (format, index) { + return listMonthsImpl(format, index, 'months'); +} + +function listMonthsShort (format, index) { + return listMonthsImpl(format, index, 'monthsShort'); +} + +function listWeekdays (localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdays'); +} + +function listWeekdaysShort (localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort'); +} + +function listWeekdaysMin (localeSorted, format, index) { + return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin'); +} + +getSetGlobalLocale('en', { + dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/, + ordinal : function (number) { + var b = number % 10, + output = (toInt(number % 100 / 10) === 1) ? 'th' : + (b === 1) ? 'st' : + (b === 2) ? 'nd' : + (b === 3) ? 'rd' : 'th'; + return number + output; + } +}); + +// Side effect imports +hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale); +hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale); + +var mathAbs = Math.abs; + +function abs () { + var data = this._data; + + this._milliseconds = mathAbs(this._milliseconds); + this._days = mathAbs(this._days); + this._months = mathAbs(this._months); + + data.milliseconds = mathAbs(data.milliseconds); + data.seconds = mathAbs(data.seconds); + data.minutes = mathAbs(data.minutes); + data.hours = mathAbs(data.hours); + data.months = mathAbs(data.months); + data.years = mathAbs(data.years); + + return this; +} + +function addSubtract$1 (duration, input, value, direction) { + var other = createDuration(input, value); + + duration._milliseconds += direction * other._milliseconds; + duration._days += direction * other._days; + duration._months += direction * other._months; + + return duration._bubble(); +} + +// supports only 2.0-style add(1, 's') or add(duration) +function add$1 (input, value) { + return addSubtract$1(this, input, value, 1); +} + +// supports only 2.0-style subtract(1, 's') or subtract(duration) +function subtract$1 (input, value) { + return addSubtract$1(this, input, value, -1); +} + +function absCeil (number) { + if (number < 0) { + return Math.floor(number); + } else { + return Math.ceil(number); + } +} + +function bubble () { + var milliseconds = this._milliseconds; + var days = this._days; + var months = this._months; + var data = this._data; + var seconds, minutes, hours, years, monthsFromDays; + + // if we have a mix of positive and negative values, bubble down first + // check: https://github.com/moment/moment/issues/2166 + if (!((milliseconds >= 0 && days >= 0 && months >= 0) || + (milliseconds <= 0 && days <= 0 && months <= 0))) { + milliseconds += absCeil(monthsToDays(months) + days) * 864e5; + days = 0; + months = 0; + } + + // The following code bubbles up values, see the tests for + // examples of what that means. + data.milliseconds = milliseconds % 1000; + + seconds = absFloor(milliseconds / 1000); + data.seconds = seconds % 60; + + minutes = absFloor(seconds / 60); + data.minutes = minutes % 60; + + hours = absFloor(minutes / 60); + data.hours = hours % 24; + + days += absFloor(hours / 24); + + // convert days to months + monthsFromDays = absFloor(daysToMonths(days)); + months += monthsFromDays; + days -= absCeil(monthsToDays(monthsFromDays)); + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + data.days = days; + data.months = months; + data.years = years; + + return this; +} + +function daysToMonths (days) { + // 400 years have 146097 days (taking into account leap year rules) + // 400 years have 12 months === 4800 + return days * 4800 / 146097; +} + +function monthsToDays (months) { + // the reverse of daysToMonths + return months * 146097 / 4800; +} + +function as (units) { + if (!this.isValid()) { + return NaN; + } + var days; + var months; + var milliseconds = this._milliseconds; + + units = normalizeUnits(units); + + if (units === 'month' || units === 'year') { + days = this._days + milliseconds / 864e5; + months = this._months + daysToMonths(days); + return units === 'month' ? months : months / 12; + } else { + // handle milliseconds separately because of floating point math errors (issue #1867) + days = this._days + Math.round(monthsToDays(this._months)); + switch (units) { + case 'week' : return days / 7 + milliseconds / 6048e5; + case 'day' : return days + milliseconds / 864e5; + case 'hour' : return days * 24 + milliseconds / 36e5; + case 'minute' : return days * 1440 + milliseconds / 6e4; + case 'second' : return days * 86400 + milliseconds / 1000; + // Math.floor prevents floating point math errors here + case 'millisecond': return Math.floor(days * 864e5) + milliseconds; + default: throw new Error('Unknown unit ' + units); + } + } +} + +// TODO: Use this.as('ms')? +function valueOf$1 () { + if (!this.isValid()) { + return NaN; + } + return ( + this._milliseconds + + this._days * 864e5 + + (this._months % 12) * 2592e6 + + toInt(this._months / 12) * 31536e6 + ); +} + +function makeAs (alias) { + return function () { + return this.as(alias); + }; +} + +var asMilliseconds = makeAs('ms'); +var asSeconds = makeAs('s'); +var asMinutes = makeAs('m'); +var asHours = makeAs('h'); +var asDays = makeAs('d'); +var asWeeks = makeAs('w'); +var asMonths = makeAs('M'); +var asYears = makeAs('y'); + +function get$2 (units) { + units = normalizeUnits(units); + return this.isValid() ? this[units + 's']() : NaN; +} + +function makeGetter(name) { + return function () { + return this.isValid() ? this._data[name] : NaN; + }; +} + +var milliseconds = makeGetter('milliseconds'); +var seconds = makeGetter('seconds'); +var minutes = makeGetter('minutes'); +var hours = makeGetter('hours'); +var days = makeGetter('days'); +var months = makeGetter('months'); +var years = makeGetter('years'); + +function weeks () { + return absFloor(this.days() / 7); +} + +var round = Math.round; +var thresholds = { + ss: 44, // a few seconds to seconds + s : 45, // seconds to minute + m : 45, // minutes to hour + h : 22, // hours to day + d : 26, // days to month + M : 11 // months to year +}; + +// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize +function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); +} + +function relativeTime$1 (posNegDuration, withoutSuffix, locale) { + var duration = createDuration(posNegDuration).abs(); + var seconds = round(duration.as('s')); + var minutes = round(duration.as('m')); + var hours = round(duration.as('h')); + var days = round(duration.as('d')); + var months = round(duration.as('M')); + var years = round(duration.as('y')); + + var a = seconds <= thresholds.ss && ['s', seconds] || + seconds < thresholds.s && ['ss', seconds] || + minutes <= 1 && ['m'] || + minutes < thresholds.m && ['mm', minutes] || + hours <= 1 && ['h'] || + hours < thresholds.h && ['hh', hours] || + days <= 1 && ['d'] || + days < thresholds.d && ['dd', days] || + months <= 1 && ['M'] || + months < thresholds.M && ['MM', months] || + years <= 1 && ['y'] || ['yy', years]; + + a[2] = withoutSuffix; + a[3] = +posNegDuration > 0; + a[4] = locale; + return substituteTimeAgo.apply(null, a); +} + +// This function allows you to set the rounding function for relative time strings +function getSetRelativeTimeRounding (roundingFunction) { + if (roundingFunction === undefined) { + return round; + } + if (typeof(roundingFunction) === 'function') { + round = roundingFunction; + return true; + } + return false; +} + +// This function allows you to set a threshold for relative time strings +function getSetRelativeTimeThreshold (threshold, limit) { + if (thresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return thresholds[threshold]; + } + thresholds[threshold] = limit; + if (threshold === 's') { + thresholds.ss = limit - 1; + } + return true; +} + +function humanize (withSuffix) { + if (!this.isValid()) { + return this.localeData().invalidDate(); + } + + var locale = this.localeData(); + var output = relativeTime$1(this, !withSuffix, locale); + + if (withSuffix) { + output = locale.pastFuture(+this, output); + } + + return locale.postformat(output); +} + +var abs$1 = Math.abs; + +function toISOString$1() { + // for ISO strings we do not use the normal bubbling rules: + // * milliseconds bubble up until they become hours + // * days do not bubble at all + // * months bubble up until they become years + // This is because there is no context-free conversion between hours and days + // (think of clock changes) + // and also not between days and months (28-31 days per month) + if (!this.isValid()) { + return this.localeData().invalidDate(); + } + + var seconds = abs$1(this._milliseconds) / 1000; + var days = abs$1(this._days); + var months = abs$1(this._months); + var minutes, hours, years; + + // 3600 seconds -> 60 minutes -> 1 hour + minutes = absFloor(seconds / 60); + hours = absFloor(minutes / 60); + seconds %= 60; + minutes %= 60; + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js + var Y = years; + var M = months; + var D = days; + var h = hours; + var m = minutes; + var s = seconds; + var total = this.asSeconds(); + + if (!total) { + // this is the same as C#'s (Noda) and python (isodate)... + // but not other JS (goog.date) + return 'P0D'; + } + + return (total < 0 ? '-' : '') + + 'P' + + (Y ? Y + 'Y' : '') + + (M ? M + 'M' : '') + + (D ? D + 'D' : '') + + ((h || m || s) ? 'T' : '') + + (h ? h + 'H' : '') + + (m ? m + 'M' : '') + + (s ? s + 'S' : ''); +} + +var proto$2 = Duration.prototype; + +proto$2.isValid = isValid$1; +proto$2.abs = abs; +proto$2.add = add$1; +proto$2.subtract = subtract$1; +proto$2.as = as; +proto$2.asMilliseconds = asMilliseconds; +proto$2.asSeconds = asSeconds; +proto$2.asMinutes = asMinutes; +proto$2.asHours = asHours; +proto$2.asDays = asDays; +proto$2.asWeeks = asWeeks; +proto$2.asMonths = asMonths; +proto$2.asYears = asYears; +proto$2.valueOf = valueOf$1; +proto$2._bubble = bubble; +proto$2.get = get$2; +proto$2.milliseconds = milliseconds; +proto$2.seconds = seconds; +proto$2.minutes = minutes; +proto$2.hours = hours; +proto$2.days = days; +proto$2.weeks = weeks; +proto$2.months = months; +proto$2.years = years; +proto$2.humanize = humanize; +proto$2.toISOString = toISOString$1; +proto$2.toString = toISOString$1; +proto$2.toJSON = toISOString$1; +proto$2.locale = locale; +proto$2.localeData = localeData; + +// Deprecations +proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1); +proto$2.lang = lang; + +// Side effect imports + +// FORMATTING + +addFormatToken('X', 0, 0, 'unix'); +addFormatToken('x', 0, 0, 'valueOf'); + +// PARSING + +addRegexToken('x', matchSigned); +addRegexToken('X', matchTimestamp); +addParseToken('X', function (input, array, config) { + config._d = new Date(parseFloat(input, 10) * 1000); +}); +addParseToken('x', function (input, array, config) { + config._d = new Date(toInt(input)); +}); + +// Side effect imports + + +hooks.version = '2.18.1'; + +setHookCallback(createLocal); + +hooks.fn = proto; +hooks.min = min; +hooks.max = max; +hooks.now = now; +hooks.utc = createUTC; +hooks.unix = createUnix; +hooks.months = listMonths; +hooks.isDate = isDate; +hooks.locale = getSetGlobalLocale; +hooks.invalid = createInvalid; +hooks.duration = createDuration; +hooks.isMoment = isMoment; +hooks.weekdays = listWeekdays; +hooks.parseZone = createInZone; +hooks.localeData = getLocale; +hooks.isDuration = isDuration; +hooks.monthsShort = listMonthsShort; +hooks.weekdaysMin = listWeekdaysMin; +hooks.defineLocale = defineLocale; +hooks.updateLocale = updateLocale; +hooks.locales = listLocales; +hooks.weekdaysShort = listWeekdaysShort; +hooks.normalizeUnits = normalizeUnits; +hooks.relativeTimeRounding = getSetRelativeTimeRounding; +hooks.relativeTimeThreshold = getSetRelativeTimeThreshold; +hooks.calendarFormat = getCalendarFormat; +hooks.prototype = proto; + +return hooks; + +}))); + +},{}],7:[function(require,module,exports){ +/** + * @namespace Chart + */ +var Chart = require(29)(); + +Chart.helpers = require(45); + +// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests! +require(27)(Chart); + +Chart.defaults = require(25); +Chart.Element = require(26); +Chart.elements = require(40); +Chart.Interaction = require(28); +Chart.platform = require(48); + +require(31)(Chart); +require(22)(Chart); +require(23)(Chart); +require(24)(Chart); +require(30)(Chart); +require(33)(Chart); +require(32)(Chart); +require(35)(Chart); + +require(54)(Chart); +require(52)(Chart); +require(53)(Chart); +require(55)(Chart); +require(56)(Chart); +require(57)(Chart); + +// Controllers must be loaded after elements +// See Chart.core.datasetController.dataElementType +require(15)(Chart); +require(16)(Chart); +require(17)(Chart); +require(18)(Chart); +require(19)(Chart); +require(20)(Chart); +require(21)(Chart); + +require(8)(Chart); +require(9)(Chart); +require(10)(Chart); +require(11)(Chart); +require(12)(Chart); +require(13)(Chart); +require(14)(Chart); + +// Loading built-it plugins +var plugins = []; + +plugins.push( + require(49)(Chart), + require(50)(Chart), + require(51)(Chart) +); + +Chart.plugins.register(plugins); + +Chart.platform.initialize(); + +module.exports = Chart; +if (typeof window !== 'undefined') { + window.Chart = Chart; +} + +// DEPRECATIONS + +/** + * Provided for backward compatibility, use Chart.helpers.canvas instead. + * @namespace Chart.canvasHelpers + * @deprecated since version 2.6.0 + * @todo remove at version 3 + * @private + */ +Chart.canvasHelpers = Chart.helpers.canvas; + +},{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"35":35,"40":40,"45":45,"48":48,"49":49,"50":50,"51":51,"52":52,"53":53,"54":54,"55":55,"56":56,"57":57,"8":8,"9":9}],8:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Bar = function(context, config) { + config.type = 'bar'; + + return new Chart(context, config); + }; + +}; + +},{}],9:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Bubble = function(context, config) { + config.type = 'bubble'; + return new Chart(context, config); + }; + +}; + +},{}],10:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Doughnut = function(context, config) { + config.type = 'doughnut'; + + return new Chart(context, config); + }; + +}; + +},{}],11:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Line = function(context, config) { + config.type = 'line'; + + return new Chart(context, config); + }; + +}; + +},{}],12:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.PolarArea = function(context, config) { + config.type = 'polarArea'; + + return new Chart(context, config); + }; + +}; + +},{}],13:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + Chart.Radar = function(context, config) { + config.type = 'radar'; + + return new Chart(context, config); + }; + +}; + +},{}],14:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + Chart.Scatter = function(context, config) { + config.type = 'scatter'; + return new Chart(context, config); + }; +}; + +},{}],15:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var elements = require(40); +var helpers = require(45); + +defaults._set('bar', { + hover: { + mode: 'label' + }, + + scales: { + xAxes: [{ + type: 'category', + + // Specific to Bar Controller + categoryPercentage: 0.8, + barPercentage: 0.9, + + // offset settings + offset: true, + + // grid line settings + gridLines: { + offsetGridLines: true + } + }], + + yAxes: [{ + type: 'linear' + }] + } +}); + +defaults._set('horizontalBar', { + hover: { + mode: 'index', + axis: 'y' + }, + + scales: { + xAxes: [{ + type: 'linear', + position: 'bottom' + }], + + yAxes: [{ + position: 'left', + type: 'category', + + // Specific to Horizontal Bar Controller + categoryPercentage: 0.8, + barPercentage: 0.9, + + // offset settings + offset: true, + + // grid line settings + gridLines: { + offsetGridLines: true + } + }] + }, + + elements: { + rectangle: { + borderSkipped: 'left' + } + }, + + tooltips: { + callbacks: { + title: function(item, data) { + // Pick first xLabel for now + var title = ''; + + if (item.length > 0) { + if (item[0].yLabel) { + title = item[0].yLabel; + } else if (data.labels.length > 0 && item[0].index < data.labels.length) { + title = data.labels[item[0].index]; + } + } + + return title; + }, + + label: function(item, data) { + var datasetLabel = data.datasets[item.datasetIndex].label || ''; + return datasetLabel + ': ' + item.xLabel; + } + }, + mode: 'index', + axis: 'y' + } +}); + +module.exports = function(Chart) { + + Chart.controllers.bar = Chart.DatasetController.extend({ + + dataElementType: elements.Rectangle, + + initialize: function() { + var me = this; + var meta; + + Chart.DatasetController.prototype.initialize.apply(me, arguments); + + meta = me.getMeta(); + meta.stack = me.getDataset().stack; + meta.bar = true; + }, + + update: function(reset) { + var me = this; + var rects = me.getMeta().data; + var i, ilen; + + me._ruler = me.getRuler(); + + for (i = 0, ilen = rects.length; i < ilen; ++i) { + me.updateElement(rects[i], i, reset); + } + }, + + updateElement: function(rectangle, index, reset) { + var me = this; + var chart = me.chart; + var meta = me.getMeta(); + var dataset = me.getDataset(); + var custom = rectangle.custom || {}; + var rectangleOptions = chart.options.elements.rectangle; + + rectangle._xScale = me.getScaleForId(meta.xAxisID); + rectangle._yScale = me.getScaleForId(meta.yAxisID); + rectangle._datasetIndex = me.index; + rectangle._index = index; + + rectangle._model = { + datasetLabel: dataset.label, + label: chart.data.labels[index], + borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped, + backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor), + borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor), + borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth) + }; + + me.updateElementGeometry(rectangle, index, reset); + + rectangle.pivot(); + }, + + /** + * @private + */ + updateElementGeometry: function(rectangle, index, reset) { + var me = this; + var model = rectangle._model; + var vscale = me.getValueScale(); + var base = vscale.getBasePixel(); + var horizontal = vscale.isHorizontal(); + var ruler = me._ruler || me.getRuler(); + var vpixels = me.calculateBarValuePixels(me.index, index); + var ipixels = me.calculateBarIndexPixels(me.index, index, ruler); + + model.horizontal = horizontal; + model.base = reset ? base : vpixels.base; + model.x = horizontal ? reset ? base : vpixels.head : ipixels.center; + model.y = horizontal ? ipixels.center : reset ? base : vpixels.head; + model.height = horizontal ? ipixels.size : undefined; + model.width = horizontal ? undefined : ipixels.size; + }, + + /** + * @private + */ + getValueScaleId: function() { + return this.getMeta().yAxisID; + }, + + /** + * @private + */ + getIndexScaleId: function() { + return this.getMeta().xAxisID; + }, + + /** + * @private + */ + getValueScale: function() { + return this.getScaleForId(this.getValueScaleId()); + }, + + /** + * @private + */ + getIndexScale: function() { + return this.getScaleForId(this.getIndexScaleId()); + }, + + /** + * Returns the effective number of stacks based on groups and bar visibility. + * @private + */ + getStackCount: function(last) { + var me = this; + var chart = me.chart; + var scale = me.getIndexScale(); + var stacked = scale.options.stacked; + var ilen = last === undefined ? chart.data.datasets.length : last + 1; + var stacks = []; + var i, meta; + + for (i = 0; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + if (meta.bar && chart.isDatasetVisible(i) && + (stacked === false || + (stacked === true && stacks.indexOf(meta.stack) === -1) || + (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) { + stacks.push(meta.stack); + } + } + + return stacks.length; + }, + + /** + * Returns the stack index for the given dataset based on groups and bar visibility. + * @private + */ + getStackIndex: function(datasetIndex) { + return this.getStackCount(datasetIndex) - 1; + }, + + /** + * @private + */ + getRuler: function() { + var me = this; + var scale = me.getIndexScale(); + var stackCount = me.getStackCount(); + var datasetIndex = me.index; + var pixels = []; + var isHorizontal = scale.isHorizontal(); + var start = isHorizontal ? scale.left : scale.top; + var end = start + (isHorizontal ? scale.width : scale.height); + var i, ilen; + + for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) { + pixels.push(scale.getPixelForValue(null, i, datasetIndex)); + } + + return { + pixels: pixels, + start: start, + end: end, + stackCount: stackCount, + scale: scale + }; + }, + + /** + * Note: pixel values are not clamped to the scale area. + * @private + */ + calculateBarValuePixels: function(datasetIndex, index) { + var me = this; + var chart = me.chart; + var meta = me.getMeta(); + var scale = me.getValueScale(); + var datasets = chart.data.datasets; + var value = scale.getRightValue(datasets[datasetIndex].data[index]); + var stacked = scale.options.stacked; + var stack = meta.stack; + var start = 0; + var i, imeta, ivalue, base, head, size; + + if (stacked || (stacked === undefined && stack !== undefined)) { + for (i = 0; i < datasetIndex; ++i) { + imeta = chart.getDatasetMeta(i); + + if (imeta.bar && + imeta.stack === stack && + imeta.controller.getValueScaleId() === scale.id && + chart.isDatasetVisible(i)) { + + ivalue = scale.getRightValue(datasets[i].data[index]); + if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) { + start += ivalue; + } + } + } + } + + base = scale.getPixelForValue(start); + head = scale.getPixelForValue(start + value); + size = (head - base) / 2; + + return { + size: size, + base: base, + head: head, + center: head + size / 2 + }; + }, + + /** + * @private + */ + calculateBarIndexPixels: function(datasetIndex, index, ruler) { + var me = this; + var options = ruler.scale.options; + var stackIndex = me.getStackIndex(datasetIndex); + var pixels = ruler.pixels; + var base = pixels[index]; + var length = pixels.length; + var start = ruler.start; + var end = ruler.end; + var leftSampleSize, rightSampleSize, leftCategorySize, rightCategorySize, fullBarSize, size; + + if (length === 1) { + leftSampleSize = base > start ? base - start : end - base; + rightSampleSize = base < end ? end - base : base - start; + } else { + if (index > 0) { + leftSampleSize = (base - pixels[index - 1]) / 2; + if (index === length - 1) { + rightSampleSize = leftSampleSize; + } + } + if (index < length - 1) { + rightSampleSize = (pixels[index + 1] - base) / 2; + if (index === 0) { + leftSampleSize = rightSampleSize; + } + } + } + + leftCategorySize = leftSampleSize * options.categoryPercentage; + rightCategorySize = rightSampleSize * options.categoryPercentage; + fullBarSize = (leftCategorySize + rightCategorySize) / ruler.stackCount; + size = fullBarSize * options.barPercentage; + + size = Math.min( + helpers.valueOrDefault(options.barThickness, size), + helpers.valueOrDefault(options.maxBarThickness, Infinity)); + + base -= leftCategorySize; + base += fullBarSize * stackIndex; + base += (fullBarSize - size) / 2; + + return { + size: size, + base: base, + head: base + size, + center: base + size / 2 + }; + }, + + draw: function() { + var me = this; + var chart = me.chart; + var scale = me.getValueScale(); + var rects = me.getMeta().data; + var dataset = me.getDataset(); + var ilen = rects.length; + var i = 0; + + helpers.canvas.clipArea(chart.ctx, chart.chartArea); + + for (; i < ilen; ++i) { + if (!isNaN(scale.getRightValue(dataset.data[i]))) { + rects[i].draw(); + } + } + + helpers.canvas.unclipArea(chart.ctx); + }, + + setHoverStyle: function(rectangle) { + var dataset = this.chart.data.datasets[rectangle._datasetIndex]; + var index = rectangle._index; + var custom = rectangle.custom || {}; + var model = rectangle._model; + + model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); + model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor)); + model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth); + }, + + removeHoverStyle: function(rectangle) { + var dataset = this.chart.data.datasets[rectangle._datasetIndex]; + var index = rectangle._index; + var custom = rectangle.custom || {}; + var model = rectangle._model; + var rectangleElementOptions = this.chart.options.elements.rectangle; + + model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor); + model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor); + model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth); + } + }); + + Chart.controllers.horizontalBar = Chart.controllers.bar.extend({ + /** + * @private + */ + getValueScaleId: function() { + return this.getMeta().xAxisID; + }, + + /** + * @private + */ + getIndexScaleId: function() { + return this.getMeta().yAxisID; + } + }); +}; + +},{"25":25,"40":40,"45":45}],16:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var elements = require(40); +var helpers = require(45); + +defaults._set('bubble', { + hover: { + mode: 'single' + }, + + scales: { + xAxes: [{ + type: 'linear', // bubble should probably use a linear scale by default + position: 'bottom', + id: 'x-axis-0' // need an ID so datasets can reference the scale + }], + yAxes: [{ + type: 'linear', + position: 'left', + id: 'y-axis-0' + }] + }, + + tooltips: { + callbacks: { + title: function() { + // Title doesn't make sense for scatter since we format the data as a point + return ''; + }, + label: function(item, data) { + var datasetLabel = data.datasets[item.datasetIndex].label || ''; + var dataPoint = data.datasets[item.datasetIndex].data[item.index]; + return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')'; + } + } + } +}); + + +module.exports = function(Chart) { + + Chart.controllers.bubble = Chart.DatasetController.extend({ + /** + * @protected + */ + dataElementType: elements.Point, + + /** + * @protected + */ + update: function(reset) { + var me = this; + var meta = me.getMeta(); + var points = meta.data; + + // Update Points + helpers.each(points, function(point, index) { + me.updateElement(point, index, reset); + }); + }, + + /** + * @protected + */ + updateElement: function(point, index, reset) { + var me = this; + var meta = me.getMeta(); + var custom = point.custom || {}; + var xScale = me.getScaleForId(meta.xAxisID); + var yScale = me.getScaleForId(meta.yAxisID); + var options = me._resolveElementOptions(point, index); + var data = me.getDataset().data[index]; + var dsIndex = me.index; + + var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex); + var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex); + + point._xScale = xScale; + point._yScale = yScale; + point._options = options; + point._datasetIndex = dsIndex; + point._index = index; + point._model = { + backgroundColor: options.backgroundColor, + borderColor: options.borderColor, + borderWidth: options.borderWidth, + hitRadius: options.hitRadius, + pointStyle: options.pointStyle, + radius: reset ? 0 : options.radius, + skip: custom.skip || isNaN(x) || isNaN(y), + x: x, + y: y, + }; + + point.pivot(); + }, + + /** + * @protected + */ + setHoverStyle: function(point) { + var model = point._model; + var options = point._options; + + model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroundColor, helpers.getHoverColor(options.backgroundColor)); + model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor)); + model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth); + model.radius = options.radius + options.hoverRadius; + }, + + /** + * @protected + */ + removeHoverStyle: function(point) { + var model = point._model; + var options = point._options; + + model.backgroundColor = options.backgroundColor; + model.borderColor = options.borderColor; + model.borderWidth = options.borderWidth; + model.radius = options.radius; + }, + + /** + * @private + */ + _resolveElementOptions: function(point, index) { + var me = this; + var chart = me.chart; + var datasets = chart.data.datasets; + var dataset = datasets[me.index]; + var custom = point.custom || {}; + var options = chart.options.elements.point; + var resolve = helpers.options.resolve; + var data = dataset.data[index]; + var values = {}; + var i, ilen, key; + + // Scriptable options + var context = { + chart: chart, + dataIndex: index, + dataset: dataset, + datasetIndex: me.index + }; + + var keys = [ + 'backgroundColor', + 'borderColor', + 'borderWidth', + 'hoverBackgroundColor', + 'hoverBorderColor', + 'hoverBorderWidth', + 'hoverRadius', + 'hitRadius', + 'pointStyle' + ]; + + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + values[key] = resolve([ + custom[key], + dataset[key], + options[key] + ], context, index); + } + + // Custom radius resolution + values.radius = resolve([ + custom.radius, + data ? data.r : undefined, + dataset.radius, + options.radius + ], context, index); + + return values; + } + }); +}; + +},{"25":25,"40":40,"45":45}],17:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var elements = require(40); +var helpers = require(45); + +defaults._set('doughnut', { + animation: { + // Boolean - Whether we animate the rotation of the Doughnut + animateRotate: true, + // Boolean - Whether we animate scaling the Doughnut from the centre + animateScale: false + }, + hover: { + mode: 'single' + }, + legendCallback: function(chart) { + var text = []; + text.push(''); + return text.join(''); + }, + legend: { + labels: { + generateLabels: function(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i]; + var custom = arc && arc.custom || {}; + var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; + var arcOpts = chart.options.elements.arc; + var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); + var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); + var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); + + return { + text: label, + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, + + // Extra data used for toggling the correct item + index: i + }; + }); + } + return []; + } + }, + + onClick: function(e, legendItem) { + var index = legendItem.index; + var chart = this.chart; + var i, ilen, meta; + + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + // toggle visibility of index if exists + if (meta.data[index]) { + meta.data[index].hidden = !meta.data[index].hidden; + } + } + + chart.update(); + } + }, + + // The percentage of the chart that we cut out of the middle. + cutoutPercentage: 50, + + // The rotation of the chart, where the first data arc begins. + rotation: Math.PI * -0.5, + + // The total circumference of the chart. + circumference: Math.PI * 2.0, + + // Need to override these to give a nice default + tooltips: { + callbacks: { + title: function() { + return ''; + }, + label: function(tooltipItem, data) { + var dataLabel = data.labels[tooltipItem.index]; + var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; + + if (helpers.isArray(dataLabel)) { + // show value on first line of multiline label + // need to clone because we are changing the value + dataLabel = dataLabel.slice(); + dataLabel[0] += value; + } else { + dataLabel += value; + } + + return dataLabel; + } + } + } +}); + +defaults._set('pie', helpers.clone(defaults.doughnut)); +defaults._set('pie', { + cutoutPercentage: 0 +}); + +module.exports = function(Chart) { + + Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({ + + dataElementType: elements.Arc, + + linkScales: helpers.noop, + + // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly + getRingIndex: function(datasetIndex) { + var ringIndex = 0; + + for (var j = 0; j < datasetIndex; ++j) { + if (this.chart.isDatasetVisible(j)) { + ++ringIndex; + } + } + + return ringIndex; + }, + + update: function(reset) { + var me = this; + var chart = me.chart; + var chartArea = chart.chartArea; + var opts = chart.options; + var arcOpts = opts.elements.arc; + var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth; + var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth; + var minSize = Math.min(availableWidth, availableHeight); + var offset = {x: 0, y: 0}; + var meta = me.getMeta(); + var cutoutPercentage = opts.cutoutPercentage; + var circumference = opts.circumference; + + // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc + if (circumference < Math.PI * 2.0) { + var startAngle = opts.rotation % (Math.PI * 2.0); + startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0); + var endAngle = startAngle + circumference; + var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)}; + var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)}; + var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle); + var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle); + var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle); + var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle); + var cutout = cutoutPercentage / 100.0; + var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))}; + var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))}; + var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5}; + minSize = Math.min(availableWidth / size.width, availableHeight / size.height); + offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5}; + } + + chart.borderWidth = me.getMaxBorderWidth(meta.data); + chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0); + chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); + chart.offsetX = offset.x * chart.outerRadius; + chart.offsetY = offset.y * chart.outerRadius; + + meta.total = me.calculateTotal(); + + me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index)); + me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0); + + helpers.each(meta.data, function(arc, index) { + me.updateElement(arc, index, reset); + }); + }, + + updateElement: function(arc, index, reset) { + var me = this; + var chart = me.chart; + var chartArea = chart.chartArea; + var opts = chart.options; + var animationOpts = opts.animation; + var centerX = (chartArea.left + chartArea.right) / 2; + var centerY = (chartArea.top + chartArea.bottom) / 2; + var startAngle = opts.rotation; // non reset case handled later + var endAngle = opts.rotation; // non reset case handled later + var dataset = me.getDataset(); + var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)); + var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius; + var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius; + var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; + + helpers.extend(arc, { + // Utility + _datasetIndex: me.index, + _index: index, + + // Desired view properties + _model: { + x: centerX + chart.offsetX, + y: centerY + chart.offsetY, + startAngle: startAngle, + endAngle: endAngle, + circumference: circumference, + outerRadius: outerRadius, + innerRadius: innerRadius, + label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index]) + } + }); + + var model = arc._model; + // Resets the visual styles + this.removeHoverStyle(arc); + + // Set correct angles if not resetting + if (!reset || !animationOpts.animateRotate) { + if (index === 0) { + model.startAngle = opts.rotation; + } else { + model.startAngle = me.getMeta().data[index - 1]._model.endAngle; + } + + model.endAngle = model.startAngle + model.circumference; + } + + arc.pivot(); + }, + + removeHoverStyle: function(arc) { + Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); + }, + + calculateTotal: function() { + var dataset = this.getDataset(); + var meta = this.getMeta(); + var total = 0; + var value; + + helpers.each(meta.data, function(element, index) { + value = dataset.data[index]; + if (!isNaN(value) && !element.hidden) { + total += Math.abs(value); + } + }); + + /* if (total === 0) { + total = NaN; + }*/ + + return total; + }, + + calculateCircumference: function(value) { + var total = this.getMeta().total; + if (total > 0 && !isNaN(value)) { + return (Math.PI * 2.0) * (value / total); + } + return 0; + }, + + // gets the max border or hover width to properly scale pie charts + getMaxBorderWidth: function(arcs) { + var max = 0; + var index = this.index; + var length = arcs.length; + var borderWidth; + var hoverWidth; + + for (var i = 0; i < length; i++) { + borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0; + hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0; + + max = borderWidth > max ? borderWidth : max; + max = hoverWidth > max ? hoverWidth : max; + } + return max; + } + }); +}; + +},{"25":25,"40":40,"45":45}],18:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var elements = require(40); +var helpers = require(45); + +defaults._set('line', { + showLines: true, + spanGaps: false, + + hover: { + mode: 'label' + }, + + scales: { + xAxes: [{ + type: 'category', + id: 'x-axis-0' + }], + yAxes: [{ + type: 'linear', + id: 'y-axis-0' + }] + } +}); + +module.exports = function(Chart) { + + function lineEnabled(dataset, options) { + return helpers.valueOrDefault(dataset.showLine, options.showLines); + } + + Chart.controllers.line = Chart.DatasetController.extend({ + + datasetElementType: elements.Line, + + dataElementType: elements.Point, + + update: function(reset) { + var me = this; + var meta = me.getMeta(); + var line = meta.dataset; + var points = meta.data || []; + var options = me.chart.options; + var lineElementOptions = options.elements.line; + var scale = me.getScaleForId(meta.yAxisID); + var i, ilen, custom; + var dataset = me.getDataset(); + var showLine = lineEnabled(dataset, options); + + // Update Line + if (showLine) { + custom = line.custom || {}; + + // Compatibility: If the properties are defined with only the old name, use those values + if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) { + dataset.lineTension = dataset.tension; + } + + // Utility + line._scale = scale; + line._datasetIndex = me.index; + // Data + line._children = points; + // Model + line._model = { + // Appearance + // The default behavior of lines is to break at null values, according + // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158 + // This option gives lines the ability to span gaps + spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps, + tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor), + borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth), + borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor), + borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle), + borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash), + borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset), + borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle), + fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill), + steppedLine: custom.steppedLine ? custom.steppedLine : helpers.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped), + cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode), + }; + + line.pivot(); + } + + // Update Points + for (i = 0, ilen = points.length; i < ilen; ++i) { + me.updateElement(points[i], i, reset); + } + + if (showLine && line._model.tension !== 0) { + me.updateBezierControlPoints(); + } + + // Now pivot the point for animation + for (i = 0, ilen = points.length; i < ilen; ++i) { + points[i].pivot(); + } + }, + + getPointBackgroundColor: function(point, index) { + var backgroundColor = this.chart.options.elements.point.backgroundColor; + var dataset = this.getDataset(); + var custom = point.custom || {}; + + if (custom.backgroundColor) { + backgroundColor = custom.backgroundColor; + } else if (dataset.pointBackgroundColor) { + backgroundColor = helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor); + } else if (dataset.backgroundColor) { + backgroundColor = dataset.backgroundColor; + } + + return backgroundColor; + }, + + getPointBorderColor: function(point, index) { + var borderColor = this.chart.options.elements.point.borderColor; + var dataset = this.getDataset(); + var custom = point.custom || {}; + + if (custom.borderColor) { + borderColor = custom.borderColor; + } else if (dataset.pointBorderColor) { + borderColor = helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor); + } else if (dataset.borderColor) { + borderColor = dataset.borderColor; + } + + return borderColor; + }, + + getPointBorderWidth: function(point, index) { + var borderWidth = this.chart.options.elements.point.borderWidth; + var dataset = this.getDataset(); + var custom = point.custom || {}; + + if (!isNaN(custom.borderWidth)) { + borderWidth = custom.borderWidth; + } else if (!isNaN(dataset.pointBorderWidth) || helpers.isArray(dataset.pointBorderWidth)) { + borderWidth = helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth); + } else if (!isNaN(dataset.borderWidth)) { + borderWidth = dataset.borderWidth; + } + + return borderWidth; + }, + + updateElement: function(point, index, reset) { + var me = this; + var meta = me.getMeta(); + var custom = point.custom || {}; + var dataset = me.getDataset(); + var datasetIndex = me.index; + var value = dataset.data[index]; + var yScale = me.getScaleForId(meta.yAxisID); + var xScale = me.getScaleForId(meta.xAxisID); + var pointOptions = me.chart.options.elements.point; + var x, y; + + // Compatibility: If the properties are defined with only the old name, use those values + if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) { + dataset.pointRadius = dataset.radius; + } + if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) { + dataset.pointHitRadius = dataset.hitRadius; + } + + x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex); + y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex); + + // Utility + point._xScale = xScale; + point._yScale = yScale; + point._datasetIndex = datasetIndex; + point._index = index; + + // Desired view properties + point._model = { + x: x, + y: y, + skip: custom.skip || isNaN(x) || isNaN(y), + // Appearance + radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius), + pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle), + backgroundColor: me.getPointBackgroundColor(point, index), + borderColor: me.getPointBorderColor(point, index), + borderWidth: me.getPointBorderWidth(point, index), + tension: meta.dataset._model ? meta.dataset._model.tension : 0, + steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false, + // Tooltip + hitRadius: custom.hitRadius || helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius) + }; + }, + + calculatePointY: function(value, index, datasetIndex) { + var me = this; + var chart = me.chart; + var meta = me.getMeta(); + var yScale = me.getScaleForId(meta.yAxisID); + var sumPos = 0; + var sumNeg = 0; + var i, ds, dsMeta; + + if (yScale.options.stacked) { + for (i = 0; i < datasetIndex; i++) { + ds = chart.data.datasets[i]; + dsMeta = chart.getDatasetMeta(i); + if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) { + var stackedRightValue = Number(yScale.getRightValue(ds.data[index])); + if (stackedRightValue < 0) { + sumNeg += stackedRightValue || 0; + } else { + sumPos += stackedRightValue || 0; + } + } + } + + var rightValue = Number(yScale.getRightValue(value)); + if (rightValue < 0) { + return yScale.getPixelForValue(sumNeg + rightValue); + } + return yScale.getPixelForValue(sumPos + rightValue); + } + + return yScale.getPixelForValue(value); + }, + + updateBezierControlPoints: function() { + var me = this; + var meta = me.getMeta(); + var area = me.chart.chartArea; + var points = (meta.data || []); + var i, ilen, point, model, controlPoints; + + // Only consider points that are drawn in case the spanGaps option is used + if (meta.dataset._model.spanGaps) { + points = points.filter(function(pt) { + return !pt._model.skip; + }); + } + + function capControlPoint(pt, min, max) { + return Math.max(Math.min(pt, max), min); + } + + if (meta.dataset._model.cubicInterpolationMode === 'monotone') { + helpers.splineCurveMonotone(points); + } else { + for (i = 0, ilen = points.length; i < ilen; ++i) { + point = points[i]; + model = point._model; + controlPoints = helpers.splineCurve( + helpers.previousItem(points, i)._model, + model, + helpers.nextItem(points, i)._model, + meta.dataset._model.tension + ); + model.controlPointPreviousX = controlPoints.previous.x; + model.controlPointPreviousY = controlPoints.previous.y; + model.controlPointNextX = controlPoints.next.x; + model.controlPointNextY = controlPoints.next.y; + } + } + + if (me.chart.options.elements.line.capBezierPoints) { + for (i = 0, ilen = points.length; i < ilen; ++i) { + model = points[i]._model; + model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right); + model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom); + model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right); + model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom); + } + } + }, + + draw: function() { + var me = this; + var chart = me.chart; + var meta = me.getMeta(); + var points = meta.data || []; + var area = chart.chartArea; + var ilen = points.length; + var i = 0; + + helpers.canvas.clipArea(chart.ctx, area); + + if (lineEnabled(me.getDataset(), chart.options)) { + meta.dataset.draw(); + } + + helpers.canvas.unclipArea(chart.ctx); + + // Draw the points + for (; i < ilen; ++i) { + points[i].draw(area); + } + }, + + setHoverStyle: function(point) { + // Point + var dataset = this.chart.data.datasets[point._datasetIndex]; + var index = point._index; + var custom = point.custom || {}; + var model = point._model; + + model.radius = custom.hoverRadius || helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius); + model.backgroundColor = custom.hoverBackgroundColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); + model.borderColor = custom.hoverBorderColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor)); + model.borderWidth = custom.hoverBorderWidth || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth); + }, + + removeHoverStyle: function(point) { + var me = this; + var dataset = me.chart.data.datasets[point._datasetIndex]; + var index = point._index; + var custom = point.custom || {}; + var model = point._model; + + // Compatibility: If the properties are defined with only the old name, use those values + if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) { + dataset.pointRadius = dataset.radius; + } + + model.radius = custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius); + model.backgroundColor = me.getPointBackgroundColor(point, index); + model.borderColor = me.getPointBorderColor(point, index); + model.borderWidth = me.getPointBorderWidth(point, index); + } + }); +}; + +},{"25":25,"40":40,"45":45}],19:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var elements = require(40); +var helpers = require(45); + +defaults._set('polarArea', { + scale: { + type: 'radialLinear', + angleLines: { + display: false + }, + gridLines: { + circular: true + }, + pointLabels: { + display: false + }, + ticks: { + beginAtZero: true + } + }, + + // Boolean - Whether to animate the rotation of the chart + animation: { + animateRotate: true, + animateScale: true + }, + + startAngle: -0.5 * Math.PI, + legendCallback: function(chart) { + var text = []; + text.push(''); + return text.join(''); + }, + legend: { + labels: { + generateLabels: function(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i]; + var custom = arc.custom || {}; + var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; + var arcOpts = chart.options.elements.arc; + var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); + var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); + var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); + + return { + text: label, + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, + + // Extra data used for toggling the correct item + index: i + }; + }); + } + return []; + } + }, + + onClick: function(e, legendItem) { + var index = legendItem.index; + var chart = this.chart; + var i, ilen, meta; + + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + meta.data[index].hidden = !meta.data[index].hidden; + } + + chart.update(); + } + }, + + // Need to override these to give a nice default + tooltips: { + callbacks: { + title: function() { + return ''; + }, + label: function(item, data) { + return data.labels[item.index] + ': ' + item.yLabel; + } + } + } +}); + +module.exports = function(Chart) { + + Chart.controllers.polarArea = Chart.DatasetController.extend({ + + dataElementType: elements.Arc, + + linkScales: helpers.noop, + + update: function(reset) { + var me = this; + var chart = me.chart; + var chartArea = chart.chartArea; + var meta = me.getMeta(); + var opts = chart.options; + var arcOpts = opts.elements.arc; + var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0); + chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); + + me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index); + me.innerRadius = me.outerRadius - chart.radiusLength; + + meta.count = me.countVisibleElements(); + + helpers.each(meta.data, function(arc, index) { + me.updateElement(arc, index, reset); + }); + }, + + updateElement: function(arc, index, reset) { + var me = this; + var chart = me.chart; + var dataset = me.getDataset(); + var opts = chart.options; + var animationOpts = opts.animation; + var scale = chart.scale; + var labels = chart.data.labels; + + var circumference = me.calculateCircumference(dataset.data[index]); + var centerX = scale.xCenter; + var centerY = scale.yCenter; + + // If there is NaN data before us, we need to calculate the starting angle correctly. + // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data + var visibleCount = 0; + var meta = me.getMeta(); + for (var i = 0; i < index; ++i) { + if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) { + ++visibleCount; + } + } + + // var negHalfPI = -0.5 * Math.PI; + var datasetStartAngle = opts.startAngle; + var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); + var startAngle = datasetStartAngle + (circumference * visibleCount); + var endAngle = startAngle + (arc.hidden ? 0 : circumference); + + var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); + + helpers.extend(arc, { + // Utility + _datasetIndex: me.index, + _index: index, + _scale: scale, + + // Desired view properties + _model: { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius: reset ? resetRadius : distance, + startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle, + endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle, + label: helpers.valueAtIndexOrDefault(labels, index, labels[index]) + } + }); + + // Apply border and fill style + me.removeHoverStyle(arc); + + arc.pivot(); + }, + + removeHoverStyle: function(arc) { + Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); + }, + + countVisibleElements: function() { + var dataset = this.getDataset(); + var meta = this.getMeta(); + var count = 0; + + helpers.each(meta.data, function(element, index) { + if (!isNaN(dataset.data[index]) && !element.hidden) { + count++; + } + }); + + return count; + }, + + calculateCircumference: function(value) { + var count = this.getMeta().count; + if (count > 0 && !isNaN(value)) { + return (2 * Math.PI) / count; + } + return 0; + } + }); +}; + +},{"25":25,"40":40,"45":45}],20:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var elements = require(40); +var helpers = require(45); + +defaults._set('radar', { + scale: { + type: 'radialLinear' + }, + elements: { + line: { + tension: 0 // no bezier in radar + } + } +}); + +module.exports = function(Chart) { + + Chart.controllers.radar = Chart.DatasetController.extend({ + + datasetElementType: elements.Line, + + dataElementType: elements.Point, + + linkScales: helpers.noop, + + update: function(reset) { + var me = this; + var meta = me.getMeta(); + var line = meta.dataset; + var points = meta.data; + var custom = line.custom || {}; + var dataset = me.getDataset(); + var lineElementOptions = me.chart.options.elements.line; + var scale = me.chart.scale; + + // Compatibility: If the properties are defined with only the old name, use those values + if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) { + dataset.lineTension = dataset.tension; + } + + helpers.extend(meta.dataset, { + // Utility + _datasetIndex: me.index, + _scale: scale, + // Data + _children: points, + _loop: true, + // Model + _model: { + // Appearance + tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor), + borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth), + borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor), + fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill), + borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle), + borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash), + borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset), + borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle), + } + }); + + meta.dataset.pivot(); + + // Update Points + helpers.each(points, function(point, index) { + me.updateElement(point, index, reset); + }, me); + + // Update bezier control points + me.updateBezierControlPoints(); + }, + updateElement: function(point, index, reset) { + var me = this; + var custom = point.custom || {}; + var dataset = me.getDataset(); + var scale = me.chart.scale; + var pointElementOptions = me.chart.options.elements.point; + var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]); + + // Compatibility: If the properties are defined with only the old name, use those values + if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) { + dataset.pointRadius = dataset.radius; + } + if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) { + dataset.pointHitRadius = dataset.hitRadius; + } + + helpers.extend(point, { + // Utility + _datasetIndex: me.index, + _index: index, + _scale: scale, + + // Desired view properties + _model: { + x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales + y: reset ? scale.yCenter : pointPosition.y, + + // Appearance + tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension), + radius: custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor), + borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor), + borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth), + pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle), + + // Tooltip + hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius) + } + }); + + point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); + }, + updateBezierControlPoints: function() { + var chartArea = this.chart.chartArea; + var meta = this.getMeta(); + + helpers.each(meta.data, function(point, index) { + var model = point._model; + var controlPoints = helpers.splineCurve( + helpers.previousItem(meta.data, index, true)._model, + model, + helpers.nextItem(meta.data, index, true)._model, + model.tension + ); + + // Prevent the bezier going outside of the bounds of the graph + model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left); + model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top); + + model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left); + model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top); + + // Now pivot the point for animation + point.pivot(); + }); + }, + + setHoverStyle: function(point) { + // Point + var dataset = this.chart.data.datasets[point._datasetIndex]; + var custom = point.custom || {}; + var index = point._index; + var model = point._model; + + model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius); + model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor)); + model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor)); + model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth); + }, + + removeHoverStyle: function(point) { + var dataset = this.chart.data.datasets[point._datasetIndex]; + var custom = point.custom || {}; + var index = point._index; + var model = point._model; + var pointElementOptions = this.chart.options.elements.point; + + model.radius = custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius); + model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor); + model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor); + model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth); + } + }); +}; + +},{"25":25,"40":40,"45":45}],21:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); + +defaults._set('scatter', { + hover: { + mode: 'single' + }, + + scales: { + xAxes: [{ + id: 'x-axis-1', // need an ID so datasets can reference the scale + type: 'linear', // scatter should not use a category axis + position: 'bottom' + }], + yAxes: [{ + id: 'y-axis-1', + type: 'linear', + position: 'left' + }] + }, + + showLines: false, + + tooltips: { + callbacks: { + title: function() { + return ''; // doesn't make sense for scatter since data are formatted as a point + }, + label: function(item) { + return '(' + item.xLabel + ', ' + item.yLabel + ')'; + } + } + } +}); + +module.exports = function(Chart) { + + // Scatter charts use line controllers + Chart.controllers.scatter = Chart.controllers.line; + +}; + +},{"25":25}],22:[function(require,module,exports){ +/* global window: false */ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); + +defaults._set('global', { + animation: { + duration: 1000, + easing: 'easeOutQuart', + onProgress: helpers.noop, + onComplete: helpers.noop + } +}); + +module.exports = function(Chart) { + + Chart.Animation = Element.extend({ + chart: null, // the animation associated chart instance + currentStep: 0, // the current animation step + numSteps: 60, // default number of steps + easing: '', // the easing to use for this animation + render: null, // render function used by the animation service + + onAnimationProgress: null, // user specified callback to fire on each step of the animation + onAnimationComplete: null, // user specified callback to fire when the animation finishes + }); + + Chart.animationService = { + frameDuration: 17, + animations: [], + dropFrames: 0, + request: null, + + /** + * @param {Chart} chart - The chart to animate. + * @param {Chart.Animation} animation - The animation that we will animate. + * @param {Number} duration - The animation duration in ms. + * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions + */ + addAnimation: function(chart, animation, duration, lazy) { + var animations = this.animations; + var i, ilen; + + animation.chart = chart; + + if (!lazy) { + chart.animating = true; + } + + for (i = 0, ilen = animations.length; i < ilen; ++i) { + if (animations[i].chart === chart) { + animations[i] = animation; + return; + } + } + + animations.push(animation); + + // If there are no animations queued, manually kickstart a digest, for lack of a better word + if (animations.length === 1) { + this.requestAnimationFrame(); + } + }, + + cancelAnimation: function(chart) { + var index = helpers.findIndex(this.animations, function(animation) { + return animation.chart === chart; + }); + + if (index !== -1) { + this.animations.splice(index, 1); + chart.animating = false; + } + }, + + requestAnimationFrame: function() { + var me = this; + if (me.request === null) { + // Skip animation frame requests until the active one is executed. + // This can happen when processing mouse events, e.g. 'mousemove' + // and 'mouseout' events will trigger multiple renders. + me.request = helpers.requestAnimFrame.call(window, function() { + me.request = null; + me.startDigest(); + }); + } + }, + + /** + * @private + */ + startDigest: function() { + var me = this; + var startTime = Date.now(); + var framesToDrop = 0; + + if (me.dropFrames > 1) { + framesToDrop = Math.floor(me.dropFrames); + me.dropFrames = me.dropFrames % 1; + } + + me.advance(1 + framesToDrop); + + var endTime = Date.now(); + + me.dropFrames += (endTime - startTime) / me.frameDuration; + + // Do we have more stuff to animate? + if (me.animations.length > 0) { + me.requestAnimationFrame(); + } + }, + + /** + * @private + */ + advance: function(count) { + var animations = this.animations; + var animation, chart; + var i = 0; + + while (i < animations.length) { + animation = animations[i]; + chart = animation.chart; + + animation.currentStep = (animation.currentStep || 0) + count; + animation.currentStep = Math.min(animation.currentStep, animation.numSteps); + + helpers.callback(animation.render, [chart, animation], chart); + helpers.callback(animation.onAnimationProgress, [animation], chart); + + if (animation.currentStep >= animation.numSteps) { + helpers.callback(animation.onAnimationComplete, [animation], chart); + chart.animating = false; + animations.splice(i, 1); + } else { + ++i; + } + } + } + }; + + /** + * Provided for backward compatibility, use Chart.Animation instead + * @prop Chart.Animation#animationObject + * @deprecated since version 2.6.0 + * @todo remove at version 3 + */ + Object.defineProperty(Chart.Animation.prototype, 'animationObject', { + get: function() { + return this; + } + }); + + /** + * Provided for backward compatibility, use Chart.Animation#chart instead + * @prop Chart.Animation#chartInstance + * @deprecated since version 2.6.0 + * @todo remove at version 3 + */ + Object.defineProperty(Chart.Animation.prototype, 'chartInstance', { + get: function() { + return this.chart; + }, + set: function(value) { + this.chart = value; + } + }); + +}; + +},{"25":25,"26":26,"45":45}],23:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var helpers = require(45); +var Interaction = require(28); +var platform = require(48); + +module.exports = function(Chart) { + var plugins = Chart.plugins; + + // Create a dictionary of chart types, to allow for extension of existing types + Chart.types = {}; + + // Store a reference to each instance - allowing us to globally resize chart instances on window resize. + // Destroy method on the chart will remove the instance of the chart from this reference. + Chart.instances = {}; + + // Controllers available for dataset visualization eg. bar, line, slice, etc. + Chart.controllers = {}; + + /** + * Initializes the given config with global and chart default values. + */ + function initConfig(config) { + config = config || {}; + + // Do NOT use configMerge() for the data object because this method merges arrays + // and so would change references to labels and datasets, preventing data updates. + var data = config.data = config.data || {}; + data.datasets = data.datasets || []; + data.labels = data.labels || []; + + config.options = helpers.configMerge( + defaults.global, + defaults[config.type], + config.options || {}); + + return config; + } + + /** + * Updates the config of the chart + * @param chart {Chart} chart to update the options for + */ + function updateConfig(chart) { + var newOptions = chart.options; + + // Update Scale(s) with options + if (newOptions.scale) { + chart.scale.options = newOptions.scale; + } else if (newOptions.scales) { + newOptions.scales.xAxes.concat(newOptions.scales.yAxes).forEach(function(scaleOptions) { + chart.scales[scaleOptions.id].options = scaleOptions; + }); + } + + // Tooltip + chart.tooltip._options = newOptions.tooltips; + } + + function positionIsHorizontal(position) { + return position === 'top' || position === 'bottom'; + } + + helpers.extend(Chart.prototype, /** @lends Chart */ { + /** + * @private + */ + construct: function(item, config) { + var me = this; + + config = initConfig(config); + + var context = platform.acquireContext(item, config); + var canvas = context && context.canvas; + var height = canvas && canvas.height; + var width = canvas && canvas.width; + + me.id = helpers.uid(); + me.ctx = context; + me.canvas = canvas; + me.config = config; + me.width = width; + me.height = height; + me.aspectRatio = height ? width / height : null; + me.options = config.options; + me._bufferedRender = false; + + /** + * Provided for backward compatibility, Chart and Chart.Controller have been merged, + * the "instance" still need to be defined since it might be called from plugins. + * @prop Chart#chart + * @deprecated since version 2.6.0 + * @todo remove at version 3 + * @private + */ + me.chart = me; + me.controller = me; // chart.chart.controller #inception + + // Add the chart instance to the global namespace + Chart.instances[me.id] = me; + + // Define alias to the config data: `chart.data === chart.config.data` + Object.defineProperty(me, 'data', { + get: function() { + return me.config.data; + }, + set: function(value) { + me.config.data = value; + } + }); + + if (!context || !canvas) { + // The given item is not a compatible context2d element, let's return before finalizing + // the chart initialization but after setting basic chart / controller properties that + // can help to figure out that the chart is not valid (e.g chart.canvas !== null); + // https://github.com/chartjs/Chart.js/issues/2807 + console.error("Failed to create chart: can't acquire context from the given item"); + return; + } + + me.initialize(); + me.update(); + }, + + /** + * @private + */ + initialize: function() { + var me = this; + + // Before init plugin notification + plugins.notify(me, 'beforeInit'); + + helpers.retinaScale(me, me.options.devicePixelRatio); + + me.bindEvents(); + + if (me.options.responsive) { + // Initial resize before chart draws (must be silent to preserve initial animations). + me.resize(true); + } + + // Make sure scales have IDs and are built before we build any controllers. + me.ensureScalesHaveIDs(); + me.buildScales(); + me.initToolTip(); + + // After init plugin notification + plugins.notify(me, 'afterInit'); + + return me; + }, + + clear: function() { + helpers.canvas.clear(this); + return this; + }, + + stop: function() { + // Stops any current animation loop occurring + Chart.animationService.cancelAnimation(this); + return this; + }, + + resize: function(silent) { + var me = this; + var options = me.options; + var canvas = me.canvas; + var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null; + + // the canvas render width and height will be casted to integers so make sure that + // the canvas display style uses the same integer values to avoid blurring effect. + + // Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collased + var newWidth = Math.max(0, Math.floor(helpers.getMaximumWidth(canvas))); + var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas))); + + if (me.width === newWidth && me.height === newHeight) { + return; + } + + canvas.width = me.width = newWidth; + canvas.height = me.height = newHeight; + canvas.style.width = newWidth + 'px'; + canvas.style.height = newHeight + 'px'; + + helpers.retinaScale(me, options.devicePixelRatio); + + if (!silent) { + // Notify any plugins about the resize + var newSize = {width: newWidth, height: newHeight}; + plugins.notify(me, 'resize', [newSize]); + + // Notify of resize + if (me.options.onResize) { + me.options.onResize(me, newSize); + } + + me.stop(); + me.update(me.options.responsiveAnimationDuration); + } + }, + + ensureScalesHaveIDs: function() { + var options = this.options; + var scalesOptions = options.scales || {}; + var scaleOptions = options.scale; + + helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) { + xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index); + }); + + helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) { + yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index); + }); + + if (scaleOptions) { + scaleOptions.id = scaleOptions.id || 'scale'; + } + }, + + /** + * Builds a map of scale ID to scale object for future lookup. + */ + buildScales: function() { + var me = this; + var options = me.options; + var scales = me.scales = {}; + var items = []; + + if (options.scales) { + items = items.concat( + (options.scales.xAxes || []).map(function(xAxisOptions) { + return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'}; + }), + (options.scales.yAxes || []).map(function(yAxisOptions) { + return {options: yAxisOptions, dtype: 'linear', dposition: 'left'}; + }) + ); + } + + if (options.scale) { + items.push({ + options: options.scale, + dtype: 'radialLinear', + isDefault: true, + dposition: 'chartArea' + }); + } + + helpers.each(items, function(item) { + var scaleOptions = item.options; + var scaleType = helpers.valueOrDefault(scaleOptions.type, item.dtype); + var scaleClass = Chart.scaleService.getScaleConstructor(scaleType); + if (!scaleClass) { + return; + } + + if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) { + scaleOptions.position = item.dposition; + } + + var scale = new scaleClass({ + id: scaleOptions.id, + options: scaleOptions, + ctx: me.ctx, + chart: me + }); + + scales[scale.id] = scale; + scale.mergeTicksOptions(); + + // TODO(SB): I think we should be able to remove this custom case (options.scale) + // and consider it as a regular scale part of the "scales"" map only! This would + // make the logic easier and remove some useless? custom code. + if (item.isDefault) { + me.scale = scale; + } + }); + + Chart.scaleService.addScalesToLayout(this); + }, + + buildOrUpdateControllers: function() { + var me = this; + var types = []; + var newControllers = []; + + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + var meta = me.getDatasetMeta(datasetIndex); + var type = dataset.type || me.config.type; + + if (meta.type && meta.type !== type) { + me.destroyDatasetMeta(datasetIndex); + meta = me.getDatasetMeta(datasetIndex); + } + meta.type = type; + + types.push(meta.type); + + if (meta.controller) { + meta.controller.updateIndex(datasetIndex); + } else { + var ControllerClass = Chart.controllers[meta.type]; + if (ControllerClass === undefined) { + throw new Error('"' + meta.type + '" is not a chart type.'); + } + + meta.controller = new ControllerClass(me, datasetIndex); + newControllers.push(meta.controller); + } + }, me); + + return newControllers; + }, + + /** + * Reset the elements of all datasets + * @private + */ + resetElements: function() { + var me = this; + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + me.getDatasetMeta(datasetIndex).controller.reset(); + }, me); + }, + + /** + * Resets the chart back to it's state before the initial animation + */ + reset: function() { + this.resetElements(); + this.tooltip.initialize(); + }, + + update: function(config) { + var me = this; + + if (!config || typeof config !== 'object') { + // backwards compatibility + config = { + duration: config, + lazy: arguments[1] + }; + } + + updateConfig(me); + + if (plugins.notify(me, 'beforeUpdate') === false) { + return; + } + + // In case the entire data object changed + me.tooltip._data = me.data; + + // Make sure dataset controllers are updated and new controllers are reset + var newControllers = me.buildOrUpdateControllers(); + + // Make sure all dataset controllers have correct meta data counts + helpers.each(me.data.datasets, function(dataset, datasetIndex) { + me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements(); + }, me); + + me.updateLayout(); + + // Can only reset the new controllers after the scales have been updated + helpers.each(newControllers, function(controller) { + controller.reset(); + }); + + 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'); + + if (me._bufferedRender) { + me._bufferedRequest = { + duration: config.duration, + easing: config.easing, + lazy: config.lazy + }; + } else { + me.render(config); + } + }, + + /** + * Updates the chart layout unless a plugin returns `false` to the `beforeLayout` + * hook, in which case, plugins will not be called on `afterLayout`. + * @private + */ + updateLayout: function() { + var me = this; + + if (plugins.notify(me, 'beforeLayout') === false) { + return; + } + + Chart.layoutService.update(this, this.width, this.height); + + /** + * Provided for backward compatibility, use `afterLayout` instead. + * @method IPlugin#afterScaleUpdate + * @deprecated since version 2.5.0 + * @todo remove at version 3 + * @private + */ + plugins.notify(me, 'afterScaleUpdate'); + plugins.notify(me, 'afterLayout'); + }, + + /** + * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate` + * hook, in which case, plugins will not be called on `afterDatasetsUpdate`. + * @private + */ + updateDatasets: function() { + var me = this; + + if (plugins.notify(me, 'beforeDatasetsUpdate') === false) { + return; + } + + for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me.updateDataset(i); + } + + plugins.notify(me, 'afterDatasetsUpdate'); + }, + + /** + * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate` + * hook, in which case, plugins will not be called on `afterDatasetUpdate`. + * @private + */ + updateDataset: function(index) { + var me = this; + var meta = me.getDatasetMeta(index); + var args = { + meta: meta, + index: index + }; + + if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) { + return; + } + + meta.controller.update(); + + plugins.notify(me, 'afterDatasetUpdate', [args]); + }, + + render: function(config) { + var me = this; + + if (!config || typeof config !== 'object') { + // backwards compatibility + config = { + duration: config, + lazy: arguments[1] + }; + } + + var duration = config.duration; + var lazy = config.lazy; + + if (plugins.notify(me, 'beforeRender') === false) { + return; + } + + var animationOptions = me.options.animation; + var onComplete = function(animation) { + plugins.notify(me, 'afterRender'); + helpers.callback(animationOptions && animationOptions.onComplete, [animation], me); + }; + + if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) { + var animation = new Chart.Animation({ + numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps + easing: config.easing || animationOptions.easing, + + render: function(chart, animationObject) { + var easingFunction = helpers.easing.effects[animationObject.easing]; + var currentStep = animationObject.currentStep; + var stepDecimal = currentStep / animationObject.numSteps; + + chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep); + }, + + onAnimationProgress: animationOptions.onProgress, + onAnimationComplete: onComplete + }); + + Chart.animationService.addAnimation(me, animation, duration, lazy); + } else { + me.draw(); + + // See https://github.com/chartjs/Chart.js/issues/3781 + onComplete(new Chart.Animation({numSteps: 0, chart: me})); + } + + return me; + }, + + draw: function(easingValue) { + var me = this; + + me.clear(); + + if (helpers.isNullOrUndef(easingValue)) { + easingValue = 1; + } + + me.transition(easingValue); + + if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) { + return; + } + + // Draw all the scales + helpers.each(me.boxes, function(box) { + box.draw(me.chartArea); + }, me); + + if (me.scale) { + me.scale.draw(); + } + + me.drawDatasets(easingValue); + me._drawTooltip(easingValue); + + plugins.notify(me, 'afterDraw', [easingValue]); + }, + + /** + * @private + */ + transition: function(easingValue) { + var me = this; + + for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) { + if (me.isDatasetVisible(i)) { + me.getDatasetMeta(i).controller.transition(easingValue); + } + } + + me.tooltip.transition(easingValue); + }, + + /** + * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw` + * hook, in which case, plugins will not be called on `afterDatasetsDraw`. + * @private + */ + drawDatasets: function(easingValue) { + var me = this; + + if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) { + return; + } + + // Draw datasets reversed to support proper line stacking + for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) { + if (me.isDatasetVisible(i)) { + me.drawDataset(i, easingValue); + } + } + + plugins.notify(me, 'afterDatasetsDraw', [easingValue]); + }, + + /** + * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw` + * hook, in which case, plugins will not be called on `afterDatasetDraw`. + * @private + */ + drawDataset: function(index, easingValue) { + var me = this; + var meta = me.getDatasetMeta(index); + var args = { + meta: meta, + index: index, + easingValue: easingValue + }; + + if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) { + return; + } + + meta.controller.draw(easingValue); + + 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) { + return Interaction.modes.single(this, e); + }, + + getElementsAtEvent: function(e) { + return Interaction.modes.label(this, e, {intersect: true}); + }, + + getElementsAtXAxis: function(e) { + return Interaction.modes['x-axis'](this, e, {intersect: true}); + }, + + getElementsAtEventForMode: function(e, mode, options) { + var method = Interaction.modes[mode]; + if (typeof method === 'function') { + return method(this, e, options); + } + + return []; + }, + + getDatasetAtEvent: function(e) { + return Interaction.modes.dataset(this, e, {intersect: true}); + }, + + getDatasetMeta: function(datasetIndex) { + var me = this; + var dataset = me.data.datasets[datasetIndex]; + if (!dataset._meta) { + dataset._meta = {}; + } + + var meta = dataset._meta[me.id]; + if (!meta) { + meta = dataset._meta[me.id] = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, // See isDatasetVisible() comment + xAxisID: null, + yAxisID: null + }; + } + + return meta; + }, + + getVisibleDatasetCount: function() { + var count = 0; + for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + if (this.isDatasetVisible(i)) { + count++; + } + } + return count; + }, + + isDatasetVisible: function(datasetIndex) { + var meta = this.getDatasetMeta(datasetIndex); + + // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false, + // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned. + return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden; + }, + + generateLegend: function() { + return this.options.legendCallback(this); + }, + + /** + * @private + */ + destroyDatasetMeta: function(datasetIndex) { + var id = this.id; + var dataset = this.data.datasets[datasetIndex]; + var meta = dataset._meta && dataset._meta[id]; + + if (meta) { + meta.controller.destroy(); + delete dataset._meta[id]; + } + }, + + destroy: function() { + var me = this; + var canvas = me.canvas; + var i, ilen; + + me.stop(); + + // dataset controllers need to cleanup associated data + for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me.destroyDatasetMeta(i); + } + + if (canvas) { + me.unbindEvents(); + helpers.canvas.clear(me); + platform.releaseContext(me.ctx); + me.canvas = null; + me.ctx = null; + } + + plugins.notify(me, 'destroy'); + + delete Chart.instances[me.id]; + }, + + toBase64Image: function() { + return this.canvas.toDataURL.apply(this.canvas, arguments); + }, + + initToolTip: function() { + var me = this; + me.tooltip = new Chart.Tooltip({ + _chart: me, + _chartInstance: me, // deprecated, backward compatibility + _data: me.data, + _options: me.options.tooltips + }, me); + }, + + /** + * @private + */ + bindEvents: function() { + var me = this; + var listeners = me._listeners = {}; + var listener = function() { + me.eventHandler.apply(me, arguments); + }; + + helpers.each(me.options.events, function(type) { + platform.addEventListener(me, type, listener); + listeners[type] = listener; + }); + + // Elements used to detect size change should not be injected for non responsive charts. + // See https://github.com/chartjs/Chart.js/issues/2210 + if (me.options.responsive) { + listener = function() { + me.resize(); + }; + + platform.addEventListener(me, 'resize', listener); + listeners.resize = listener; + } + }, + + /** + * @private + */ + unbindEvents: function() { + var me = this; + var listeners = me._listeners; + if (!listeners) { + return; + } + + delete me._listeners; + helpers.each(listeners, function(listener, type) { + platform.removeEventListener(me, type, listener); + }); + }, + + updateHoverStyle: function(elements, mode, enabled) { + var method = enabled ? 'setHoverStyle' : 'removeHoverStyle'; + var element, i, ilen; + + for (i = 0, ilen = elements.length; i < ilen; ++i) { + element = elements[i]; + if (element) { + this.getDatasetMeta(element._datasetIndex).controller[method](element); + } + } + }, + + /** + * @private + */ + eventHandler: function(e) { + var me = this; + var tooltip = me.tooltip; + + if (plugins.notify(me, 'beforeEvent', [e]) === false) { + return; + } + + // Buffer any update calls so that renders do not occur + me._bufferedRender = true; + me._bufferedRequest = null; + + var changed = me.handleEvent(e); + changed |= tooltip && tooltip.handleEvent(e); + + plugins.notify(me, 'afterEvent', [e]); + + var bufferedRequest = me._bufferedRequest; + if (bufferedRequest) { + // If we have an update that was triggered, we need to do a normal render + me.render(bufferedRequest); + } else if (changed && !me.animating) { + // If entering, leaving, or changing elements, animate the change via pivot + me.stop(); + + // We only need to render at this point. Updating will cause scales to be + // recomputed generating flicker & using more memory than necessary. + me.render(me.options.hover.animationDuration, true); + } + + me._bufferedRender = false; + me._bufferedRequest = null; + + return me; + }, + + /** + * Handle an event + * @private + * @param {IEvent} event the event to handle + * @return {Boolean} true if the chart needs to re-render + */ + handleEvent: function(e) { + var me = this; + var options = me.options || {}; + var hoverOptions = options.hover; + var changed = false; + + me.lastActive = me.lastActive || []; + + // Find Active Elements for hover and tooltips + if (e.type === 'mouseout') { + me.active = []; + } else { + me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions); + } + + // Invoke onHover hook + // Need to call with native event here to not break backwards compatibility + helpers.callback(options.onHover || options.hover.onHover, [e.native, me.active], me); + + if (e.type === 'mouseup' || e.type === 'click') { + if (options.onClick) { + // Use e.native here for backwards compatibility + options.onClick.call(me, e.native, me.active); + } + } + + // Remove styling for last active (even if it may still be active) + if (me.lastActive.length) { + me.updateHoverStyle(me.lastActive, hoverOptions.mode, false); + } + + // Built in hover styling + if (me.active.length && hoverOptions.mode) { + me.updateHoverStyle(me.active, hoverOptions.mode, true); + } + + changed = !helpers.arrayEquals(me.active, me.lastActive); + + // Remember Last Actives + me.lastActive = me.active; + + return changed; + } + }); + + /** + * Provided for backward compatibility, use Chart instead. + * @class Chart.Controller + * @deprecated since version 2.6.0 + * @todo remove at version 3 + * @private + */ + Chart.Controller = Chart; +}; + +},{"25":25,"28":28,"45":45,"48":48}],24:[function(require,module,exports){ +'use strict'; + +var helpers = require(45); + +module.exports = function(Chart) { + + var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; + + /** + * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice', + * 'unshift') and notify the listener AFTER the array has been altered. Listeners are + * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments. + */ + function listenArrayEvents(array, listener) { + if (array._chartjs) { + array._chartjs.listeners.push(listener); + return; + } + + Object.defineProperty(array, '_chartjs', { + configurable: true, + enumerable: false, + value: { + listeners: [listener] + } + }); + + arrayEvents.forEach(function(key) { + var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1); + var base = array[key]; + + Object.defineProperty(array, key, { + configurable: true, + enumerable: false, + value: function() { + var args = Array.prototype.slice.call(arguments); + var res = base.apply(this, args); + + helpers.each(array._chartjs.listeners, function(object) { + if (typeof object[method] === 'function') { + object[method].apply(object, args); + } + }); + + return res; + } + }); + }); + } + + /** + * Removes the given array event listener and cleanup extra attached properties (such as + * the _chartjs stub and overridden methods) if array doesn't have any more listeners. + */ + function unlistenArrayEvents(array, listener) { + var stub = array._chartjs; + if (!stub) { + return; + } + + var listeners = stub.listeners; + var index = listeners.indexOf(listener); + if (index !== -1) { + listeners.splice(index, 1); + } + + if (listeners.length > 0) { + return; + } + + arrayEvents.forEach(function(key) { + delete array[key]; + }); + + delete array._chartjs; + } + + // Base class for all dataset controllers (line, bar, etc) + Chart.DatasetController = function(chart, datasetIndex) { + this.initialize(chart, datasetIndex); + }; + + helpers.extend(Chart.DatasetController.prototype, { + + /** + * Element type used to generate a meta dataset (e.g. Chart.element.Line). + * @type {Chart.core.element} + */ + datasetElementType: null, + + /** + * Element type used to generate a meta data (e.g. Chart.element.Point). + * @type {Chart.core.element} + */ + dataElementType: null, + + initialize: function(chart, datasetIndex) { + var me = this; + me.chart = chart; + me.index = datasetIndex; + me.linkScales(); + me.addElements(); + }, + + updateIndex: function(datasetIndex) { + this.index = datasetIndex; + }, + + linkScales: function() { + var me = this; + var meta = me.getMeta(); + var dataset = me.getDataset(); + + if (meta.xAxisID === null) { + meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id; + } + if (meta.yAxisID === null) { + meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id; + } + }, + + getDataset: function() { + return this.chart.data.datasets[this.index]; + }, + + getMeta: function() { + return this.chart.getDatasetMeta(this.index); + }, + + getScaleForId: function(scaleID) { + return this.chart.scales[scaleID]; + }, + + reset: function() { + this.update(true); + }, + + /** + * @private + */ + destroy: function() { + if (this._data) { + unlistenArrayEvents(this._data, this); + } + }, + + createMetaDataset: function() { + var me = this; + var type = me.datasetElementType; + return type && new type({ + _chart: me.chart, + _datasetIndex: me.index + }); + }, + + createMetaData: function(index) { + var me = this; + var type = me.dataElementType; + return type && new type({ + _chart: me.chart, + _datasetIndex: me.index, + _index: index + }); + }, + + addElements: function() { + var me = this; + var meta = me.getMeta(); + var data = me.getDataset().data || []; + var metaData = meta.data; + var i, ilen; + + for (i = 0, ilen = data.length; i < ilen; ++i) { + metaData[i] = metaData[i] || me.createMetaData(i); + } + + meta.dataset = meta.dataset || me.createMetaDataset(); + }, + + addElementAndReset: function(index) { + var element = this.createMetaData(index); + this.getMeta().data.splice(index, 0, element); + this.updateElement(element, index, true); + }, + + buildOrUpdateElements: function() { + var me = this; + var dataset = me.getDataset(); + var data = dataset.data || (dataset.data = []); + + // In order to correctly handle data addition/deletion animation (an thus simulate + // real-time charts), we need to monitor these data modifications and synchronize + // the internal meta data accordingly. + if (me._data !== data) { + if (me._data) { + // This case happens when the user replaced the data array instance. + unlistenArrayEvents(me._data, me); + } + + listenArrayEvents(data, me); + me._data = data; + } + + // Re-sync meta data in case the user replaced the data array or if we missed + // any updates and so make sure that we handle number of datapoints changing. + me.resyncElements(); + }, + + update: helpers.noop, + + transition: function(easingValue) { + var meta = this.getMeta(); + var elements = meta.data || []; + var ilen = elements.length; + var i = 0; + + for (; i < ilen; ++i) { + elements[i].transition(easingValue); + } + + if (meta.dataset) { + meta.dataset.transition(easingValue); + } + }, + + draw: function() { + var meta = this.getMeta(); + var elements = meta.data || []; + var ilen = elements.length; + var i = 0; + + if (meta.dataset) { + meta.dataset.draw(); + } + + for (; i < ilen; ++i) { + elements[i].draw(); + } + }, + + removeHoverStyle: function(element, elementOpts) { + var dataset = this.chart.data.datasets[element._datasetIndex]; + var index = element._index; + var custom = element.custom || {}; + var valueOrDefault = helpers.valueAtIndexOrDefault; + var model = element._model; + + model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor); + model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor); + model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth); + }, + + setHoverStyle: function(element) { + var dataset = this.chart.data.datasets[element._datasetIndex]; + var index = element._index; + var custom = element.custom || {}; + var valueOrDefault = helpers.valueAtIndexOrDefault; + var getHoverColor = helpers.getHoverColor; + var model = element._model; + + model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor)); + model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor)); + model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth); + }, + + /** + * @private + */ + resyncElements: function() { + var me = this; + var meta = me.getMeta(); + var data = me.getDataset().data; + var numMeta = meta.data.length; + var numData = data.length; + + if (numData < numMeta) { + meta.data.splice(numData, numMeta - numData); + } else if (numData > numMeta) { + me.insertElements(numMeta, numData - numMeta); + } + }, + + /** + * @private + */ + insertElements: function(start, count) { + for (var i = 0; i < count; ++i) { + this.addElementAndReset(start + i); + } + }, + + /** + * @private + */ + onDataPush: function() { + this.insertElements(this.getDataset().data.length - 1, arguments.length); + }, + + /** + * @private + */ + onDataPop: function() { + this.getMeta().data.pop(); + }, + + /** + * @private + */ + onDataShift: function() { + this.getMeta().data.shift(); + }, + + /** + * @private + */ + onDataSplice: function(start, count) { + this.getMeta().data.splice(start, count); + this.insertElements(start, arguments.length - 2); + }, + + /** + * @private + */ + onDataUnshift: function() { + this.insertElements(0, arguments.length); + } + }); + + Chart.DatasetController.extend = helpers.inherits; +}; + +},{"45":45}],25:[function(require,module,exports){ +'use strict'; + +var helpers = require(45); + +module.exports = { + /** + * @private + */ + _set: function(scope, values) { + return helpers.merge(this[scope] || (this[scope] = {}), values); + } +}; + +},{"45":45}],26:[function(require,module,exports){ +'use strict'; + +var color = require(2); +var helpers = require(45); + +function interpolate(start, view, model, ease) { + var keys = Object.keys(model); + var i, ilen, key, actual, origin, target, type, c0, c1; + + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + + target = model[key]; + + // if a value is added to the model after pivot() has been called, the view + // doesn't contain it, so let's initialize the view to the target value. + if (!view.hasOwnProperty(key)) { + view[key] = target; + } + + actual = view[key]; + + if (actual === target || key[0] === '_') { + continue; + } + + if (!start.hasOwnProperty(key)) { + start[key] = actual; + } + + origin = start[key]; + + type = typeof target; + + if (type === typeof origin) { + if (type === 'string') { + c0 = color(origin); + if (c0.valid) { + c1 = color(target); + if (c1.valid) { + view[key] = c1.mix(c0, ease).rgbString(); + continue; + } + } + } else if (type === 'number' && isFinite(origin) && isFinite(target)) { + view[key] = origin + (target - origin) * ease; + continue; + } + } + + view[key] = target; + } +} + +var Element = function(configuration) { + helpers.extend(this, configuration); + this.initialize.apply(this, arguments); +}; + +helpers.extend(Element.prototype, { + + initialize: function() { + this.hidden = false; + }, + + pivot: function() { + var me = this; + if (!me._view) { + me._view = helpers.clone(me._model); + } + me._start = {}; + return me; + }, + + transition: function(ease) { + var me = this; + var model = me._model; + var start = me._start; + var view = me._view; + + // No animation -> No Transition + if (!model || ease === 1) { + me._view = model; + me._start = null; + return me; + } + + if (!view) { + view = me._view = {}; + } + + if (!start) { + start = me._start = {}; + } + + interpolate(start, view, model, ease); + + return me; + }, + + tooltipPosition: function() { + return { + x: this._model.x, + y: this._model.y + }; + }, + + hasValue: function() { + return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y); + } +}); + +Element.extend = helpers.inherits; + +module.exports = Element; + +},{"2":2,"45":45}],27:[function(require,module,exports){ +/* global window: false */ +/* global document: false */ +'use strict'; + +var color = require(2); +var defaults = require(25); +var helpers = require(45); + +module.exports = function(Chart) { + + // -- Basic js utility methods + + helpers.configMerge = function(/* objects ... */) { + return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), { + merger: function(key, target, source, options) { + var tval = target[key] || {}; + var sval = source[key]; + + if (key === 'scales') { + // scale config merging is complex. Add our own function here for that + target[key] = helpers.scaleMerge(tval, sval); + } else if (key === 'scale') { + // used in polar area & radar charts since there is only one scale + target[key] = helpers.merge(tval, [Chart.scaleService.getScaleDefaults(sval.type), sval]); + } else { + helpers._merger(key, target, source, options); + } + } + }); + }; + + helpers.scaleMerge = function(/* objects ... */) { + return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), { + merger: function(key, target, source, options) { + if (key === 'xAxes' || key === 'yAxes') { + var slen = source[key].length; + var i, type, scale; + + if (!target[key]) { + target[key] = []; + } + + for (i = 0; i < slen; ++i) { + scale = source[key][i]; + type = helpers.valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear'); + + if (i >= target[key].length) { + target[key].push({}); + } + + if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) { + // new/untyped scale or type changed: let's apply the new defaults + // then merge source scale to correctly overwrite the defaults. + helpers.merge(target[key][i], [Chart.scaleService.getScaleDefaults(type), scale]); + } else { + // scales type are the same + helpers.merge(target[key][i], scale); + } + } + } else { + helpers._merger(key, target, source, options); + } + } + }); + }; + + helpers.where = function(collection, filterCallback) { + if (helpers.isArray(collection) && Array.prototype.filter) { + return collection.filter(filterCallback); + } + var filtered = []; + + helpers.each(collection, function(item) { + if (filterCallback(item)) { + filtered.push(item); + } + }); + + return filtered; + }; + helpers.findIndex = Array.prototype.findIndex ? + function(array, callback, scope) { + return array.findIndex(callback, scope); + } : + function(array, callback, scope) { + scope = scope === undefined ? array : scope; + for (var i = 0, ilen = array.length; i < ilen; ++i) { + if (callback.call(scope, array[i], i, array)) { + return i; + } + } + return -1; + }; + helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) { + // Default to start of the array + if (helpers.isNullOrUndef(startIndex)) { + startIndex = -1; + } + for (var i = startIndex + 1; i < arrayToSearch.length; i++) { + var currentItem = arrayToSearch[i]; + if (filterCallback(currentItem)) { + return currentItem; + } + } + }; + helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) { + // Default to end of the array + if (helpers.isNullOrUndef(startIndex)) { + startIndex = arrayToSearch.length; + } + for (var i = startIndex - 1; i >= 0; i--) { + var currentItem = arrayToSearch[i]; + if (filterCallback(currentItem)) { + return currentItem; + } + } + }; + + // -- Math methods + helpers.isNumber = function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }; + helpers.almostEquals = function(x, y, epsilon) { + return Math.abs(x - y) < epsilon; + }; + helpers.almostWhole = function(x, epsilon) { + var rounded = Math.round(x); + return (((rounded - epsilon) < x) && ((rounded + epsilon) > x)); + }; + helpers.max = function(array) { + return array.reduce(function(max, value) { + if (!isNaN(value)) { + return Math.max(max, value); + } + return max; + }, Number.NEGATIVE_INFINITY); + }; + helpers.min = function(array) { + return array.reduce(function(min, value) { + if (!isNaN(value)) { + return Math.min(min, value); + } + return min; + }, Number.POSITIVE_INFINITY); + }; + helpers.sign = Math.sign ? + function(x) { + return Math.sign(x); + } : + function(x) { + x = +x; // convert to a number + if (x === 0 || isNaN(x)) { + return x; + } + return x > 0 ? 1 : -1; + }; + helpers.log10 = Math.log10 ? + function(x) { + return Math.log10(x); + } : + function(x) { + return Math.log(x) / Math.LN10; + }; + helpers.toRadians = function(degrees) { + return degrees * (Math.PI / 180); + }; + helpers.toDegrees = function(radians) { + return radians * (180 / Math.PI); + }; + // Gets the angle from vertical upright to the point about a centre. + helpers.getAngleFromPoint = function(centrePoint, anglePoint) { + var distanceFromXCenter = anglePoint.x - centrePoint.x; + var distanceFromYCenter = anglePoint.y - centrePoint.y; + var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); + + var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); + + if (angle < (-0.5 * Math.PI)) { + angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2] + } + + return { + angle: angle, + distance: radialDistanceFromCenter + }; + }; + helpers.distanceBetweenPoints = function(pt1, pt2) { + return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); + }; + helpers.aliasPixel = function(pixelWidth) { + return (pixelWidth % 2 === 0) ? 0 : 0.5; + }; + helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) { + // Props to Rob Spencer at scaled innovation for his post on splining between points + // http://scaledinnovation.com/analytics/splines/aboutSplines.html + + // This function must also respect "skipped" points + + var previous = firstPoint.skip ? middlePoint : firstPoint; + var current = middlePoint; + var next = afterPoint.skip ? middlePoint : afterPoint; + + var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2)); + var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2)); + + var s01 = d01 / (d01 + d12); + var s12 = d12 / (d01 + d12); + + // If all points are the same, s01 & s02 will be inf + s01 = isNaN(s01) ? 0 : s01; + s12 = isNaN(s12) ? 0 : s12; + + var fa = t * s01; // scaling factor for triangle Ta + var fb = t * s12; + + return { + previous: { + x: current.x - fa * (next.x - previous.x), + y: current.y - fa * (next.y - previous.y) + }, + next: { + x: current.x + fb * (next.x - previous.x), + y: current.y + fb * (next.y - previous.y) + } + }; + }; + helpers.EPSILON = Number.EPSILON || 1e-14; + helpers.splineCurveMonotone = function(points) { + // This function calculates Bézier control points in a similar way than |splineCurve|, + // but preserves monotonicity of the provided data and ensures no local extremums are added + // between the dataset discrete points due to the interpolation. + // See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation + + var pointsWithTangents = (points || []).map(function(point) { + return { + model: point._model, + deltaK: 0, + mK: 0 + }; + }); + + // Calculate slopes (deltaK) and initialize tangents (mK) + var pointsLen = pointsWithTangents.length; + var i, pointBefore, pointCurrent, pointAfter; + for (i = 0; i < pointsLen; ++i) { + pointCurrent = pointsWithTangents[i]; + if (pointCurrent.model.skip) { + continue; + } + + pointBefore = i > 0 ? pointsWithTangents[i - 1] : null; + pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null; + if (pointAfter && !pointAfter.model.skip) { + var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x); + + // In the case of two points that appear at the same x pixel, slopeDeltaX is 0 + pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0; + } + + if (!pointBefore || pointBefore.model.skip) { + pointCurrent.mK = pointCurrent.deltaK; + } else if (!pointAfter || pointAfter.model.skip) { + pointCurrent.mK = pointBefore.deltaK; + } else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) { + pointCurrent.mK = 0; + } else { + pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2; + } + } + + // Adjust tangents to ensure monotonic properties + var alphaK, betaK, tauK, squaredMagnitude; + for (i = 0; i < pointsLen - 1; ++i) { + pointCurrent = pointsWithTangents[i]; + pointAfter = pointsWithTangents[i + 1]; + if (pointCurrent.model.skip || pointAfter.model.skip) { + continue; + } + + if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) { + pointCurrent.mK = pointAfter.mK = 0; + continue; + } + + alphaK = pointCurrent.mK / pointCurrent.deltaK; + betaK = pointAfter.mK / pointCurrent.deltaK; + squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); + if (squaredMagnitude <= 9) { + continue; + } + + tauK = 3 / Math.sqrt(squaredMagnitude); + pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK; + pointAfter.mK = betaK * tauK * pointCurrent.deltaK; + } + + // Compute control points + var deltaX; + for (i = 0; i < pointsLen; ++i) { + pointCurrent = pointsWithTangents[i]; + if (pointCurrent.model.skip) { + continue; + } + + pointBefore = i > 0 ? pointsWithTangents[i - 1] : null; + pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null; + if (pointBefore && !pointBefore.model.skip) { + deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3; + pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX; + pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK; + } + if (pointAfter && !pointAfter.model.skip) { + deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3; + pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX; + pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK; + } + } + }; + helpers.nextItem = function(collection, index, loop) { + if (loop) { + return index >= collection.length - 1 ? collection[0] : collection[index + 1]; + } + return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1]; + }; + helpers.previousItem = function(collection, index, loop) { + if (loop) { + return index <= 0 ? collection[collection.length - 1] : collection[index - 1]; + } + return index <= 0 ? collection[0] : collection[index - 1]; + }; + // Implementation of the nice number algorithm used in determining where axis labels will go + helpers.niceNum = function(range, round) { + var exponent = Math.floor(helpers.log10(range)); + var fraction = range / Math.pow(10, exponent); + var niceFraction; + + if (round) { + if (fraction < 1.5) { + niceFraction = 1; + } else if (fraction < 3) { + niceFraction = 2; + } else if (fraction < 7) { + niceFraction = 5; + } else { + niceFraction = 10; + } + } else if (fraction <= 1.0) { + niceFraction = 1; + } else if (fraction <= 2) { + niceFraction = 2; + } else if (fraction <= 5) { + niceFraction = 5; + } else { + niceFraction = 10; + } + + return niceFraction * Math.pow(10, exponent); + }; + // Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/ + helpers.requestAnimFrame = (function() { + if (typeof window === 'undefined') { + return function(callback) { + callback(); + }; + } + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function(callback) { + return window.setTimeout(callback, 1000 / 60); + }; + }()); + // -- DOM methods + helpers.getRelativePosition = function(evt, chart) { + var mouseX, mouseY; + var e = evt.originalEvent || evt; + var canvas = evt.currentTarget || evt.srcElement; + var boundingRect = canvas.getBoundingClientRect(); + + var touches = e.touches; + if (touches && touches.length > 0) { + mouseX = touches[0].clientX; + mouseY = touches[0].clientY; + + } else { + mouseX = e.clientX; + mouseY = e.clientY; + } + + // Scale mouse coordinates into canvas coordinates + // by following the pattern laid out by 'jerryj' in the comments of + // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/ + var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left')); + var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top')); + var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right')); + var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom')); + var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight; + var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom; + + // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However + // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here + mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio); + mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio); + + return { + x: mouseX, + y: mouseY + }; + + }; + + // Private helper function to convert max-width/max-height values that may be percentages into a number + function parseMaxStyle(styleValue, node, parentProperty) { + var valueInPixels; + if (typeof styleValue === 'string') { + valueInPixels = parseInt(styleValue, 10); + + if (styleValue.indexOf('%') !== -1) { + // percentage * size in dimension + valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; + } + } else { + valueInPixels = styleValue; + } + + return valueInPixels; + } + + /** + * Returns if the given value contains an effective constraint. + * @private + */ + function isConstrainedValue(value) { + return value !== undefined && value !== null && value !== 'none'; + } + + // Private helper to get a constraint dimension + // @param domNode : the node to check the constraint on + // @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight) + // @param percentageProperty : property of parent to use when calculating width as a percentage + // @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser + function getConstraintDimension(domNode, maxStyle, percentageProperty) { + var view = document.defaultView; + var parentNode = domNode.parentNode; + var constrainedNode = view.getComputedStyle(domNode)[maxStyle]; + var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle]; + var hasCNode = isConstrainedValue(constrainedNode); + var hasCContainer = isConstrainedValue(constrainedContainer); + var infinity = Number.POSITIVE_INFINITY; + + if (hasCNode || hasCContainer) { + return Math.min( + hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity, + hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity); + } + + return 'none'; + } + // returns Number or undefined if no constraint + helpers.getConstraintWidth = function(domNode) { + return getConstraintDimension(domNode, 'max-width', 'clientWidth'); + }; + // returns Number or undefined if no constraint + helpers.getConstraintHeight = function(domNode) { + return getConstraintDimension(domNode, 'max-height', 'clientHeight'); + }; + helpers.getMaximumWidth = function(domNode) { + var container = domNode.parentNode; + if (!container) { + return domNode.clientWidth; + } + + var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10); + var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10); + var w = container.clientWidth - paddingLeft - paddingRight; + var cw = helpers.getConstraintWidth(domNode); + return isNaN(cw) ? w : Math.min(w, cw); + }; + helpers.getMaximumHeight = function(domNode) { + var container = domNode.parentNode; + if (!container) { + return domNode.clientHeight; + } + + var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10); + var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10); + var h = container.clientHeight - paddingTop - paddingBottom; + var ch = helpers.getConstraintHeight(domNode); + return isNaN(ch) ? h : Math.min(h, ch); + }; + helpers.getStyle = function(el, property) { + return el.currentStyle ? + el.currentStyle[property] : + document.defaultView.getComputedStyle(el, null).getPropertyValue(property); + }; + helpers.retinaScale = function(chart, forceRatio) { + var pixelRatio = chart.currentDevicePixelRatio = forceRatio || window.devicePixelRatio || 1; + if (pixelRatio === 1) { + return; + } + + var canvas = chart.canvas; + var height = chart.height; + var width = chart.width; + + canvas.height = height * pixelRatio; + canvas.width = width * pixelRatio; + chart.ctx.scale(pixelRatio, pixelRatio); + + // If no style has been set on the canvas, the render size is used as display size, + // making the chart visually bigger, so let's enforce it to the "correct" values. + // See https://github.com/chartjs/Chart.js/issues/3575 + canvas.style.height = height + 'px'; + canvas.style.width = width + 'px'; + }; + // -- Canvas methods + helpers.fontString = function(pixelSize, fontStyle, fontFamily) { + return fontStyle + ' ' + pixelSize + 'px ' + fontFamily; + }; + helpers.longestText = function(ctx, font, arrayOfThings, cache) { + cache = cache || {}; + var data = cache.data = cache.data || {}; + var gc = cache.garbageCollect = cache.garbageCollect || []; + + if (cache.font !== font) { + data = cache.data = {}; + gc = cache.garbageCollect = []; + cache.font = font; + } + + ctx.font = font; + var longest = 0; + helpers.each(arrayOfThings, function(thing) { + // Undefined strings and arrays should not be measured + if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) { + longest = helpers.measureText(ctx, data, gc, longest, thing); + } else if (helpers.isArray(thing)) { + // if it is an array lets measure each element + // to do maybe simplify this function a bit so we can do this more recursively? + helpers.each(thing, function(nestedThing) { + // Undefined strings and arrays should not be measured + if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) { + longest = helpers.measureText(ctx, data, gc, longest, nestedThing); + } + }); + } + }); + + var gcLen = gc.length / 2; + if (gcLen > arrayOfThings.length) { + for (var i = 0; i < gcLen; i++) { + delete data[gc[i]]; + } + gc.splice(0, gcLen); + } + return longest; + }; + helpers.measureText = function(ctx, data, gc, longest, string) { + var textWidth = data[string]; + if (!textWidth) { + textWidth = data[string] = ctx.measureText(string).width; + gc.push(string); + } + if (textWidth > longest) { + longest = textWidth; + } + return longest; + }; + helpers.numberOfLabelLines = function(arrayOfThings) { + var numberOfLines = 1; + helpers.each(arrayOfThings, function(thing) { + if (helpers.isArray(thing)) { + if (thing.length > numberOfLines) { + numberOfLines = thing.length; + } + } + }); + return numberOfLines; + }; + + helpers.color = !color ? + function(value) { + console.error('Color.js not found!'); + return value; + } : + function(value) { + /* global CanvasGradient */ + if (value instanceof CanvasGradient) { + value = defaults.global.defaultColor; + } + + return color(value); + }; + + helpers.getHoverColor = function(colorValue) { + /* global CanvasPattern */ + return (colorValue instanceof CanvasPattern) ? + colorValue : + helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString(); + }; +}; + +},{"2":2,"25":25,"45":45}],28:[function(require,module,exports){ +'use strict'; + +var helpers = require(45); + +/** + * Helper function to get relative position for an event + * @param {Event|IEvent} event - The event to get the position for + * @param {Chart} chart - The chart + * @returns {Point} the event position + */ +function getRelativePosition(e, chart) { + if (e.native) { + return { + x: e.x, + y: e.y + }; + } + + return helpers.getRelativePosition(e, chart); +} + +/** + * Helper function to traverse all of the visible elements in the chart + * @param chart {chart} the chart + * @param handler {Function} the callback to execute for each visible item + */ +function parseVisibleItems(chart, handler) { + var datasets = chart.data.datasets; + var meta, i, j, ilen, jlen; + + for (i = 0, ilen = datasets.length; i < ilen; ++i) { + if (!chart.isDatasetVisible(i)) { + continue; + } + + meta = chart.getDatasetMeta(i); + for (j = 0, jlen = meta.data.length; j < jlen; ++j) { + var element = meta.data[j]; + if (!element._view.skip) { + handler(element); + } + } + } +} + +/** + * Helper function to get the items that intersect the event position + * @param items {ChartElement[]} elements to filter + * @param position {Point} the point to be nearest to + * @return {ChartElement[]} the nearest items + */ +function getIntersectItems(chart, position) { + var elements = []; + + parseVisibleItems(chart, function(element) { + if (element.inRange(position.x, position.y)) { + elements.push(element); + } + }); + + return elements; +} + +/** + * Helper function to get the items nearest to the event position considering all visible items in teh chart + * @param chart {Chart} the chart to look at elements from + * @param position {Point} the point to be nearest to + * @param intersect {Boolean} if true, only consider items that intersect the position + * @param distanceMetric {Function} function to provide the distance between points + * @return {ChartElement[]} the nearest items + */ +function getNearestItems(chart, position, intersect, distanceMetric) { + var minDistance = Number.POSITIVE_INFINITY; + var nearestItems = []; + + parseVisibleItems(chart, function(element) { + if (intersect && !element.inRange(position.x, position.y)) { + return; + } + + var center = element.getCenterPoint(); + var distance = distanceMetric(position, center); + + if (distance < minDistance) { + nearestItems = [element]; + minDistance = distance; + } else if (distance === minDistance) { + // Can have multiple items at the same distance in which case we sort by size + nearestItems.push(element); + } + }); + + return nearestItems; +} + +/** + * Get a distance metric function for two points based on the + * axis mode setting + * @param {String} axis the axis mode. x|y|xy + */ +function getDistanceMetricForAxis(axis) { + var useX = axis.indexOf('x') !== -1; + var useY = axis.indexOf('y') !== -1; + + return function(pt1, pt2) { + var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; + var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; + return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); + }; +} + +function indexMode(chart, e, options) { + var position = getRelativePosition(e, chart); + // Default axis for index mode is 'x' to match old behaviour + options.axis = options.axis || 'x'; + var distanceMetric = getDistanceMetricForAxis(options.axis); + var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); + var elements = []; + + if (!items.length) { + return []; + } + + chart.data.datasets.forEach(function(dataset, datasetIndex) { + if (chart.isDatasetVisible(datasetIndex)) { + var meta = chart.getDatasetMeta(datasetIndex); + var element = meta.data[items[0]._index]; + + // don't count items that are skipped (null data) + if (element && !element._view.skip) { + elements.push(element); + } + } + }); + + return elements; +} + +/** + * @interface IInteractionOptions + */ +/** + * If true, only consider items that intersect the point + * @name IInterfaceOptions#boolean + * @type Boolean + */ + +/** + * Contains interaction related functions + * @namespace Chart.Interaction + */ +module.exports = { + // Helper function for different modes + modes: { + single: function(chart, e) { + var position = getRelativePosition(e, chart); + var elements = []; + + parseVisibleItems(chart, function(element) { + if (element.inRange(position.x, position.y)) { + elements.push(element); + return elements; + } + }); + + return elements.slice(0, 1); + }, + + /** + * @function Chart.Interaction.modes.label + * @deprecated since version 2.4.0 + * @todo remove at version 3 + * @private + */ + label: indexMode, + + /** + * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something + * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item + * @function Chart.Interaction.modes.index + * @since v2.4.0 + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use during interaction + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + index: indexMode, + + /** + * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something + * If the options.intersect is false, we find the nearest item and return the items in that dataset + * @function Chart.Interaction.modes.dataset + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use during interaction + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + dataset: function(chart, e, options) { + var position = getRelativePosition(e, chart); + options.axis = options.axis || 'xy'; + var distanceMetric = getDistanceMetricForAxis(options.axis); + var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); + + if (items.length > 0) { + items = chart.getDatasetMeta(items[0]._datasetIndex).data; + } + + return items; + }, + + /** + * @function Chart.Interaction.modes.x-axis + * @deprecated since version 2.4.0. Use index mode and intersect == true + * @todo remove at version 3 + * @private + */ + 'x-axis': function(chart, e) { + return indexMode(chart, e, {intersect: false}); + }, + + /** + * Point mode returns all elements that hit test based on the event position + * of the event + * @function Chart.Interaction.modes.intersect + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + point: function(chart, e) { + var position = getRelativePosition(e, chart); + return getIntersectItems(chart, position); + }, + + /** + * nearest mode returns the element closest to the point + * @function Chart.Interaction.modes.intersect + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + nearest: function(chart, e, options) { + var position = getRelativePosition(e, chart); + options.axis = options.axis || 'xy'; + var distanceMetric = getDistanceMetricForAxis(options.axis); + var nearestItems = getNearestItems(chart, position, options.intersect, distanceMetric); + + // We have multiple items at the same distance from the event. Now sort by smallest + if (nearestItems.length > 1) { + nearestItems.sort(function(a, b) { + var sizeA = a.getArea(); + var sizeB = b.getArea(); + var ret = sizeA - sizeB; + + if (ret === 0) { + // if equal sort by dataset index + ret = a._datasetIndex - b._datasetIndex; + } + + return ret; + }); + } + + // Return only 1 item + return nearestItems.slice(0, 1); + }, + + /** + * x mode returns the elements that hit-test at the current x coordinate + * @function Chart.Interaction.modes.x + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + x: function(chart, e, options) { + var position = getRelativePosition(e, chart); + var items = []; + var intersectsItem = false; + + parseVisibleItems(chart, function(element) { + if (element.inXRange(position.x)) { + items.push(element); + } + + if (element.inRange(position.x, position.y)) { + intersectsItem = true; + } + }); + + // If we want to trigger on an intersect and we don't have any items + // that intersect the position, return nothing + if (options.intersect && !intersectsItem) { + items = []; + } + return items; + }, + + /** + * y mode returns the elements that hit-test at the current y coordinate + * @function Chart.Interaction.modes.y + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + y: function(chart, e, options) { + var position = getRelativePosition(e, chart); + var items = []; + var intersectsItem = false; + + parseVisibleItems(chart, function(element) { + if (element.inYRange(position.y)) { + items.push(element); + } + + if (element.inRange(position.x, position.y)) { + intersectsItem = true; + } + }); + + // If we want to trigger on an intersect and we don't have any items + // that intersect the position, return nothing + if (options.intersect && !intersectsItem) { + items = []; + } + return items; + } + } +}; + +},{"45":45}],29:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); + +defaults._set('global', { + responsive: true, + responsiveAnimationDuration: 0, + maintainAspectRatio: true, + events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'], + hover: { + onHover: null, + mode: 'nearest', + intersect: true, + animationDuration: 400 + }, + onClick: null, + defaultColor: 'rgba(0,0,0,0.1)', + defaultFontColor: '#666', + defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + defaultFontSize: 12, + defaultFontStyle: 'normal', + showLines: true, + + // Element defaults defined in element extensions + elements: {}, + + // Layout options such as padding + layout: { + padding: { + top: 0, + right: 0, + bottom: 0, + left: 0 + } + } +}); + +module.exports = function() { + + // Occupy the global variable of Chart, and create a simple base class + var Chart = function(item, config) { + this.construct(item, config); + return this; + }; + + Chart.Chart = Chart; + + return Chart; +}; + +},{"25":25}],30:[function(require,module,exports){ +'use strict'; + +var helpers = require(45); + +module.exports = function(Chart) { + + function filterByPosition(array, position) { + return helpers.where(array, function(v) { + return v.position === position; + }); + } + + function sortByWeight(array, reverse) { + array.forEach(function(v, i) { + v._tmpIndex_ = i; + return v; + }); + array.sort(function(a, b) { + var v0 = reverse ? b : a; + var v1 = reverse ? a : b; + return v0.weight === v1.weight ? + v0._tmpIndex_ - v1._tmpIndex_ : + v0.weight - v1.weight; + }); + array.forEach(function(v) { + delete v._tmpIndex_; + }); + } + + /** + * @interface ILayoutItem + * @prop {String} position - The position of the item in the chart layout. Possible values are + * 'left', 'top', 'right', 'bottom', and 'chartArea' + * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area + * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down + * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom) + * @prop {Function} update - Takes two parameters: width and height. Returns size of item + * @prop {Function} getPadding - Returns an object with padding on the edges + * @prop {Number} width - Width of item. Must be valid after update() + * @prop {Number} height - Height of item. Must be valid after update() + * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update + * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update + * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update + * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update + */ + + // The layout service is very self explanatory. It's responsible for the layout within a chart. + // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need + // It is this service's responsibility of carrying out that layout. + Chart.layoutService = { + defaults: {}, + + /** + * Register a box to a chart. + * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title. + * @param {Chart} chart - the chart to use + * @param {ILayoutItem} item - the item to add to be layed out + */ + addBox: function(chart, item) { + if (!chart.boxes) { + chart.boxes = []; + } + + // initialize item with default values + item.fullWidth = item.fullWidth || false; + item.position = item.position || 'top'; + item.weight = item.weight || 0; + + chart.boxes.push(item); + }, + + /** + * Remove a layoutItem from a chart + * @param {Chart} chart - the chart to remove the box from + * @param {Object} layoutItem - the item to remove from the layout + */ + removeBox: function(chart, layoutItem) { + var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; + if (index !== -1) { + chart.boxes.splice(index, 1); + } + }, + + /** + * Sets (or updates) options on the given `item`. + * @param {Chart} chart - the chart in which the item lives (or will be added to) + * @param {Object} item - the item to configure with the given options + * @param {Object} options - the new item options. + */ + configure: function(chart, item, options) { + var props = ['fullWidth', 'position', 'weight']; + var ilen = props.length; + var i = 0; + var prop; + + for (; i < ilen; ++i) { + prop = props[i]; + if (options.hasOwnProperty(prop)) { + item[prop] = options[prop]; + } + } + }, + + /** + * Fits boxes of the given chart into the given size by having each box measure itself + * then running a fitting algorithm + * @param {Chart} chart - the chart + * @param {Number} width - the width to fit into + * @param {Number} height - the height to fit into + */ + update: function(chart, width, height) { + if (!chart) { + return; + } + + var layoutOptions = chart.options.layout || {}; + var padding = helpers.options.toPadding(layoutOptions.padding); + var leftPadding = padding.left; + var rightPadding = padding.right; + var topPadding = padding.top; + var bottomPadding = padding.bottom; + + var leftBoxes = filterByPosition(chart.boxes, 'left'); + var rightBoxes = filterByPosition(chart.boxes, 'right'); + var topBoxes = filterByPosition(chart.boxes, 'top'); + var bottomBoxes = filterByPosition(chart.boxes, 'bottom'); + var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea'); + + // Sort boxes by weight. A higher weight is further away from the chart area + sortByWeight(leftBoxes, true); + sortByWeight(rightBoxes, false); + sortByWeight(topBoxes, true); + sortByWeight(bottomBoxes, false); + + // Essentially we now have any number of boxes on each of the 4 sides. + // Our canvas looks like the following. + // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and + // B1 is the bottom axis + // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays + // These locations are single-box locations only, when trying to register a chartArea location that is already taken, + // an error will be thrown. + // + // |----------------------------------------------------| + // | T1 (Full Width) | + // |----------------------------------------------------| + // | | | T2 | | + // | |----|-------------------------------------|----| + // | | | C1 | | C2 | | + // | | |----| |----| | + // | | | | | + // | L1 | L2 | ChartArea (C0) | R1 | + // | | | | | + // | | |----| |----| | + // | | | C3 | | C4 | | + // | |----|-------------------------------------|----| + // | | | B1 | | + // |----------------------------------------------------| + // | B2 (Full Width) | + // |----------------------------------------------------| + // + // What we do to find the best sizing, we do the following + // 1. Determine the minimum size of the chart area. + // 2. Split the remaining width equally between each vertical axis + // 3. Split the remaining height equally between each horizontal axis + // 4. Give each layout the maximum size it can be. The layout will return it's minimum size + // 5. Adjust the sizes of each axis based on it's minimum reported size. + // 6. Refit each axis + // 7. Position each axis in the final location + // 8. Tell the chart the final location of the chart area + // 9. Tell any axes that overlay the chart area the positions of the chart area + + // Step 1 + var chartWidth = width - leftPadding - rightPadding; + var chartHeight = height - topPadding - bottomPadding; + var chartAreaWidth = chartWidth / 2; // min 50% + var chartAreaHeight = chartHeight / 2; // min 50% + + // Step 2 + var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length); + + // Step 3 + var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length); + + // Step 4 + var maxChartAreaWidth = chartWidth; + var maxChartAreaHeight = chartHeight; + var minBoxSizes = []; + + function getMinimumBoxSize(box) { + var minSize; + var isHorizontal = box.isHorizontal(); + + if (isHorizontal) { + minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight); + maxChartAreaHeight -= minSize.height; + } else { + minSize = box.update(verticalBoxWidth, chartAreaHeight); + maxChartAreaWidth -= minSize.width; + } + + minBoxSizes.push({ + horizontal: isHorizontal, + minSize: minSize, + box: box, + }); + } + + helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize); + + // If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478) + var maxHorizontalLeftPadding = 0; + var maxHorizontalRightPadding = 0; + var maxVerticalTopPadding = 0; + var maxVerticalBottomPadding = 0; + + helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) { + if (horizontalBox.getPadding) { + var boxPadding = horizontalBox.getPadding(); + maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left); + maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right); + } + }); + + helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) { + if (verticalBox.getPadding) { + var boxPadding = verticalBox.getPadding(); + maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top); + maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom); + } + }); + + // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could + // be if the axes are drawn at their minimum sizes. + // Steps 5 & 6 + var totalLeftBoxesWidth = leftPadding; + var totalRightBoxesWidth = rightPadding; + var totalTopBoxesHeight = topPadding; + var totalBottomBoxesHeight = bottomPadding; + + // Function to fit a box + function fitBox(box) { + var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) { + return minBox.box === box; + }); + + if (minBoxSize) { + if (box.isHorizontal()) { + var scaleMargin = { + left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding), + right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding), + top: 0, + bottom: 0 + }; + + // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends + // on the margin. Sometimes they need to increase in size slightly + box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin); + } else { + box.update(minBoxSize.minSize.width, maxChartAreaHeight); + } + } + } + + // Update, and calculate the left and right margins for the horizontal boxes + helpers.each(leftBoxes.concat(rightBoxes), fitBox); + + helpers.each(leftBoxes, function(box) { + totalLeftBoxesWidth += box.width; + }); + + helpers.each(rightBoxes, function(box) { + totalRightBoxesWidth += box.width; + }); + + // Set the Left and Right margins for the horizontal boxes + helpers.each(topBoxes.concat(bottomBoxes), fitBox); + + // Figure out how much margin is on the top and bottom of the vertical boxes + helpers.each(topBoxes, function(box) { + totalTopBoxesHeight += box.height; + }); + + helpers.each(bottomBoxes, function(box) { + totalBottomBoxesHeight += box.height; + }); + + function finalFitVerticalBox(box) { + var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) { + return minSize.box === box; + }); + + var scaleMargin = { + left: 0, + right: 0, + top: totalTopBoxesHeight, + bottom: totalBottomBoxesHeight + }; + + if (minBoxSize) { + box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin); + } + } + + // Let the left layout know the final margin + helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox); + + // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance) + totalLeftBoxesWidth = leftPadding; + totalRightBoxesWidth = rightPadding; + totalTopBoxesHeight = topPadding; + totalBottomBoxesHeight = bottomPadding; + + helpers.each(leftBoxes, function(box) { + totalLeftBoxesWidth += box.width; + }); + + helpers.each(rightBoxes, function(box) { + totalRightBoxesWidth += box.width; + }); + + helpers.each(topBoxes, function(box) { + totalTopBoxesHeight += box.height; + }); + helpers.each(bottomBoxes, function(box) { + totalBottomBoxesHeight += box.height; + }); + + // We may be adding some padding to account for rotated x axis labels + var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0); + totalLeftBoxesWidth += leftPaddingAddition; + totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0); + + var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0); + totalTopBoxesHeight += topPaddingAddition; + totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0); + + // Figure out if our chart area changed. This would occur if the dataset layout label rotation + // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do + // without calling `fit` again + var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight; + var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth; + + if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) { + helpers.each(leftBoxes, function(box) { + box.height = newMaxChartAreaHeight; + }); + + helpers.each(rightBoxes, function(box) { + box.height = newMaxChartAreaHeight; + }); + + helpers.each(topBoxes, function(box) { + if (!box.fullWidth) { + box.width = newMaxChartAreaWidth; + } + }); + + helpers.each(bottomBoxes, function(box) { + if (!box.fullWidth) { + box.width = newMaxChartAreaWidth; + } + }); + + maxChartAreaHeight = newMaxChartAreaHeight; + maxChartAreaWidth = newMaxChartAreaWidth; + } + + // Step 7 - Position the boxes + var left = leftPadding + leftPaddingAddition; + var top = topPadding + topPaddingAddition; + + function placeBox(box) { + if (box.isHorizontal()) { + box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth; + box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth; + box.top = top; + box.bottom = top + box.height; + + // Move to next point + top = box.bottom; + + } else { + + box.left = left; + box.right = left + box.width; + box.top = totalTopBoxesHeight; + box.bottom = totalTopBoxesHeight + maxChartAreaHeight; + + // Move to next point + left = box.right; + } + } + + helpers.each(leftBoxes.concat(topBoxes), placeBox); + + // Account for chart width and height + left += maxChartAreaWidth; + top += maxChartAreaHeight; + + helpers.each(rightBoxes, placeBox); + helpers.each(bottomBoxes, placeBox); + + // Step 8 + chart.chartArea = { + left: totalLeftBoxesWidth, + top: totalTopBoxesHeight, + right: totalLeftBoxesWidth + maxChartAreaWidth, + bottom: totalTopBoxesHeight + maxChartAreaHeight + }; + + // Step 9 + helpers.each(chartAreaBoxes, function(box) { + box.left = chart.chartArea.left; + box.top = chart.chartArea.top; + box.right = chart.chartArea.right; + box.bottom = chart.chartArea.bottom; + + box.update(maxChartAreaWidth, maxChartAreaHeight); + }); + } + }; +}; + +},{"45":45}],31:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); + +defaults._set('global', { + plugins: {} +}); + +module.exports = function(Chart) { + + /** + * The plugin service singleton + * @namespace Chart.plugins + * @since 2.1.0 + */ + Chart.plugins = { + /** + * Globally registered plugins. + * @private + */ + _plugins: [], + + /** + * This identifier is used to invalidate the descriptors cache attached to each chart + * when a global plugin is registered or unregistered. In this case, the cache ID is + * incremented and descriptors are regenerated during following API calls. + * @private + */ + _cacheId: 0, + + /** + * Registers the given plugin(s) if not already registered. + * @param {Array|Object} plugins plugin instance(s). + */ + register: function(plugins) { + var p = this._plugins; + ([]).concat(plugins).forEach(function(plugin) { + if (p.indexOf(plugin) === -1) { + p.push(plugin); + } + }); + + this._cacheId++; + }, + + /** + * Unregisters the given plugin(s) only if registered. + * @param {Array|Object} plugins plugin instance(s). + */ + unregister: function(plugins) { + var p = this._plugins; + ([]).concat(plugins).forEach(function(plugin) { + var idx = p.indexOf(plugin); + if (idx !== -1) { + p.splice(idx, 1); + } + }); + + this._cacheId++; + }, + + /** + * Remove all registered plugins. + * @since 2.1.5 + */ + clear: function() { + this._plugins = []; + this._cacheId++; + }, + + /** + * Returns the number of registered plugins? + * @returns {Number} + * @since 2.1.5 + */ + count: function() { + return this._plugins.length; + }, + + /** + * Returns all registered plugin instances. + * @returns {Array} array of plugin objects. + * @since 2.1.5 + */ + getAll: function() { + return this._plugins; + }, + + /** + * Calls enabled plugins for `chart` on the specified hook and with the given args. + * This method immediately returns as soon as a plugin explicitly returns false. The + * returned value can be used, for instance, to interrupt the current action. + * @param {Object} chart - The chart instance for which plugins should be called. + * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate'). + * @param {Array} [args] - Extra arguments to apply to the hook call. + * @returns {Boolean} false if any of the plugins return false, else returns true. + */ + notify: function(chart, hook, args) { + var descriptors = this.descriptors(chart); + var ilen = descriptors.length; + var i, descriptor, plugin, params, method; + + for (i = 0; i < ilen; ++i) { + descriptor = descriptors[i]; + plugin = descriptor.plugin; + method = plugin[hook]; + if (typeof method === 'function') { + params = [chart].concat(args || []); + params.push(descriptor.options); + if (method.apply(plugin, params) === false) { + return false; + } + } + } + + return true; + }, + + /** + * Returns descriptors of enabled plugins for the given chart. + * @returns {Array} [{ plugin, options }] + * @private + */ + descriptors: function(chart) { + var cache = chart._plugins || (chart._plugins = {}); + if (cache.id === this._cacheId) { + return cache.descriptors; + } + + var plugins = []; + var descriptors = []; + var config = (chart && chart.config) || {}; + var options = (config.options && config.options.plugins) || {}; + + this._plugins.concat(config.plugins || []).forEach(function(plugin) { + var idx = plugins.indexOf(plugin); + if (idx !== -1) { + return; + } + + var id = plugin.id; + var opts = options[id]; + if (opts === false) { + return; + } + + if (opts === true) { + opts = helpers.clone(defaults.global.plugins[id]); + } + + plugins.push(plugin); + descriptors.push({ + plugin: plugin, + options: opts || {} + }); + }); + + cache.descriptors = descriptors; + cache.id = this._cacheId; + return descriptors; + } + }; + + /** + * Plugin extension hooks. + * @interface IPlugin + * @since 2.1.0 + */ + /** + * @method IPlugin#beforeInit + * @desc Called before initializing `chart`. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#afterInit + * @desc Called after `chart` has been initialized and before the first update. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#beforeUpdate + * @desc Called before updating `chart`. If any plugin returns `false`, the update + * is cancelled (and thus subsequent render(s)) until another `update` is triggered. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + * @returns {Boolean} `false` to cancel the chart update. + */ + /** + * @method IPlugin#afterUpdate + * @desc Called after `chart` has been updated and before rendering. Note that this + * hook will not be called if the chart update has been previously cancelled. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#beforeDatasetsUpdate + * @desc Called before updating the `chart` datasets. If any plugin returns `false`, + * the datasets update is cancelled until another `update` is triggered. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + * @returns {Boolean} false to cancel the datasets update. + * @since version 2.1.5 + */ + /** + * @method IPlugin#afterDatasetsUpdate + * @desc Called after the `chart` datasets have been updated. Note that this hook + * will not be called if the datasets update has been previously cancelled. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + * @since version 2.1.5 + */ + /** + * @method IPlugin#beforeDatasetUpdate + * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin + * returns `false`, the datasets update is cancelled until another `update` is triggered. + * @param {Chart} chart - The chart instance. + * @param {Object} args - The call arguments. + * @param {Number} args.index - The dataset index. + * @param {Object} args.meta - The dataset metadata. + * @param {Object} options - The plugin options. + * @returns {Boolean} `false` to cancel the chart datasets drawing. + */ + /** + * @method IPlugin#afterDatasetUpdate + * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note + * that this hook will not be called if the datasets update has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {Object} args - The call arguments. + * @param {Number} args.index - The dataset index. + * @param {Object} args.meta - The dataset metadata. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#beforeLayout + * @desc Called before laying out `chart`. If any plugin returns `false`, + * the layout update is cancelled until another `update` is triggered. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + * @returns {Boolean} `false` to cancel the chart layout. + */ + /** + * @method IPlugin#afterLayout + * @desc Called after the `chart` has been layed out. Note that this hook will not + * be called if the layout update has been previously cancelled. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#beforeRender + * @desc Called before rendering `chart`. If any plugin returns `false`, + * the rendering is cancelled until another `render` is triggered. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + * @returns {Boolean} `false` to cancel the chart rendering. + */ + /** + * @method IPlugin#afterRender + * @desc Called after the `chart` has been fully rendered (and animation completed). Note + * that this hook will not be called if the rendering has been previously cancelled. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#beforeDraw + * @desc Called before drawing `chart` at every animation frame specified by the given + * easing value. If any plugin returns `false`, the frame drawing is cancelled until + * another `render` is triggered. + * @param {Chart.Controller} chart - The chart instance. + * @param {Number} easingValue - The current animation value, between 0.0 and 1.0. + * @param {Object} options - The plugin options. + * @returns {Boolean} `false` to cancel the chart drawing. + */ + /** + * @method IPlugin#afterDraw + * @desc Called after the `chart` has been drawn for the specific easing value. Note + * that this hook will not be called if the drawing has been previously cancelled. + * @param {Chart.Controller} chart - The chart instance. + * @param {Number} easingValue - The current animation value, between 0.0 and 1.0. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#beforeDatasetsDraw + * @desc Called before drawing the `chart` datasets. If any plugin returns `false`, + * the datasets drawing is cancelled until another `render` is triggered. + * @param {Chart.Controller} chart - The chart instance. + * @param {Number} easingValue - The current animation value, between 0.0 and 1.0. + * @param {Object} options - The plugin options. + * @returns {Boolean} `false` to cancel the chart datasets drawing. + */ + /** + * @method IPlugin#afterDatasetsDraw + * @desc Called after the `chart` datasets have been drawn. Note that this hook + * will not be called if the datasets drawing has been previously cancelled. + * @param {Chart.Controller} chart - The chart instance. + * @param {Number} easingValue - The current animation value, between 0.0 and 1.0. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#beforeDatasetDraw + * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets + * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing + * is cancelled until another `render` is triggered. + * @param {Chart} chart - The chart instance. + * @param {Object} args - The call arguments. + * @param {Number} args.index - The dataset index. + * @param {Object} args.meta - The dataset metadata. + * @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 datasets drawing. + */ + /** + * @method IPlugin#afterDatasetDraw + * @desc Called after the `chart` datasets at the given `args.index` have been drawn + * (datasets are drawn in the reverse order). Note that this hook will not be called + * if the datasets drawing has been previously cancelled. + * @param {Chart} chart - The chart instance. + * @param {Object} args - The call arguments. + * @param {Number} args.index - The dataset index. + * @param {Object} args.meta - The dataset metadata. + * @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`, + * the event will be discarded. + * @param {Chart.Controller} chart - The chart instance. + * @param {IEvent} event - The event object. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#afterEvent + * @desc Called after the `event` has been consumed. Note that this hook + * will not be called if the `event` has been previously discarded. + * @param {Chart.Controller} chart - The chart instance. + * @param {IEvent} event - The event object. + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#resize + * @desc Called after the chart as been resized. + * @param {Chart.Controller} chart - The chart instance. + * @param {Number} size - The new canvas display size (eq. canvas.style width & height). + * @param {Object} options - The plugin options. + */ + /** + * @method IPlugin#destroy + * @desc Called after the chart as been destroyed. + * @param {Chart.Controller} chart - The chart instance. + * @param {Object} options - The plugin options. + */ + + /** + * Provided for backward compatibility, use Chart.plugins instead + * @namespace Chart.pluginService + * @deprecated since version 2.1.5 + * @todo remove at version 3 + * @private + */ + Chart.pluginService = Chart.plugins; + + /** + * Provided for backward compatibility, inheriting from Chart.PlugingBase has no + * effect, instead simply create/register plugins via plain JavaScript objects. + * @interface Chart.PluginBase + * @deprecated since version 2.5.0 + * @todo remove at version 3 + * @private + */ + Chart.PluginBase = Element.extend({}); +}; + +},{"25":25,"26":26,"45":45}],32:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); +var Ticks = require(34); + +defaults._set('scale', { + display: true, + position: 'left', + offset: false, + + // grid line settings + gridLines: { + display: true, + color: 'rgba(0, 0, 0, 0.1)', + lineWidth: 1, + drawBorder: true, + drawOnChartArea: true, + drawTicks: true, + tickMarkLength: 10, + zeroLineWidth: 1, + zeroLineColor: 'rgba(0,0,0,0.25)', + zeroLineBorderDash: [], + zeroLineBorderDashOffset: 0.0, + offsetGridLines: false, + borderDash: [], + borderDashOffset: 0.0 + }, + + // scale label + scaleLabel: { + // display property + display: false, + + // actual label + labelString: '', + + // line height + lineHeight: 1.2, + + // top/bottom padding + padding: { + top: 4, + bottom: 4 + } + }, + + // label settings + ticks: { + beginAtZero: false, + minRotation: 0, + maxRotation: 50, + mirror: false, + padding: 0, + reverse: false, + display: true, + autoSkip: true, + autoSkipPadding: 0, + labelOffset: 0, + // We pass through arrays to be rendered as multiline labels, we convert Others to strings here. + callback: Ticks.formatters.values, + minor: {}, + major: {} + } +}); + +function labelsFromTicks(ticks) { + var labels = []; + var i, ilen; + + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + labels.push(ticks[i].label); + } + + return labels; +} + +function getLineValue(scale, index, offsetGridLines) { + var lineValue = scale.getPixelForTick(index); + + if (offsetGridLines) { + if (index === 0) { + lineValue -= (scale.getPixelForTick(1) - lineValue) / 2; + } else { + lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2; + } + } + return lineValue; +} + +module.exports = function(Chart) { + + function computeTextSize(context, tick, font) { + return helpers.isArray(tick) ? + helpers.longestText(context, font, tick) : + context.measureText(tick).width; + } + + function parseFontOptions(options) { + var valueOrDefault = helpers.valueOrDefault; + var globalDefaults = defaults.global; + var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize); + var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle); + var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily); + + return { + size: size, + style: style, + family: family, + font: helpers.fontString(size, style, family) + }; + } + + function parseLineHeight(options) { + return helpers.options.toLineHeight( + helpers.valueOrDefault(options.lineHeight, 1.2), + helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize)); + } + + Chart.Scale = Element.extend({ + /** + * Get the padding needed for the scale + * @method getPadding + * @private + * @returns {Padding} the necessary padding + */ + getPadding: function() { + var me = this; + return { + left: me.paddingLeft || 0, + top: me.paddingTop || 0, + right: me.paddingRight || 0, + bottom: me.paddingBottom || 0 + }; + }, + + /** + * Returns the scale tick objects ({label, major}) + * @since 2.7 + */ + getTicks: function() { + return this._ticks; + }, + + // These methods are ordered by lifecyle. Utilities then follow. + // Any function defined here is inherited by all scale types. + // Any function can be extended by the scale type + + mergeTicksOptions: function() { + var ticks = this.options.ticks; + if (ticks.minor === false) { + ticks.minor = { + display: false + }; + } + if (ticks.major === false) { + ticks.major = { + display: false + }; + } + for (var key in ticks) { + if (key !== 'major' && key !== 'minor') { + if (typeof ticks.minor[key] === 'undefined') { + ticks.minor[key] = ticks[key]; + } + if (typeof ticks.major[key] === 'undefined') { + ticks.major[key] = ticks[key]; + } + } + } + }, + beforeUpdate: function() { + helpers.callback(this.options.beforeUpdate, [this]); + }, + update: function(maxWidth, maxHeight, margins) { + var me = this; + var i, ilen, labels, label, ticks, tick; + + // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) + me.beforeUpdate(); + + // Absorb the master measurements + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me.margins = helpers.extend({ + left: 0, + right: 0, + top: 0, + bottom: 0 + }, margins); + me.longestTextCache = me.longestTextCache || {}; + + // Dimensions + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + + // Data min/max + me.beforeDataLimits(); + me.determineDataLimits(); + me.afterDataLimits(); + + // Ticks - `this.ticks` is now DEPRECATED! + // Internal ticks are now stored as objects in the PRIVATE `this._ticks` member + // and must not be accessed directly from outside this class. `this.ticks` being + // around for long time and not marked as private, we can't change its structure + // without unexpected breaking changes. If you need to access the scale ticks, + // use scale.getTicks() instead. + + me.beforeBuildTicks(); + + // New implementations should return an array of objects but for BACKWARD COMPAT, + // we still support no return (`this.ticks` internally set by calling this method). + ticks = me.buildTicks() || []; + + me.afterBuildTicks(); + + me.beforeTickToLabelConversion(); + + // New implementations should return the formatted tick labels but for BACKWARD + // COMPAT, we still support no return (`this.ticks` internally changed by calling + // this method and supposed to contain only string values). + labels = me.convertTicksToLabels(ticks) || me.ticks; + + me.afterTickToLabelConversion(); + + me.ticks = labels; // BACKWARD COMPATIBILITY + + // IMPORTANT: from this point, we consider that `this.ticks` will NEVER change! + + // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`) + for (i = 0, ilen = labels.length; i < ilen; ++i) { + label = labels[i]; + tick = ticks[i]; + if (!tick) { + ticks.push(tick = { + label: label, + major: false + }); + } else { + tick.label = label; + } + } + + me._ticks = ticks; + + // Tick Rotation + me.beforeCalculateTickRotation(); + me.calculateTickRotation(); + me.afterCalculateTickRotation(); + // Fit + me.beforeFit(); + me.fit(); + me.afterFit(); + // + me.afterUpdate(); + + return me.minSize; + + }, + afterUpdate: function() { + helpers.callback(this.options.afterUpdate, [this]); + }, + + // + + beforeSetDimensions: function() { + helpers.callback(this.options.beforeSetDimensions, [this]); + }, + setDimensions: function() { + var me = this; + // Set the unconstrained dimension before label rotation + if (me.isHorizontal()) { + // Reset position before calculating rotation + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + + // Reset position before calculating rotation + me.top = 0; + me.bottom = me.height; + } + + // Reset padding + me.paddingLeft = 0; + me.paddingTop = 0; + me.paddingRight = 0; + me.paddingBottom = 0; + }, + afterSetDimensions: function() { + helpers.callback(this.options.afterSetDimensions, [this]); + }, + + // Data limits + beforeDataLimits: function() { + helpers.callback(this.options.beforeDataLimits, [this]); + }, + determineDataLimits: helpers.noop, + afterDataLimits: function() { + helpers.callback(this.options.afterDataLimits, [this]); + }, + + // + beforeBuildTicks: function() { + helpers.callback(this.options.beforeBuildTicks, [this]); + }, + buildTicks: helpers.noop, + afterBuildTicks: function() { + helpers.callback(this.options.afterBuildTicks, [this]); + }, + + beforeTickToLabelConversion: function() { + helpers.callback(this.options.beforeTickToLabelConversion, [this]); + }, + convertTicksToLabels: function() { + var me = this; + // Convert ticks to strings + var tickOpts = me.options.ticks; + me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this); + }, + afterTickToLabelConversion: function() { + helpers.callback(this.options.afterTickToLabelConversion, [this]); + }, + + // + + beforeCalculateTickRotation: function() { + helpers.callback(this.options.beforeCalculateTickRotation, [this]); + }, + calculateTickRotation: function() { + var me = this; + var context = me.ctx; + var tickOpts = me.options.ticks; + var labels = labelsFromTicks(me._ticks); + + // Get the width of each grid by calculating the difference + // between x offsets between 0 and 1. + var tickFont = parseFontOptions(tickOpts); + context.font = tickFont.font; + + var labelRotation = tickOpts.minRotation || 0; + + if (labels.length && me.options.display && me.isHorizontal()) { + var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache); + var labelWidth = originalLabelWidth; + var cosRotation, sinRotation; + + // Allow 3 pixels x2 padding either side for label readability + var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6; + + // Max label rotation can be set or default to 90 - also act as a loop counter + while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) { + var angleRadians = helpers.toRadians(labelRotation); + cosRotation = Math.cos(angleRadians); + sinRotation = Math.sin(angleRadians); + + if (sinRotation * originalLabelWidth > me.maxHeight) { + // go back one step + labelRotation--; + break; + } + + labelRotation++; + labelWidth = cosRotation * originalLabelWidth; + } + } + + me.labelRotation = labelRotation; + }, + afterCalculateTickRotation: function() { + helpers.callback(this.options.afterCalculateTickRotation, [this]); + }, + + // + + beforeFit: function() { + helpers.callback(this.options.beforeFit, [this]); + }, + fit: function() { + var me = this; + // Reset + var minSize = me.minSize = { + width: 0, + height: 0 + }; + + var labels = labelsFromTicks(me._ticks); + + var opts = me.options; + var tickOpts = opts.ticks; + var scaleLabelOpts = opts.scaleLabel; + var gridLineOpts = opts.gridLines; + var display = opts.display; + var isHorizontal = me.isHorizontal(); + + var tickFont = parseFontOptions(tickOpts); + var tickMarkLength = opts.gridLines.tickMarkLength; + + // Width + if (isHorizontal) { + // subtract the margins to line up with the chartArea if we are a full width scale + minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth; + } else { + minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0; + } + + // height + if (isHorizontal) { + minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0; + } else { + minSize.height = me.maxHeight; // fill all the height + } + + // Are we showing a title for the scale? + if (scaleLabelOpts.display && display) { + var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts); + var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding); + var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height; + + if (isHorizontal) { + minSize.height += deltaHeight; + } else { + minSize.width += deltaHeight; + } + } + + // Don't bother fitting the ticks if we are not showing them + if (tickOpts.display && display) { + var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, labels, me.longestTextCache); + var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels); + var lineSpace = tickFont.size * 0.5; + var tickPadding = me.options.ticks.padding; + + if (isHorizontal) { + // A horizontal axis is more constrained by the height. + me.longestLabelWidth = largestTextWidth; + + var angleRadians = helpers.toRadians(me.labelRotation); + var cosRotation = Math.cos(angleRadians); + var sinRotation = Math.sin(angleRadians); + + // TODO - improve this calculation + var labelHeight = (sinRotation * largestTextWidth) + + (tickFont.size * tallestLabelHeightInLines) + + (lineSpace * (tallestLabelHeightInLines - 1)) + + lineSpace; // padding + + minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding); + + me.ctx.font = tickFont.font; + var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font); + var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font); + + // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned + // which means that the right padding is dominated by the font height + if (me.labelRotation !== 0) { + me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges + me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3; + } else { + me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges + me.paddingRight = lastLabelWidth / 2 + 3; + } + } else { + // A vertical axis is more constrained by the width. Labels are the + // dominant factor here, so get that length first and account for padding + if (tickOpts.mirror) { + largestTextWidth = 0; + } else { + // use lineSpace for consistency with horizontal axis + // tickPadding is not implemented for horizontal + largestTextWidth += tickPadding + lineSpace; + } + + minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth); + + me.paddingTop = tickFont.size / 2; + me.paddingBottom = tickFont.size / 2; + } + } + + me.handleMargins(); + + me.width = minSize.width; + me.height = minSize.height; + }, + + /** + * Handle margins and padding interactions + * @private + */ + handleMargins: function() { + var me = this; + if (me.margins) { + me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0); + me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0); + me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0); + me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0); + } + }, + + afterFit: function() { + helpers.callback(this.options.afterFit, [this]); + }, + + // Shared Methods + isHorizontal: function() { + return this.options.position === 'top' || this.options.position === 'bottom'; + }, + isFullWidth: function() { + return (this.options.fullWidth); + }, + + // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not + getRightValue: function(rawValue) { + // Null and undefined values first + if (helpers.isNullOrUndef(rawValue)) { + return NaN; + } + // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values + if (typeof rawValue === 'number' && !isFinite(rawValue)) { + return NaN; + } + // If it is in fact an object, dive in one more level + if (rawValue) { + if (this.isHorizontal()) { + if (rawValue.x !== undefined) { + return this.getRightValue(rawValue.x); + } + } else if (rawValue.y !== undefined) { + return this.getRightValue(rawValue.y); + } + } + + // Value is good, return it + return rawValue; + }, + + /** + * Used to get the value to display in the tooltip for the data at the given index + * @param index + * @param datasetIndex + */ + getLabelForIndex: helpers.noop, + + /** + * 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 + * The coordinate (0, 0) is at the upper-left corner of the canvas + * @param pixel + */ + getValueForPixel: helpers.noop, + + /** + * 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; + if (me.isHorizontal()) { + var innerWidth = me.width - (me.paddingLeft + me.paddingRight); + var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1); + var pixel = (tickWidth * index) + me.paddingLeft; + + if (offset) { + pixel += tickWidth / 2; + } + + var finalVal = me.left + Math.round(pixel); + finalVal += me.isFullWidth() ? me.margins.left : 0; + return finalVal; + } + var innerHeight = me.height - (me.paddingTop + me.paddingBottom); + return me.top + (index * (innerHeight / (me._ticks.length - 1))); + }, + + /** + * 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()) { + var innerWidth = me.width - (me.paddingLeft + me.paddingRight); + var valueOffset = (innerWidth * decimal) + me.paddingLeft; + + var finalVal = me.left + Math.round(valueOffset); + finalVal += me.isFullWidth() ? me.margins.left : 0; + return finalVal; + } + 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()); + }, + + getBaseValue: function() { + var me = this; + var min = me.min; + var max = me.max; + + return me.beginAtZero ? 0 : + min < 0 && max < 0 ? max : + min > 0 && max > 0 ? min : + 0; + }, + + /** + * Returns a subset of ticks to be plotted to avoid overlapping labels. + * @private + */ + _autoSkip: function(ticks) { + var skipRatio; + var me = this; + var isHorizontal = me.isHorizontal(); + var optionTicks = me.options.ticks.minor; + var tickCount = ticks.length; + var labelRotationRadians = helpers.toRadians(me.labelRotation); + var cosRotation = Math.cos(labelRotationRadians); + var longestRotatedLabel = me.longestLabelWidth * cosRotation; + var result = []; + var i, tick, shouldSkip; + + // figure out the maximum number of gridlines to show + var maxTicks; + if (optionTicks.maxTicksLimit) { + maxTicks = optionTicks.maxTicksLimit; + } + + if (isHorizontal) { + skipRatio = false; + + if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) { + skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight))); + } + + // if they defined a max number of optionTicks, + // increase skipRatio until that number is met + if (maxTicks && tickCount > maxTicks) { + skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks)); + } + } + + for (i = 0; i < tickCount; i++) { + tick = ticks[i]; + + // 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) { + // leave tick in place but make sure it's not displayed (#4635) + delete tick.label; + } + result.push(tick); + } + return result; + }, + + // Actually draw the scale on the canvas + // @param {rectangle} chartArea : the area of the chart to draw full grid lines on + draw: function(chartArea) { + var me = this; + var options = me.options; + if (!options.display) { + return; + } + + var context = me.ctx; + var globalDefaults = defaults.global; + var optionTicks = options.ticks.minor; + var optionMajorTicks = options.ticks.major || optionTicks; + var gridLines = options.gridLines; + var scaleLabel = options.scaleLabel; + + var isRotated = me.labelRotation !== 0; + var isHorizontal = me.isHorizontal(); + + var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks(); + var tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor); + var tickFont = parseFontOptions(optionTicks); + var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor); + var majorTickFont = parseFontOptions(optionMajorTicks); + + var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0; + + var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor); + var scaleLabelFont = parseFontOptions(scaleLabel); + var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding); + var labelRotationRadians = helpers.toRadians(me.labelRotation); + + var itemsToDraw = []; + + var xTickStart = options.position === 'right' ? me.left : me.right - tl; + var xTickEnd = options.position === 'right' ? me.left + tl : me.right; + var yTickStart = options.position === 'bottom' ? me.top : me.bottom - tl; + var yTickEnd = options.position === 'bottom' ? me.top + tl : me.bottom; + + helpers.each(ticks, function(tick, index) { + // autoskipper skipped this tick (#4635) + if (helpers.isNullOrUndef(tick.label)) { + return; + } + + var label = tick.label; + var lineWidth, lineColor, borderDash, borderDashOffset; + if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) { + // Draw the first index specially + lineWidth = gridLines.zeroLineWidth; + lineColor = gridLines.zeroLineColor; + borderDash = gridLines.zeroLineBorderDash; + borderDashOffset = gridLines.zeroLineBorderDashOffset; + } else { + lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, index); + lineColor = helpers.valueAtIndexOrDefault(gridLines.color, index); + borderDash = helpers.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash); + borderDashOffset = helpers.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset); + } + + // Common properties + var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY; + var textAlign = 'middle'; + var textBaseline = 'middle'; + var tickPadding = optionTicks.padding; + + if (isHorizontal) { + var labelYOffset = tl + tickPadding; + + if (options.position === 'bottom') { + // bottom + textBaseline = !isRotated ? 'top' : 'middle'; + textAlign = !isRotated ? 'center' : 'right'; + labelY = me.top + labelYOffset; + } else { + // top + textBaseline = !isRotated ? 'bottom' : 'middle'; + textAlign = !isRotated ? 'center' : 'left'; + labelY = me.bottom - labelYOffset; + } + + var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1); + if (xLineValue < me.left) { + lineColor = 'rgba(0,0,0,0)'; + } + xLineValue += helpers.aliasPixel(lineWidth); + + labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option) + + tx1 = tx2 = x1 = x2 = xLineValue; + ty1 = yTickStart; + ty2 = yTickEnd; + y1 = chartArea.top; + y2 = chartArea.bottom; + } else { + var isLeft = options.position === 'left'; + var labelXOffset; + + if (optionTicks.mirror) { + textAlign = isLeft ? 'left' : 'right'; + labelXOffset = tickPadding; + } else { + textAlign = isLeft ? 'right' : 'left'; + labelXOffset = tl + tickPadding; + } + + labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset; + + var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1); + if (yLineValue < me.top) { + lineColor = 'rgba(0,0,0,0)'; + } + yLineValue += helpers.aliasPixel(lineWidth); + + labelY = me.getPixelForTick(index) + optionTicks.labelOffset; + + tx1 = xTickStart; + tx2 = xTickEnd; + x1 = chartArea.left; + x2 = chartArea.right; + ty1 = ty2 = y1 = y2 = yLineValue; + } + + itemsToDraw.push({ + tx1: tx1, + ty1: ty1, + tx2: tx2, + ty2: ty2, + x1: x1, + y1: y1, + x2: x2, + y2: y2, + labelX: labelX, + labelY: labelY, + glWidth: lineWidth, + glColor: lineColor, + glBorderDash: borderDash, + glBorderDashOffset: borderDashOffset, + rotation: -1 * labelRotationRadians, + label: label, + major: tick.major, + textBaseline: textBaseline, + textAlign: textAlign + }); + }); + + // Draw all of the tick labels, tick marks, and grid lines at the correct places + helpers.each(itemsToDraw, function(itemToDraw) { + if (gridLines.display) { + context.save(); + context.lineWidth = itemToDraw.glWidth; + context.strokeStyle = itemToDraw.glColor; + if (context.setLineDash) { + context.setLineDash(itemToDraw.glBorderDash); + context.lineDashOffset = itemToDraw.glBorderDashOffset; + } + + context.beginPath(); + + if (gridLines.drawTicks) { + context.moveTo(itemToDraw.tx1, itemToDraw.ty1); + context.lineTo(itemToDraw.tx2, itemToDraw.ty2); + } + + if (gridLines.drawOnChartArea) { + context.moveTo(itemToDraw.x1, itemToDraw.y1); + context.lineTo(itemToDraw.x2, itemToDraw.y2); + } + + context.stroke(); + context.restore(); + } + + if (optionTicks.display) { + // Make sure we draw text in the correct color and font + context.save(); + context.translate(itemToDraw.labelX, itemToDraw.labelY); + context.rotate(itemToDraw.rotation); + context.font = itemToDraw.major ? majorTickFont.font : tickFont.font; + context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor; + context.textBaseline = itemToDraw.textBaseline; + context.textAlign = itemToDraw.textAlign; + + var label = itemToDraw.label; + if (helpers.isArray(label)) { + for (var i = 0, y = 0; i < label.length; ++i) { + // We just make sure the multiline element is a string here.. + context.fillText('' + label[i], 0, y); + // apply same lineSpacing as calculated @ L#320 + y += (tickFont.size * 1.5); + } + } else { + context.fillText(label, 0, 0); + } + context.restore(); + } + }); + + if (scaleLabel.display) { + // Draw the scale label + var scaleLabelX; + var scaleLabelY; + var rotation = 0; + var halfLineHeight = parseLineHeight(scaleLabel) / 2; + + if (isHorizontal) { + scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width + scaleLabelY = options.position === 'bottom' + ? me.bottom - halfLineHeight - scaleLabelPadding.bottom + : me.top + halfLineHeight + scaleLabelPadding.top; + } else { + var isLeft = options.position === 'left'; + scaleLabelX = isLeft + ? me.left + halfLineHeight + scaleLabelPadding.top + : me.right - halfLineHeight - scaleLabelPadding.top; + scaleLabelY = me.top + ((me.bottom - me.top) / 2); + rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI; + } + + context.save(); + context.translate(scaleLabelX, scaleLabelY); + context.rotate(rotation); + context.textAlign = 'center'; + context.textBaseline = 'middle'; + context.fillStyle = scaleLabelFontColor; // render in correct colour + context.font = scaleLabelFont.font; + context.fillText(scaleLabel.labelString, 0, 0); + context.restore(); + } + + if (gridLines.drawBorder) { + // Draw the line at the edge of the axis + context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0); + context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0); + var x1 = me.left; + var x2 = me.right; + var y1 = me.top; + var y2 = me.bottom; + + var aliasPixel = helpers.aliasPixel(context.lineWidth); + if (isHorizontal) { + y1 = y2 = options.position === 'top' ? me.bottom : me.top; + y1 += aliasPixel; + y2 += aliasPixel; + } else { + x1 = x2 = options.position === 'left' ? me.right : me.left; + x1 += aliasPixel; + x2 += aliasPixel; + } + + context.beginPath(); + context.moveTo(x1, y1); + context.lineTo(x2, y2); + context.stroke(); + } + } + }); +}; + +},{"25":25,"26":26,"34":34,"45":45}],33:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var helpers = require(45); + +module.exports = function(Chart) { + + Chart.scaleService = { + // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then + // use the new chart options to grab the correct scale + constructors: {}, + // Use a registration function so that we can move to an ES6 map when we no longer need to support + // old browsers + + // Scale config defaults + defaults: {}, + registerScaleType: function(type, scaleConstructor, scaleDefaults) { + this.constructors[type] = scaleConstructor; + this.defaults[type] = helpers.clone(scaleDefaults); + }, + getScaleConstructor: function(type) { + return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined; + }, + getScaleDefaults: function(type) { + // Return the scale defaults merged with the global settings so that we always use the latest ones + return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [defaults.scale, this.defaults[type]]) : {}; + }, + updateScaleDefaults: function(type, additions) { + var me = this; + if (me.defaults.hasOwnProperty(type)) { + me.defaults[type] = helpers.extend(me.defaults[type], additions); + } + }, + addScalesToLayout: function(chart) { + // Adds each scale to the chart.boxes array to be sized accordingly + helpers.each(chart.scales, function(scale) { + // Set ILayoutItem parameters for backwards compatibility + scale.fullWidth = scale.options.fullWidth; + scale.position = scale.options.position; + scale.weight = scale.options.weight; + Chart.layoutService.addBox(chart, scale); + }); + } + }; +}; + +},{"25":25,"45":45}],34:[function(require,module,exports){ +'use strict'; + +var helpers = require(45); + +/** + * Namespace to hold static tick generation functions + * @namespace Chart.Ticks + */ +module.exports = { + /** + * Namespace to hold generators for different types of ticks + * @namespace Chart.Ticks.generators + */ + generators: { + /** + * Interface for the options provided to the numeric tick generator + * @interface INumericTickGenerationOptions + */ + /** + * The maximum number of ticks to display + * @name INumericTickGenerationOptions#maxTicks + * @type Number + */ + /** + * The distance between each tick. + * @name INumericTickGenerationOptions#stepSize + * @type Number + * @optional + */ + /** + * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum + * @name INumericTickGenerationOptions#min + * @type Number + * @optional + */ + /** + * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum + * @name INumericTickGenerationOptions#max + * @type Number + * @optional + */ + + /** + * Generate a set of linear ticks + * @method Chart.Ticks.generators.linear + * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks + * @param dataRange {IRange} the range of the data + * @returns {Array} array of tick values + */ + linear: function(generationOptions, dataRange) { + var ticks = []; + // To get a "nice" value for the tick spacing, we will use the appropriately named + // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks + // for details. + + var spacing; + if (generationOptions.stepSize && generationOptions.stepSize > 0) { + spacing = generationOptions.stepSize; + } else { + var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false); + spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true); + } + var niceMin = Math.floor(dataRange.min / spacing) * spacing; + var niceMax = Math.ceil(dataRange.max / spacing) * spacing; + + // If min, max and stepSize is set and they make an evenly spaced scale use it. + if (generationOptions.min && generationOptions.max && generationOptions.stepSize) { + // If very close to our whole number, use it. + if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) { + niceMin = generationOptions.min; + niceMax = generationOptions.max; + } + } + + var numSpaces = (niceMax - niceMin) / spacing; + // If very close to our rounded value, use it. + if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { + numSpaces = Math.round(numSpaces); + } else { + numSpaces = Math.ceil(numSpaces); + } + + // Put the values into the ticks array + ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin); + for (var j = 1; j < numSpaces; ++j) { + ticks.push(niceMin + (j * spacing)); + } + ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax); + + return ticks; + }, + + /** + * Generate a set of logarithmic ticks + * @method Chart.Ticks.generators.logarithmic + * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks + * @param dataRange {IRange} the range of the data + * @returns {Array} array of tick values + */ + logarithmic: function(generationOptions, dataRange) { + var ticks = []; + var valueOrDefault = helpers.valueOrDefault; + + // Figure out what the max number of ticks we can support it is based on the size of + // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 + // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on + // the graph + var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min)))); + + var endExp = Math.floor(helpers.log10(dataRange.max)); + var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); + var exp, significand; + + if (tickVal === 0) { + exp = Math.floor(helpers.log10(dataRange.minNotZero)); + significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp)); + + ticks.push(tickVal); + tickVal = significand * Math.pow(10, exp); + } else { + exp = Math.floor(helpers.log10(tickVal)); + significand = Math.floor(tickVal / Math.pow(10, exp)); + } + + do { + ticks.push(tickVal); + + ++significand; + if (significand === 10) { + significand = 1; + ++exp; + } + + tickVal = significand * Math.pow(10, exp); + } while (exp < endExp || (exp === endExp && significand < endSignificand)); + + var lastTick = valueOrDefault(generationOptions.max, tickVal); + ticks.push(lastTick); + + return ticks; + } + }, + + /** + * Namespace to hold formatters for different types of ticks + * @namespace Chart.Ticks.formatters + */ + formatters: { + /** + * Formatter for value labels + * @method Chart.Ticks.formatters.values + * @param value the value to display + * @return {String|Array} the label to display + */ + values: function(value) { + return helpers.isArray(value) ? value : '' + value; + }, + + /** + * Formatter for linear numeric ticks + * @method Chart.Ticks.formatters.linear + * @param tickValue {Number} the value to be formatted + * @param index {Number} the position of the tickValue parameter in the ticks array + * @param ticks {Array} the list of ticks being converted + * @return {String} string representation of the tickValue parameter + */ + linear: function(tickValue, index, ticks) { + // If we have lots of ticks, don't use the ones + var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0]; + + // If we have a number like 2.5 as the delta, figure out how many decimal places we need + if (Math.abs(delta) > 1) { + if (tickValue !== Math.floor(tickValue)) { + // not an integer + delta = tickValue - Math.floor(tickValue); + } + } + + var logDelta = helpers.log10(Math.abs(delta)); + var tickString = ''; + + if (tickValue !== 0) { + var numDecimal = -1 * Math.floor(logDelta); + numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places + tickString = tickValue.toFixed(numDecimal); + } else { + tickString = '0'; // never show decimal places for 0 + } + + return tickString; + }, + + logarithmic: function(tickValue, index, ticks) { + var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue)))); + + if (tickValue === 0) { + return '0'; + } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) { + return tickValue.toExponential(); + } + return ''; + } + } +}; + +},{"45":45}],35:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); + +defaults._set('global', { + tooltips: { + enabled: true, + custom: null, + mode: 'nearest', + position: 'average', + intersect: true, + backgroundColor: 'rgba(0,0,0,0.8)', + titleFontStyle: 'bold', + titleSpacing: 2, + titleMarginBottom: 6, + titleFontColor: '#fff', + titleAlign: 'left', + bodySpacing: 2, + bodyFontColor: '#fff', + bodyAlign: 'left', + footerFontStyle: 'bold', + footerSpacing: 2, + footerMarginTop: 6, + footerFontColor: '#fff', + footerAlign: 'left', + yPadding: 6, + xPadding: 6, + caretPadding: 2, + caretSize: 5, + cornerRadius: 6, + multiKeyBackground: '#fff', + displayColors: true, + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + callbacks: { + // Args are: (tooltipItems, data) + beforeTitle: helpers.noop, + title: function(tooltipItems, data) { + // Pick first xLabel for now + var title = ''; + var labels = data.labels; + var labelCount = labels ? labels.length : 0; + + if (tooltipItems.length > 0) { + var item = tooltipItems[0]; + + if (item.xLabel) { + title = item.xLabel; + } else if (labelCount > 0 && item.index < labelCount) { + title = labels[item.index]; + } + } + + return title; + }, + afterTitle: helpers.noop, + + // Args are: (tooltipItems, data) + beforeBody: helpers.noop, + + // Args are: (tooltipItem, data) + beforeLabel: helpers.noop, + label: function(tooltipItem, data) { + var label = data.datasets[tooltipItem.datasetIndex].label || ''; + + if (label) { + label += ': '; + } + label += tooltipItem.yLabel; + return label; + }, + labelColor: function(tooltipItem, chart) { + var meta = chart.getDatasetMeta(tooltipItem.datasetIndex); + var activeElement = meta.data[tooltipItem.index]; + var view = activeElement._view; + return { + borderColor: view.borderColor, + backgroundColor: view.backgroundColor + }; + }, + labelTextColor: function() { + return this._options.bodyFontColor; + }, + afterLabel: helpers.noop, + + // Args are: (tooltipItems, data) + afterBody: helpers.noop, + + // Args are: (tooltipItems, data) + beforeFooter: helpers.noop, + footer: helpers.noop, + afterFooter: helpers.noop + } + } +}); + +module.exports = function(Chart) { + + /** + * Helper method to merge the opacity into a color + */ + function mergeOpacity(colorString, opacity) { + var color = helpers.color(colorString); + return color.alpha(opacity * color.alpha()).rgbaString(); + } + + // Helper to push or concat based on if the 2nd parameter is an array or not + function pushOrConcat(base, toPush) { + if (toPush) { + if (helpers.isArray(toPush)) { + // base = base.concat(toPush); + Array.prototype.push.apply(base, toPush); + } else { + base.push(toPush); + } + } + + return base; + } + + // Private helper to create a tooltip item model + // @param element : the chart element (point, arc, bar) to create the tooltip item for + // @return : new tooltip item + function createTooltipItem(element) { + var xScale = element._xScale; + var yScale = element._yScale || element._scale; // handle radar || polarArea charts + var index = element._index; + var datasetIndex = element._datasetIndex; + + return { + xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '', + yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '', + index: index, + datasetIndex: datasetIndex, + x: element._model.x, + y: element._model.y + }; + } + + /** + * Helper to get the reset model for the tooltip + * @param tooltipOpts {Object} the tooltip options + */ + function getBaseModel(tooltipOpts) { + var globalDefaults = defaults.global; + var valueOrDefault = helpers.valueOrDefault; + + return { + // Positioning + xPadding: tooltipOpts.xPadding, + yPadding: tooltipOpts.yPadding, + xAlign: tooltipOpts.xAlign, + yAlign: tooltipOpts.yAlign, + + // Body + bodyFontColor: tooltipOpts.bodyFontColor, + _bodyFontFamily: valueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily), + _bodyFontStyle: valueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle), + _bodyAlign: tooltipOpts.bodyAlign, + bodyFontSize: valueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize), + bodySpacing: tooltipOpts.bodySpacing, + + // Title + titleFontColor: tooltipOpts.titleFontColor, + _titleFontFamily: valueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily), + _titleFontStyle: valueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle), + titleFontSize: valueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize), + _titleAlign: tooltipOpts.titleAlign, + titleSpacing: tooltipOpts.titleSpacing, + titleMarginBottom: tooltipOpts.titleMarginBottom, + + // Footer + footerFontColor: tooltipOpts.footerFontColor, + _footerFontFamily: valueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily), + _footerFontStyle: valueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle), + footerFontSize: valueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize), + _footerAlign: tooltipOpts.footerAlign, + footerSpacing: tooltipOpts.footerSpacing, + footerMarginTop: tooltipOpts.footerMarginTop, + + // Appearance + caretSize: tooltipOpts.caretSize, + cornerRadius: tooltipOpts.cornerRadius, + backgroundColor: tooltipOpts.backgroundColor, + opacity: 0, + legendColorBackground: tooltipOpts.multiKeyBackground, + displayColors: tooltipOpts.displayColors, + borderColor: tooltipOpts.borderColor, + borderWidth: tooltipOpts.borderWidth + }; + } + + /** + * Get the size of the tooltip + */ + function getTooltipSize(tooltip, model) { + var ctx = tooltip._chart.ctx; + + var height = model.yPadding * 2; // Tooltip Padding + var width = 0; + + // Count of all lines in the body + var body = model.body; + var combinedBodyLength = body.reduce(function(count, bodyItem) { + return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length; + }, 0); + combinedBodyLength += model.beforeBody.length + model.afterBody.length; + + var titleLineCount = model.title.length; + var footerLineCount = model.footer.length; + var titleFontSize = model.titleFontSize; + var bodyFontSize = model.bodyFontSize; + var footerFontSize = model.footerFontSize; + + height += titleLineCount * titleFontSize; // Title Lines + height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing + height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin + height += combinedBodyLength * bodyFontSize; // Body Lines + height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing + height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin + height += footerLineCount * (footerFontSize); // Footer Lines + height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing + + // Title width + var widthPadding = 0; + var maxLineWidth = function(line) { + width = Math.max(width, ctx.measureText(line).width + widthPadding); + }; + + ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily); + helpers.each(model.title, maxLineWidth); + + // Body width + ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily); + helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth); + + // Body lines may include some extra width due to the color box + widthPadding = model.displayColors ? (bodyFontSize + 2) : 0; + helpers.each(body, function(bodyItem) { + helpers.each(bodyItem.before, maxLineWidth); + helpers.each(bodyItem.lines, maxLineWidth); + helpers.each(bodyItem.after, maxLineWidth); + }); + + // Reset back to 0 + widthPadding = 0; + + // Footer width + ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily); + helpers.each(model.footer, maxLineWidth); + + // Add padding + width += 2 * model.xPadding; + + return { + width: width, + height: height + }; + } + + /** + * Helper to get the alignment of a tooltip given the size + */ + function determineAlignment(tooltip, size) { + var model = tooltip._model; + var chart = tooltip._chart; + var chartArea = tooltip._chart.chartArea; + var xAlign = 'center'; + var yAlign = 'center'; + + if (model.y < size.height) { + yAlign = 'top'; + } else if (model.y > (chart.height - size.height)) { + yAlign = 'bottom'; + } + + var lf, rf; // functions to determine left, right alignment + var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart + var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges + var midX = (chartArea.left + chartArea.right) / 2; + var midY = (chartArea.top + chartArea.bottom) / 2; + + if (yAlign === 'center') { + lf = function(x) { + return x <= midX; + }; + rf = function(x) { + return x > midX; + }; + } else { + lf = function(x) { + return x <= (size.width / 2); + }; + rf = function(x) { + return x >= (chart.width - (size.width / 2)); + }; + } + + olf = function(x) { + return x + size.width > chart.width; + }; + orf = function(x) { + return x - size.width < 0; + }; + yf = function(y) { + return y <= midY ? 'top' : 'bottom'; + }; + + if (lf(model.x)) { + xAlign = 'left'; + + // Is tooltip too wide and goes over the right side of the chart.? + if (olf(model.x)) { + xAlign = 'center'; + yAlign = yf(model.y); + } + } else if (rf(model.x)) { + xAlign = 'right'; + + // Is tooltip too wide and goes outside left edge of canvas? + if (orf(model.x)) { + xAlign = 'center'; + yAlign = yf(model.y); + } + } + + var opts = tooltip._options; + return { + xAlign: opts.xAlign ? opts.xAlign : xAlign, + yAlign: opts.yAlign ? opts.yAlign : yAlign + }; + } + + /** + * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment + */ + function getBackgroundPoint(vm, size, alignment) { + // Background Position + var x = vm.x; + var y = vm.y; + + var caretSize = vm.caretSize; + var caretPadding = vm.caretPadding; + var cornerRadius = vm.cornerRadius; + var xAlign = alignment.xAlign; + var yAlign = alignment.yAlign; + var paddingAndSize = caretSize + caretPadding; + var radiusAndPadding = cornerRadius + caretPadding; + + if (xAlign === 'right') { + x -= size.width; + } else if (xAlign === 'center') { + x -= (size.width / 2); + } + + if (yAlign === 'top') { + y += paddingAndSize; + } else if (yAlign === 'bottom') { + y -= size.height + paddingAndSize; + } else { + y -= (size.height / 2); + } + + if (yAlign === 'center') { + if (xAlign === 'left') { + x += paddingAndSize; + } else if (xAlign === 'right') { + x -= paddingAndSize; + } + } else if (xAlign === 'left') { + x -= radiusAndPadding; + } else if (xAlign === 'right') { + x += radiusAndPadding; + } + + return { + x: x, + y: y + }; + } + + Chart.Tooltip = Element.extend({ + initialize: function() { + this._model = getBaseModel(this._options); + this._lastActive = []; + }, + + // Get the title + // Args are: (tooltipItem, data) + getTitle: function() { + var me = this; + var opts = me._options; + var callbacks = opts.callbacks; + + var beforeTitle = callbacks.beforeTitle.apply(me, arguments); + var title = callbacks.title.apply(me, arguments); + var afterTitle = callbacks.afterTitle.apply(me, arguments); + + var lines = []; + lines = pushOrConcat(lines, beforeTitle); + lines = pushOrConcat(lines, title); + lines = pushOrConcat(lines, afterTitle); + + return lines; + }, + + // Args are: (tooltipItem, data) + getBeforeBody: function() { + var lines = this._options.callbacks.beforeBody.apply(this, arguments); + return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : []; + }, + + // Args are: (tooltipItem, data) + getBody: function(tooltipItems, data) { + var me = this; + var callbacks = me._options.callbacks; + var bodyItems = []; + + helpers.each(tooltipItems, function(tooltipItem) { + var bodyItem = { + before: [], + lines: [], + after: [] + }; + pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data)); + pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data)); + pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data)); + + bodyItems.push(bodyItem); + }); + + return bodyItems; + }, + + // Args are: (tooltipItem, data) + getAfterBody: function() { + var lines = this._options.callbacks.afterBody.apply(this, arguments); + return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : []; + }, + + // Get the footer and beforeFooter and afterFooter lines + // Args are: (tooltipItem, data) + getFooter: function() { + var me = this; + var callbacks = me._options.callbacks; + + var beforeFooter = callbacks.beforeFooter.apply(me, arguments); + var footer = callbacks.footer.apply(me, arguments); + var afterFooter = callbacks.afterFooter.apply(me, arguments); + + var lines = []; + lines = pushOrConcat(lines, beforeFooter); + lines = pushOrConcat(lines, footer); + lines = pushOrConcat(lines, afterFooter); + + return lines; + }, + + update: function(changed) { + var me = this; + var opts = me._options; + + // Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition + // that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time + // which breaks any animations. + var existingModel = me._model; + var model = me._model = getBaseModel(opts); + var active = me._active; + + var data = me._data; + + // In the case where active.length === 0 we need to keep these at existing values for good animations + var alignment = { + xAlign: existingModel.xAlign, + yAlign: existingModel.yAlign + }; + var backgroundPoint = { + x: existingModel.x, + y: existingModel.y + }; + var tooltipSize = { + width: existingModel.width, + height: existingModel.height + }; + var tooltipPosition = { + x: existingModel.caretX, + y: existingModel.caretY + }; + + var i, len; + + if (active.length) { + model.opacity = 1; + + var labelColors = []; + var labelTextColors = []; + tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition); + + var tooltipItems = []; + for (i = 0, len = active.length; i < len; ++i) { + tooltipItems.push(createTooltipItem(active[i])); + } + + // If the user provided a filter function, use it to modify the tooltip items + if (opts.filter) { + tooltipItems = tooltipItems.filter(function(a) { + return opts.filter(a, data); + }); + } + + // If the user provided a sorting function, use it to modify the tooltip items + if (opts.itemSort) { + tooltipItems = tooltipItems.sort(function(a, b) { + return opts.itemSort(a, b, data); + }); + } + + // Determine colors for boxes + helpers.each(tooltipItems, function(tooltipItem) { + labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart)); + labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart)); + }); + + + // Build the Text Lines + model.title = me.getTitle(tooltipItems, data); + model.beforeBody = me.getBeforeBody(tooltipItems, data); + model.body = me.getBody(tooltipItems, data); + model.afterBody = me.getAfterBody(tooltipItems, data); + model.footer = me.getFooter(tooltipItems, data); + + // Initial positioning and colors + model.x = Math.round(tooltipPosition.x); + model.y = Math.round(tooltipPosition.y); + model.caretPadding = opts.caretPadding; + model.labelColors = labelColors; + model.labelTextColors = labelTextColors; + + // data points + model.dataPoints = tooltipItems; + + // We need to determine alignment of the tooltip + tooltipSize = getTooltipSize(this, model); + alignment = determineAlignment(this, tooltipSize); + // Final Size and Position + backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment); + } else { + model.opacity = 0; + } + + model.xAlign = alignment.xAlign; + model.yAlign = alignment.yAlign; + model.x = backgroundPoint.x; + model.y = backgroundPoint.y; + model.width = tooltipSize.width; + model.height = tooltipSize.height; + + // Point where the caret on the tooltip points to + model.caretX = tooltipPosition.x; + model.caretY = tooltipPosition.y; + + me._model = model; + + if (changed && opts.custom) { + opts.custom.call(me, model); + } + + return me; + }, + drawCaret: function(tooltipPoint, size) { + var ctx = this._chart.ctx; + var vm = this._view; + var caretPosition = this.getCaretPosition(tooltipPoint, size, vm); + + ctx.lineTo(caretPosition.x1, caretPosition.y1); + ctx.lineTo(caretPosition.x2, caretPosition.y2); + ctx.lineTo(caretPosition.x3, caretPosition.y3); + }, + getCaretPosition: function(tooltipPoint, size, vm) { + var x1, x2, x3, y1, y2, y3; + var caretSize = vm.caretSize; + var cornerRadius = vm.cornerRadius; + var xAlign = vm.xAlign; + var yAlign = vm.yAlign; + var ptX = tooltipPoint.x; + var ptY = tooltipPoint.y; + var width = size.width; + var height = size.height; + + if (yAlign === 'center') { + y2 = ptY + (height / 2); + + if (xAlign === 'left') { + x1 = ptX; + x2 = x1 - caretSize; + x3 = x1; + + y1 = y2 + caretSize; + y3 = y2 - caretSize; + } else { + x1 = ptX + width; + x2 = x1 + caretSize; + x3 = x1; + + y1 = y2 - caretSize; + y3 = y2 + caretSize; + } + } else { + if (xAlign === 'left') { + x2 = ptX + cornerRadius + (caretSize); + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } else if (xAlign === 'right') { + x2 = ptX + width - cornerRadius - caretSize; + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } else { + x2 = ptX + (width / 2); + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } + if (yAlign === 'top') { + y1 = ptY; + y2 = y1 - caretSize; + y3 = y1; + } else { + y1 = ptY + height; + y2 = y1 + caretSize; + y3 = y1; + // invert drawing order + var tmp = x3; + x3 = x1; + x1 = tmp; + } + } + return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3}; + }, + drawTitle: function(pt, vm, ctx, opacity) { + var title = vm.title; + + if (title.length) { + ctx.textAlign = vm._titleAlign; + ctx.textBaseline = 'top'; + + var titleFontSize = vm.titleFontSize; + var titleSpacing = vm.titleSpacing; + + ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity); + ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily); + + var i, len; + for (i = 0, len = title.length; i < len; ++i) { + ctx.fillText(title[i], pt.x, pt.y); + pt.y += titleFontSize + titleSpacing; // Line Height and spacing + + if (i + 1 === title.length) { + pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing + } + } + } + }, + drawBody: function(pt, vm, ctx, opacity) { + var bodyFontSize = vm.bodyFontSize; + var bodySpacing = vm.bodySpacing; + var body = vm.body; + + ctx.textAlign = vm._bodyAlign; + ctx.textBaseline = 'top'; + ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily); + + // Before Body + var xLinePadding = 0; + var fillLineOfText = function(line) { + ctx.fillText(line, pt.x + xLinePadding, pt.y); + pt.y += bodyFontSize + bodySpacing; + }; + + // Before body lines + ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity); + helpers.each(vm.beforeBody, fillLineOfText); + + var drawColorBoxes = vm.displayColors; + xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0; + + // 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) { + // Draw Legend-like boxes if needed + if (drawColorBoxes) { + // Fill a white rect so that colours merge nicely if the opacity is < 1 + ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity); + ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize); + + // Border + ctx.lineWidth = 1; + ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity); + ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize); + + // Inner square + ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity); + ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2); + ctx.fillStyle = textColor; + } + + fillLineOfText(line); + }); + + helpers.each(bodyItem.after, fillLineOfText); + }); + + // Reset back to 0 for after body + xLinePadding = 0; + + // After body lines + helpers.each(vm.afterBody, fillLineOfText); + pt.y -= bodySpacing; // Remove last body spacing + }, + drawFooter: function(pt, vm, ctx, opacity) { + var footer = vm.footer; + + if (footer.length) { + pt.y += vm.footerMarginTop; + + ctx.textAlign = vm._footerAlign; + ctx.textBaseline = 'top'; + + ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity); + ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); + + helpers.each(footer, function(line) { + ctx.fillText(line, pt.x, pt.y); + pt.y += vm.footerFontSize + vm.footerSpacing; + }); + } + }, + drawBackground: function(pt, vm, ctx, tooltipSize, opacity) { + ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity); + ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity); + ctx.lineWidth = vm.borderWidth; + var xAlign = vm.xAlign; + var yAlign = vm.yAlign; + var x = pt.x; + var y = pt.y; + var width = tooltipSize.width; + var height = tooltipSize.height; + var radius = vm.cornerRadius; + + ctx.beginPath(); + ctx.moveTo(x + radius, y); + if (yAlign === 'top') { + this.drawCaret(pt, tooltipSize); + } + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + if (yAlign === 'center' && xAlign === 'right') { + this.drawCaret(pt, tooltipSize); + } + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); + if (yAlign === 'bottom') { + this.drawCaret(pt, tooltipSize); + } + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + if (yAlign === 'center' && xAlign === 'left') { + this.drawCaret(pt, tooltipSize); + } + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + + ctx.fill(); + + if (vm.borderWidth > 0) { + ctx.stroke(); + } + }, + draw: function() { + var ctx = this._chart.ctx; + var vm = this._view; + + if (vm.opacity === 0) { + return; + } + + var tooltipSize = { + width: vm.width, + height: vm.height + }; + var pt = { + x: vm.x, + y: vm.y + }; + + // IE11/Edge does not like very small opacities, so snap to 0 + var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity; + + // Truthy/falsey value for empty tooltip + var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length; + + if (this._options.enabled && hasTooltipContent) { + // Draw Background + this.drawBackground(pt, vm, ctx, tooltipSize, opacity); + + // Draw Title, Body, and Footer + pt.x += vm.xPadding; + pt.y += vm.yPadding; + + // Titles + this.drawTitle(pt, vm, ctx, opacity); + + // Body + this.drawBody(pt, vm, ctx, opacity); + + // Footer + this.drawFooter(pt, vm, ctx, opacity); + } + }, + + /** + * Handle an event + * @private + * @param {IEvent} event - The event to handle + * @returns {Boolean} true if the tooltip changed + */ + handleEvent: function(e) { + var me = this; + var options = me._options; + var changed = false; + + me._lastActive = me._lastActive || []; + + // Find Active Elements for tooltips + if (e.type === 'mouseout') { + me._active = []; + } else { + me._active = me._chart.getElementsAtEventForMode(e, options.mode, options); + } + + // Remember Last Actives + changed = !helpers.arrayEquals(me._active, me._lastActive); + + // If tooltip didn't change, do not handle the target event + if (!changed) { + return false; + } + + me._lastActive = me._active; + + if (options.enabled || options.custom) { + me._eventPosition = { + x: e.x, + y: e.y + }; + + var model = me._model; + me.update(true); + me.pivot(); + + // See if our tooltip position changed + changed |= (model.x !== me._model.x) || (model.y !== me._model.y); + } + + return changed; + } + }); + + /** + * @namespace Chart.Tooltip.positioners + */ + Chart.Tooltip.positioners = { + /** + * Average mode places the tooltip at the average position of the elements shown + * @function Chart.Tooltip.positioners.average + * @param elements {ChartElement[]} the elements being displayed in the tooltip + * @returns {Point} tooltip position + */ + average: function(elements) { + if (!elements.length) { + return false; + } + + var i, len; + var x = 0; + var y = 0; + var count = 0; + + for (i = 0, len = elements.length; i < len; ++i) { + var el = elements[i]; + if (el && el.hasValue()) { + var pos = el.tooltipPosition(); + x += pos.x; + y += pos.y; + ++count; + } + } + + return { + x: Math.round(x / count), + y: Math.round(y / count) + }; + }, + + /** + * Gets the tooltip position nearest of the item nearest to the event position + * @function Chart.Tooltip.positioners.nearest + * @param elements {Chart.Element[]} the tooltip elements + * @param eventPosition {Point} the position of the event in canvas coordinates + * @returns {Point} the tooltip position + */ + nearest: function(elements, eventPosition) { + var x = eventPosition.x; + var y = eventPosition.y; + var minDistance = Number.POSITIVE_INFINITY; + var i, len, nearestElement; + + for (i = 0, len = elements.length; i < len; ++i) { + var el = elements[i]; + if (el && el.hasValue()) { + var center = el.getCenterPoint(); + var d = helpers.distanceBetweenPoints(eventPosition, center); + + if (d < minDistance) { + minDistance = d; + nearestElement = el; + } + } + } + + if (nearestElement) { + var tp = nearestElement.tooltipPosition(); + x = tp.x; + y = tp.y; + } + + return { + x: x, + y: y + }; + } + }; +}; + +},{"25":25,"26":26,"45":45}],36:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); + +defaults._set('global', { + elements: { + arc: { + backgroundColor: defaults.global.defaultColor, + borderColor: '#fff', + borderWidth: 2 + } + } +}); + +module.exports = Element.extend({ + inLabelRange: function(mouseX) { + var vm = this._view; + + if (vm) { + return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2)); + } + return false; + }, + + inRange: function(chartX, chartY) { + var vm = this._view; + + if (vm) { + var pointRelativePosition = helpers.getAngleFromPoint(vm, {x: chartX, y: chartY}); + var angle = pointRelativePosition.angle; + var distance = pointRelativePosition.distance; + + // Sanitise angle range + var startAngle = vm.startAngle; + var endAngle = vm.endAngle; + while (endAngle < startAngle) { + endAngle += 2.0 * Math.PI; + } + while (angle > endAngle) { + angle -= 2.0 * Math.PI; + } + while (angle < startAngle) { + angle += 2.0 * Math.PI; + } + + // Check if within the range of the open/close angle + var betweenAngles = (angle >= startAngle && angle <= endAngle); + var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius); + + return (betweenAngles && withinRadius); + } + return false; + }, + + getCenterPoint: function() { + var vm = this._view; + var halfAngle = (vm.startAngle + vm.endAngle) / 2; + var halfRadius = (vm.innerRadius + vm.outerRadius) / 2; + return { + x: vm.x + Math.cos(halfAngle) * halfRadius, + y: vm.y + Math.sin(halfAngle) * halfRadius + }; + }, + + getArea: function() { + var vm = this._view; + return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2)); + }, + + tooltipPosition: function() { + var vm = this._view; + var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2); + var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius; + + return { + x: vm.x + (Math.cos(centreAngle) * rangeFromCentre), + y: vm.y + (Math.sin(centreAngle) * rangeFromCentre) + }; + }, + + draw: function() { + var ctx = this._chart.ctx; + var vm = this._view; + var sA = vm.startAngle; + var eA = vm.endAngle; + + ctx.beginPath(); + + ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA); + ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true); + + ctx.closePath(); + ctx.strokeStyle = vm.borderColor; + ctx.lineWidth = vm.borderWidth; + + ctx.fillStyle = vm.backgroundColor; + + ctx.fill(); + ctx.lineJoin = 'bevel'; + + if (vm.borderWidth) { + ctx.stroke(); + } + } +}); + +},{"25":25,"26":26,"45":45}],37:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); + +var globalDefaults = defaults.global; + +defaults._set('global', { + elements: { + line: { + tension: 0.4, + backgroundColor: globalDefaults.defaultColor, + borderWidth: 3, + borderColor: globalDefaults.defaultColor, + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: 'miter', + capBezierPoints: true, + fill: true, // do we fill in the area between the line and its base axis + } + } +}); + +module.exports = Element.extend({ + draw: function() { + var me = this; + var vm = me._view; + var ctx = me._chart.ctx; + var spanGaps = vm.spanGaps; + var points = me._children.slice(); // clone array + var globalOptionLineElements = globalDefaults.elements.line; + var lastDrawnIndex = -1; + var index, current, previous, currentVM; + + // If we are looping, adding the first point again + if (me._loop && points.length) { + points.push(points[0]); + } + + ctx.save(); + + // Stroke Line Options + ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle; + + // IE 9 and 10 do not support line dash + if (ctx.setLineDash) { + ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash); + } + + ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset; + ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle; + ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth; + ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor; + + // Stroke Line + ctx.beginPath(); + lastDrawnIndex = -1; + + for (index = 0; index < points.length; ++index) { + current = points[index]; + previous = helpers.previousItem(points, index); + currentVM = current._view; + + // First point moves to it's starting position no matter what + if (index === 0) { + if (!currentVM.skip) { + ctx.moveTo(currentVM.x, currentVM.y); + lastDrawnIndex = index; + } + } else { + previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex]; + + if (!currentVM.skip) { + if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) { + // There was a gap and this is the first point after the gap + ctx.moveTo(currentVM.x, currentVM.y); + } else { + // Line to next point + helpers.canvas.lineTo(ctx, previous._view, current._view); + } + lastDrawnIndex = index; + } + } + } + + ctx.stroke(); + ctx.restore(); + } +}); + +},{"25":25,"26":26,"45":45}],38:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); + +var defaultColor = defaults.global.defaultColor; + +defaults._set('global', { + elements: { + point: { + radius: 3, + pointStyle: 'circle', + backgroundColor: defaultColor, + borderColor: defaultColor, + borderWidth: 1, + // Hover + hitRadius: 1, + hoverRadius: 4, + hoverBorderWidth: 1 + } + } +}); + +function xRange(mouseX) { + var vm = this._view; + return vm ? (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false; +} + +function yRange(mouseY) { + var vm = this._view; + return vm ? (Math.pow(mouseY - vm.y, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false; +} + +module.exports = Element.extend({ + inRange: function(mouseX, mouseY) { + var vm = this._view; + return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false; + }, + + inLabelRange: xRange, + inXRange: xRange, + inYRange: yRange, + + getCenterPoint: function() { + var vm = this._view; + return { + x: vm.x, + y: vm.y + }; + }, + + getArea: function() { + return Math.PI * Math.pow(this._view.radius, 2); + }, + + tooltipPosition: function() { + var vm = this._view; + return { + x: vm.x, + y: vm.y, + padding: vm.radius + vm.borderWidth + }; + }, + + draw: function(chartArea) { + var vm = this._view; + var model = this._model; + var ctx = this._chart.ctx; + var pointStyle = vm.pointStyle; + var radius = vm.radius; + var x = vm.x; + var y = vm.y; + var color = helpers.color; + var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.) + var ratio = 0; + + if (vm.skip) { + return; + } + + ctx.strokeStyle = vm.borderColor || defaultColor; + ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth); + ctx.fillStyle = vm.backgroundColor || defaultColor; + + // Cliping for Points. + // going out from inner charArea? + if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right * errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom * errMargin < model.y))) { + // Point fade out + if (model.x < chartArea.left) { + ratio = (x - model.x) / (chartArea.left - model.x); + } else if (chartArea.right * errMargin < model.x) { + ratio = (model.x - x) / (model.x - chartArea.right); + } else if (model.y < chartArea.top) { + ratio = (y - model.y) / (chartArea.top - model.y); + } else if (chartArea.bottom * errMargin < model.y) { + ratio = (model.y - y) / (model.y - chartArea.bottom); + } + ratio = Math.round(ratio * 100) / 100; + ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString(); + ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString(); + } + + helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y); + } +}); + +},{"25":25,"26":26,"45":45}],39:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); + +defaults._set('global', { + elements: { + rectangle: { + backgroundColor: defaults.global.defaultColor, + borderColor: defaults.global.defaultColor, + borderSkipped: 'bottom', + borderWidth: 0 + } + } +}); + +function isVertical(bar) { + return bar._view.width !== undefined; +} + +/** + * Helper function to get the bounds of the bar regardless of the orientation + * @param bar {Chart.Element.Rectangle} the bar + * @return {Bounds} bounds of the bar + * @private + */ +function getBarBounds(bar) { + var vm = bar._view; + var x1, x2, y1, y2; + + if (isVertical(bar)) { + // vertical + var halfWidth = vm.width / 2; + x1 = vm.x - halfWidth; + x2 = vm.x + halfWidth; + y1 = Math.min(vm.y, vm.base); + y2 = Math.max(vm.y, vm.base); + } else { + // horizontal bar + var halfHeight = vm.height / 2; + x1 = Math.min(vm.x, vm.base); + x2 = Math.max(vm.x, vm.base); + y1 = vm.y - halfHeight; + y2 = vm.y + halfHeight; + } + + return { + left: x1, + top: y1, + right: x2, + bottom: y2 + }; +} + +module.exports = Element.extend({ + draw: function() { + var ctx = this._chart.ctx; + var vm = this._view; + var left, right, top, bottom, signX, signY, borderSkipped; + var borderWidth = vm.borderWidth; + + if (!vm.horizontal) { + // bar + left = vm.x - vm.width / 2; + right = vm.x + vm.width / 2; + top = vm.y; + bottom = vm.base; + signX = 1; + signY = bottom > top ? 1 : -1; + borderSkipped = vm.borderSkipped || 'bottom'; + } else { + // horizontal bar + left = vm.base; + right = vm.x; + top = vm.y - vm.height / 2; + bottom = vm.y + vm.height / 2; + signX = right > left ? 1 : -1; + signY = 1; + borderSkipped = vm.borderSkipped || 'left'; + } + + // Canvas doesn't allow us to stroke inside the width so we can + // adjust the sizes to fit if we're setting a stroke on the line + if (borderWidth) { + // borderWidth shold be less than bar width and bar height. + var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom)); + borderWidth = borderWidth > barSize ? barSize : borderWidth; + var halfStroke = borderWidth / 2; + // Adjust borderWidth when bar top position is near vm.base(zero). + var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0); + var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0); + var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0); + var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0); + // not become a vertical line? + if (borderLeft !== borderRight) { + top = borderTop; + bottom = borderBottom; + } + // not become a horizontal line? + if (borderTop !== borderBottom) { + left = borderLeft; + right = borderRight; + } + } + + ctx.beginPath(); + ctx.fillStyle = vm.backgroundColor; + ctx.strokeStyle = vm.borderColor; + ctx.lineWidth = borderWidth; + + // Corner points, from bottom-left to bottom-right clockwise + // | 1 2 | + // | 0 3 | + var corners = [ + [left, bottom], + [left, top], + [right, top], + [right, bottom] + ]; + + // Find first (starting) corner with fallback to 'bottom' + var borders = ['bottom', 'left', 'top', 'right']; + var startCorner = borders.indexOf(borderSkipped, 0); + if (startCorner === -1) { + startCorner = 0; + } + + function cornerAt(index) { + return corners[(startCorner + index) % 4]; + } + + // Draw rectangle from 'startCorner' + var corner = cornerAt(0); + ctx.moveTo(corner[0], corner[1]); + + for (var i = 1; i < 4; i++) { + corner = cornerAt(i); + ctx.lineTo(corner[0], corner[1]); + } + + ctx.fill(); + if (borderWidth) { + ctx.stroke(); + } + }, + + height: function() { + var vm = this._view; + return vm.base - vm.y; + }, + + inRange: function(mouseX, mouseY) { + var inRange = false; + + if (this._view) { + var bounds = getBarBounds(this); + inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom; + } + + return inRange; + }, + + inLabelRange: function(mouseX, mouseY) { + var me = this; + if (!me._view) { + return false; + } + + var inRange = false; + var bounds = getBarBounds(me); + + if (isVertical(me)) { + inRange = mouseX >= bounds.left && mouseX <= bounds.right; + } else { + inRange = mouseY >= bounds.top && mouseY <= bounds.bottom; + } + + return inRange; + }, + + inXRange: function(mouseX) { + var bounds = getBarBounds(this); + return mouseX >= bounds.left && mouseX <= bounds.right; + }, + + inYRange: function(mouseY) { + var bounds = getBarBounds(this); + return mouseY >= bounds.top && mouseY <= bounds.bottom; + }, + + getCenterPoint: function() { + var vm = this._view; + var x, y; + if (isVertical(this)) { + x = vm.x; + y = (vm.y + vm.base) / 2; + } else { + x = (vm.x + vm.base) / 2; + y = vm.y; + } + + return {x: x, y: y}; + }, + + getArea: function() { + var vm = this._view; + return vm.width * Math.abs(vm.y - vm.base); + }, + + tooltipPosition: function() { + var vm = this._view; + return { + x: vm.x, + y: vm.y + }; + } +}); + +},{"25":25,"26":26}],40:[function(require,module,exports){ +'use strict'; + +module.exports = {}; +module.exports.Arc = require(36); +module.exports.Line = require(37); +module.exports.Point = require(38); +module.exports.Rectangle = require(39); + +},{"36":36,"37":37,"38":38,"39":39}],41:[function(require,module,exports){ +'use strict'; + +var helpers = require(42); + +/** + * @namespace Chart.helpers.canvas + */ +var exports = module.exports = { + /** + * Clears the entire canvas associated to the given `chart`. + * @param {Chart} chart - The chart for which to clear the canvas. + */ + clear: function(chart) { + chart.ctx.clearRect(0, 0, chart.width, chart.height); + }, + + /** + * Creates a "path" for a rectangle with rounded corners at position (x, y) with a + * given size (width, height) and the same `radius` for all corners. + * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context. + * @param {Number} x - The x axis of the coordinate for the rectangle starting point. + * @param {Number} y - The y axis of the coordinate for the rectangle starting point. + * @param {Number} width - The rectangle's width. + * @param {Number} height - The rectangle's height. + * @param {Number} radius - The rounded amount (in pixels) for the four corners. + * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object? + */ + roundedRect: function(ctx, x, y, width, height, radius) { + if (radius) { + var rx = Math.min(radius, width / 2); + var ry = Math.min(radius, height / 2); + + ctx.moveTo(x + rx, y); + ctx.lineTo(x + width - rx, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + ry); + ctx.lineTo(x + width, y + height - ry); + ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height); + ctx.lineTo(x + rx, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - ry); + ctx.lineTo(x, y + ry); + ctx.quadraticCurveTo(x, y, x + rx, y); + } else { + ctx.rect(x, y, width, height); + } + }, + + drawPoint: function(ctx, style, radius, x, y) { + var type, edgeLength, xOffset, yOffset, height, size; + + 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); + return; + } + } + + if (isNaN(radius) || radius <= 0) { + return; + } + + switch (style) { + // Default includes circle + default: + ctx.beginPath(); + ctx.arc(x, y, radius, 0, Math.PI * 2); + ctx.closePath(); + ctx.fill(); + break; + case 'triangle': + ctx.beginPath(); + edgeLength = 3 * radius / Math.sqrt(3); + height = edgeLength * Math.sqrt(3) / 2; + ctx.moveTo(x - edgeLength / 2, y + height / 3); + ctx.lineTo(x + edgeLength / 2, y + height / 3); + ctx.lineTo(x, y - 2 * height / 3); + ctx.closePath(); + ctx.fill(); + break; + case 'rect': + size = 1 / Math.SQRT2 * radius; + ctx.beginPath(); + ctx.fillRect(x - size, y - size, 2 * size, 2 * size); + ctx.strokeRect(x - size, y - size, 2 * size, 2 * size); + break; + case 'rectRounded': + var offset = radius / Math.SQRT2; + var leftX = x - offset; + var topY = y - offset; + var sideSize = Math.SQRT2 * radius; + ctx.beginPath(); + this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2); + ctx.closePath(); + ctx.fill(); + break; + case 'rectRot': + size = 1 / Math.SQRT2 * radius; + ctx.beginPath(); + ctx.moveTo(x - size, y); + ctx.lineTo(x, y + size); + ctx.lineTo(x + size, y); + ctx.lineTo(x, y - size); + ctx.closePath(); + ctx.fill(); + break; + case 'cross': + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y - radius); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + case 'crossRot': + ctx.beginPath(); + xOffset = Math.cos(Math.PI / 4) * radius; + yOffset = Math.sin(Math.PI / 4) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x - xOffset, y + yOffset); + ctx.lineTo(x + xOffset, y - yOffset); + ctx.closePath(); + break; + case 'star': + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y - radius); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + xOffset = Math.cos(Math.PI / 4) * radius; + yOffset = Math.sin(Math.PI / 4) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x - xOffset, y + yOffset); + ctx.lineTo(x + xOffset, y - yOffset); + ctx.closePath(); + break; + case 'line': + ctx.beginPath(); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + case 'dash': + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); + break; + } + + ctx.stroke(); + }, + + clipArea: function(ctx, area) { + ctx.save(); + ctx.beginPath(); + ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); + ctx.clip(); + }, + + unclipArea: function(ctx) { + ctx.restore(); + }, + + lineTo: function(ctx, previous, target, flip) { + if (target.steppedLine) { + if ((target.steppedLine === 'after' && !flip) || (target.steppedLine !== 'after' && flip)) { + ctx.lineTo(previous.x, target.y); + } else { + ctx.lineTo(target.x, previous.y); + } + ctx.lineTo(target.x, target.y); + return; + } + + if (!target.tension) { + ctx.lineTo(target.x, target.y); + return; + } + + ctx.bezierCurveTo( + flip ? previous.controlPointPreviousX : previous.controlPointNextX, + flip ? previous.controlPointPreviousY : previous.controlPointNextY, + flip ? target.controlPointNextX : target.controlPointPreviousX, + flip ? target.controlPointNextY : target.controlPointPreviousY, + target.x, + target.y); + } +}; + +// DEPRECATIONS + +/** + * Provided for backward compatibility, use Chart.helpers.canvas.clear instead. + * @namespace Chart.helpers.clear + * @deprecated since version 2.7.0 + * @todo remove at version 3 + * @private + */ +helpers.clear = exports.clear; + +/** + * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead. + * @namespace Chart.helpers.drawRoundedRectangle + * @deprecated since version 2.7.0 + * @todo remove at version 3 + * @private + */ +helpers.drawRoundedRectangle = function(ctx) { + ctx.beginPath(); + exports.roundedRect.apply(exports, arguments); + ctx.closePath(); +}; + +},{"42":42}],42:[function(require,module,exports){ +'use strict'; + +/** + * @namespace Chart.helpers + */ +var helpers = { + /** + * An empty function that can be used, for example, for optional callback. + */ + noop: function() {}, + + /** + * Returns a unique id, sequentially generated from a global variable. + * @returns {Number} + * @function + */ + uid: (function() { + var id = 0; + return function() { + return id++; + }; + }()), + + /** + * Returns true if `value` is neither null nor undefined, else returns false. + * @param {*} value - The value to test. + * @returns {Boolean} + * @since 2.7.0 + */ + isNullOrUndef: function(value) { + return value === null || typeof value === 'undefined'; + }, + + /** + * Returns true if `value` is an array, else returns false. + * @param {*} value - The value to test. + * @returns {Boolean} + * @function + */ + isArray: Array.isArray ? Array.isArray : function(value) { + return Object.prototype.toString.call(value) === '[object Array]'; + }, + + /** + * Returns true if `value` is an object (excluding null), else returns false. + * @param {*} value - The value to test. + * @returns {Boolean} + * @since 2.7.0 + */ + isObject: function(value) { + return value !== null && Object.prototype.toString.call(value) === '[object Object]'; + }, + + /** + * Returns `value` if defined, else returns `defaultValue`. + * @param {*} value - The value to return if defined. + * @param {*} defaultValue - The value to return if `value` is undefined. + * @returns {*} + */ + valueOrDefault: function(value, defaultValue) { + return typeof value === 'undefined' ? defaultValue : value; + }, + + /** + * Returns value at the given `index` in array if defined, else returns `defaultValue`. + * @param {Array} value - The array to lookup for value at `index`. + * @param {Number} index - The index in `value` to lookup for value. + * @param {*} defaultValue - The value to return if `value[index]` is undefined. + * @returns {*} + */ + valueAtIndexOrDefault: function(value, index, defaultValue) { + return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue); + }, + + /** + * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the + * value returned by `fn`. If `fn` is not a function, this method returns undefined. + * @param {Function} fn - The function to call. + * @param {Array|undefined|null} args - The arguments with which `fn` should be called. + * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`. + * @returns {*} + */ + callback: function(fn, args, thisArg) { + if (fn && typeof fn.call === 'function') { + return fn.apply(thisArg, args); + } + }, + + /** + * Note(SB) for performance sake, this method should only be used when loopable type + * is unknown or in none intensive code (not called often and small loopable). Else + * it's preferable to use a regular for() loop and save extra function calls. + * @param {Object|Array} loopable - The object or array to be iterated. + * @param {Function} fn - The function to call for each item. + * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`. + * @param {Boolean} [reverse] - If true, iterates backward on the loopable. + */ + each: function(loopable, fn, thisArg, reverse) { + var i, len, keys; + if (helpers.isArray(loopable)) { + len = loopable.length; + if (reverse) { + for (i = len - 1; i >= 0; i--) { + fn.call(thisArg, loopable[i], i); + } + } else { + for (i = 0; i < len; i++) { + fn.call(thisArg, loopable[i], i); + } + } + } else if (helpers.isObject(loopable)) { + keys = Object.keys(loopable); + len = keys.length; + for (i = 0; i < len; i++) { + fn.call(thisArg, loopable[keys[i]], keys[i]); + } + } + }, + + /** + * Returns true if the `a0` and `a1` arrays have the same content, else returns false. + * @see http://stackoverflow.com/a/14853974 + * @param {Array} a0 - The array to compare + * @param {Array} a1 - The array to compare + * @returns {Boolean} + */ + arrayEquals: function(a0, a1) { + var i, ilen, v0, v1; + + if (!a0 || !a1 || a0.length !== a1.length) { + return false; + } + + for (i = 0, ilen = a0.length; i < ilen; ++i) { + v0 = a0[i]; + v1 = a1[i]; + + if (v0 instanceof Array && v1 instanceof Array) { + if (!helpers.arrayEquals(v0, v1)) { + return false; + } + } else if (v0 !== v1) { + // NOTE: two different object instances will never be equal: {x:20} != {x:20} + return false; + } + } + + return true; + }, + + /** + * Returns a deep copy of `source` without keeping references on objects and arrays. + * @param {*} source - The value to clone. + * @returns {*} + */ + clone: function(source) { + if (helpers.isArray(source)) { + return source.map(helpers.clone); + } + + if (helpers.isObject(source)) { + var target = {}; + var keys = Object.keys(source); + var klen = keys.length; + var k = 0; + + for (; k < klen; ++k) { + target[keys[k]] = helpers.clone(source[keys[k]]); + } + + return target; + } + + return source; + }, + + /** + * The default merger when Chart.helpers.merge is called without merger option. + * Note(SB): this method is also used by configMerge and scaleMerge as fallback. + * @private + */ + _merger: function(key, target, source, options) { + var tval = target[key]; + var sval = source[key]; + + if (helpers.isObject(tval) && helpers.isObject(sval)) { + helpers.merge(tval, sval, options); + } else { + target[key] = helpers.clone(sval); + } + }, + + /** + * Merges source[key] in target[key] only if target[key] is undefined. + * @private + */ + _mergerIf: function(key, target, source) { + var tval = target[key]; + var sval = source[key]; + + if (helpers.isObject(tval) && helpers.isObject(sval)) { + helpers.mergeIf(tval, sval); + } else if (!target.hasOwnProperty(key)) { + target[key] = helpers.clone(sval); + } + }, + + /** + * Recursively deep copies `source` properties into `target` with the given `options`. + * IMPORTANT: `target` is not cloned and will be updated with `source` properties. + * @param {Object} target - The target object in which all sources are merged into. + * @param {Object|Array(Object)} source - Object(s) to merge into `target`. + * @param {Object} [options] - Merging options: + * @param {Function} [options.merger] - The merge method (key, target, source, options) + * @returns {Object} The `target` object. + */ + merge: function(target, source, options) { + var sources = helpers.isArray(source) ? source : [source]; + var ilen = sources.length; + var merge, i, keys, klen, k; + + if (!helpers.isObject(target)) { + return target; + } + + options = options || {}; + merge = options.merger || helpers._merger; + + for (i = 0; i < ilen; ++i) { + source = sources[i]; + if (!helpers.isObject(source)) { + continue; + } + + keys = Object.keys(source); + for (k = 0, klen = keys.length; k < klen; ++k) { + merge(keys[k], target, source, options); + } + } + + return target; + }, + + /** + * Recursively deep copies `source` properties into `target` *only* if not defined in target. + * IMPORTANT: `target` is not cloned and will be updated with `source` properties. + * @param {Object} target - The target object in which all sources are merged into. + * @param {Object|Array(Object)} source - Object(s) to merge into `target`. + * @returns {Object} The `target` object. + */ + 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; + } +}; + +module.exports = helpers; + +// DEPRECATIONS + +/** + * Provided for backward compatibility, use Chart.helpers.callback instead. + * @function Chart.helpers.callCallback + * @deprecated since version 2.6.0 + * @todo remove at version 3 + * @private + */ +helpers.callCallback = helpers.callback; + +/** + * Provided for backward compatibility, use Array.prototype.indexOf instead. + * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+ + * @function Chart.helpers.indexOf + * @deprecated since version 2.7.0 + * @todo remove at version 3 + * @private + */ +helpers.indexOf = function(array, item, fromIndex) { + return Array.prototype.indexOf.call(array, item, fromIndex); +}; + +/** + * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead. + * @function Chart.helpers.getValueOrDefault + * @deprecated since version 2.7.0 + * @todo remove at version 3 + * @private + */ +helpers.getValueOrDefault = helpers.valueOrDefault; + +/** + * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead. + * @function Chart.helpers.getValueAtIndexOrDefault + * @deprecated since version 2.7.0 + * @todo remove at version 3 + * @private + */ +helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault; + +},{}],43:[function(require,module,exports){ +'use strict'; + +var helpers = require(42); + +/** + * Easing functions adapted from Robert Penner's easing equations. + * @namespace Chart.helpers.easingEffects + * @see http://www.robertpenner.com/easing/ + */ +var effects = { + linear: function(t) { + return t; + }, + + easeInQuad: function(t) { + return t * t; + }, + + easeOutQuad: function(t) { + return -t * (t - 2); + }, + + easeInOutQuad: function(t) { + if ((t /= 0.5) < 1) { + return 0.5 * t * t; + } + return -0.5 * ((--t) * (t - 2) - 1); + }, + + easeInCubic: function(t) { + return t * t * t; + }, + + easeOutCubic: function(t) { + return (t = t - 1) * t * t + 1; + }, + + easeInOutCubic: function(t) { + if ((t /= 0.5) < 1) { + return 0.5 * t * t * t; + } + return 0.5 * ((t -= 2) * t * t + 2); + }, + + easeInQuart: function(t) { + return t * t * t * t; + }, + + easeOutQuart: function(t) { + return -((t = t - 1) * t * t * t - 1); + }, + + easeInOutQuart: function(t) { + if ((t /= 0.5) < 1) { + return 0.5 * t * t * t * t; + } + return -0.5 * ((t -= 2) * t * t * t - 2); + }, + + easeInQuint: function(t) { + return t * t * t * t * t; + }, + + easeOutQuint: function(t) { + return (t = t - 1) * t * t * t * t + 1; + }, + + easeInOutQuint: function(t) { + if ((t /= 0.5) < 1) { + return 0.5 * t * t * t * t * t; + } + return 0.5 * ((t -= 2) * t * t * t * t + 2); + }, + + easeInSine: function(t) { + return -Math.cos(t * (Math.PI / 2)) + 1; + }, + + easeOutSine: function(t) { + return Math.sin(t * (Math.PI / 2)); + }, + + easeInOutSine: function(t) { + return -0.5 * (Math.cos(Math.PI * t) - 1); + }, + + easeInExpo: function(t) { + return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)); + }, + + easeOutExpo: function(t) { + return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1; + }, + + easeInOutExpo: function(t) { + if (t === 0) { + return 0; + } + if (t === 1) { + return 1; + } + if ((t /= 0.5) < 1) { + return 0.5 * Math.pow(2, 10 * (t - 1)); + } + return 0.5 * (-Math.pow(2, -10 * --t) + 2); + }, + + easeInCirc: function(t) { + if (t >= 1) { + return t; + } + return -(Math.sqrt(1 - t * t) - 1); + }, + + easeOutCirc: function(t) { + return Math.sqrt(1 - (t = t - 1) * t); + }, + + easeInOutCirc: function(t) { + if ((t /= 0.5) < 1) { + return -0.5 * (Math.sqrt(1 - t * t) - 1); + } + return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); + }, + + easeInElastic: function(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if (t === 1) { + return 1; + } + if (!p) { + p = 0.3; + } + if (a < 1) { + a = 1; + s = p / 4; + } else { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)); + }, + + easeOutElastic: function(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if (t === 1) { + return 1; + } + if (!p) { + p = 0.3; + } + if (a < 1) { + a = 1; + s = p / 4; + } else { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1; + }, + + easeInOutElastic: function(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if ((t /= 0.5) === 2) { + return 1; + } + if (!p) { + p = 0.45; + } + if (a < 1) { + a = 1; + s = p / 4; + } else { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + if (t < 1) { + return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)); + } + return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1; + }, + easeInBack: function(t) { + var s = 1.70158; + return t * t * ((s + 1) * t - s); + }, + + easeOutBack: function(t) { + var s = 1.70158; + return (t = t - 1) * t * ((s + 1) * t + s) + 1; + }, + + easeInOutBack: function(t) { + var s = 1.70158; + if ((t /= 0.5) < 1) { + return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s)); + } + return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2); + }, + + easeInBounce: function(t) { + return 1 - effects.easeOutBounce(1 - t); + }, + + easeOutBounce: function(t) { + if (t < (1 / 2.75)) { + return 7.5625 * t * t; + } + if (t < (2 / 2.75)) { + return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75; + } + if (t < (2.5 / 2.75)) { + return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375; + } + return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375; + }, + + easeInOutBounce: function(t) { + if (t < 0.5) { + return effects.easeInBounce(t * 2) * 0.5; + } + return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5; + } +}; + +module.exports = { + effects: effects +}; + +// DEPRECATIONS + +/** + * Provided for backward compatibility, use Chart.helpers.easing.effects instead. + * @function Chart.helpers.easingEffects + * @deprecated since version 2.7.0 + * @todo remove at version 3 + * @private + */ +helpers.easingEffects = effects; + +},{"42":42}],44:[function(require,module,exports){ +'use strict'; + +var helpers = require(42); + +/** + * @alias Chart.helpers.options + * @namespace + */ +module.exports = { + /** + * Converts the given line height `value` in pixels for a specific font `size`. + * @param {Number|String} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em'). + * @param {Number} size - The font size (in pixels) used to resolve relative `value`. + * @returns {Number} The effective line height in pixels (size * 1.2 if value is invalid). + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height + * @since 2.7.0 + */ + toLineHeight: function(value, size) { + var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); + if (!matches || matches[1] === 'normal') { + return size * 1.2; + } + + value = +matches[2]; + + switch (matches[3]) { + case 'px': + return value; + case '%': + value /= 100; + break; + default: + break; + } + + return size * value; + }, + + /** + * Converts the given value into a padding object with pre-computed width/height. + * @param {Number|Object} value - If a number, set the value to all TRBL component, + * else, if and object, use defined properties and sets undefined ones to 0. + * @returns {Object} The padding values (top, right, bottom, left, width, height) + * @since 2.7.0 + */ + toPadding: function(value) { + var t, r, b, l; + + if (helpers.isObject(value)) { + t = +value.top || 0; + r = +value.right || 0; + b = +value.bottom || 0; + l = +value.left || 0; + } else { + t = r = b = l = +value || 0; + } + + return { + top: t, + right: r, + bottom: b, + left: l, + height: t + b, + width: l + r + }; + }, + + /** + * Evaluates the given `inputs` sequentially and returns the first defined value. + * @param {Array[]} inputs - An array of values, falling back to the last value. + * @param {Object} [context] - If defined and the current value is a function, the value + * is called with `context` as first argument and the result becomes the new input. + * @param {Number} [index] - If defined and the current value is an array, the value + * at `index` become the new input. + * @since 2.7.0 + */ + resolve: function(inputs, context, index) { + var i, ilen, value; + + for (i = 0, ilen = inputs.length; i < ilen; ++i) { + value = inputs[i]; + if (value === undefined) { + continue; + } + if (context !== undefined && typeof value === 'function') { + value = value(context); + } + if (index !== undefined && helpers.isArray(value)) { + value = value[index]; + } + if (value !== undefined) { + return value; + } + } + } +}; + +},{"42":42}],45:[function(require,module,exports){ +'use strict'; + +module.exports = require(42); +module.exports.easing = require(43); +module.exports.canvas = require(41); +module.exports.options = require(44); + +},{"41":41,"42":42,"43":43,"44":44}],46:[function(require,module,exports){ +/** + * Platform fallback implementation (minimal). + * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939 + */ + +module.exports = { + acquireContext: function(item) { + if (item && item.canvas) { + // Support for any object associated to a canvas (including a context2d) + item = item.canvas; + } + + return item && item.getContext('2d') || null; + } +}; + +},{}],47:[function(require,module,exports){ +/** + * Chart.Platform implementation for targeting a web browser + */ + +'use strict'; + +var helpers = require(45); + +var EXPANDO_KEY = '$chartjs'; +var CSS_PREFIX = 'chartjs-'; +var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor'; +var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation'; +var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart']; + +/** + * DOM event types -> Chart.js event types. + * Note: only events with different types are mapped. + * @see https://developer.mozilla.org/en-US/docs/Web/Events + */ +var EVENT_TYPES = { + touchstart: 'mousedown', + touchmove: 'mousemove', + touchend: 'mouseup', + pointerenter: 'mouseenter', + pointerdown: 'mousedown', + pointermove: 'mousemove', + pointerup: 'mouseup', + pointerleave: 'mouseout', + pointerout: 'mouseout' +}; + +/** + * The "used" size is the final value of a dimension property after all calculations have + * been performed. This method uses the computed style of `element` but returns undefined + * if the computed style is not expressed in pixels. That can happen in some cases where + * `element` has a size relative to its parent and this last one is not yet displayed, + * for example because of `display: none` on a parent node. + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value + * @returns {Number} Size in pixels or undefined if unknown. + */ +function readUsedSize(element, property) { + var value = helpers.getStyle(element, property); + var matches = value && value.match(/^(\d+)(\.\d+)?px$/); + return matches ? Number(matches[1]) : undefined; +} + +/** + * Initializes the canvas style and render size without modifying the canvas display size, + * since responsiveness is handled by the controller.resize() method. The config is used + * to determine the aspect ratio to apply in case no explicit height has been specified. + */ +function initCanvas(canvas, config) { + var style = canvas.style; + + // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it + // returns null or '' if no explicit value has been set to the canvas attribute. + var renderHeight = canvas.getAttribute('height'); + var renderWidth = canvas.getAttribute('width'); + + // Chart.js modifies some canvas values that we want to restore on destroy + canvas[EXPANDO_KEY] = { + initial: { + height: renderHeight, + width: renderWidth, + style: { + display: style.display, + height: style.height, + width: style.width + } + } + }; + + // Force canvas to display as block to avoid extra space caused by inline + // elements, which would interfere with the responsive resize process. + // https://github.com/chartjs/Chart.js/issues/2538 + style.display = style.display || 'block'; + + if (renderWidth === null || renderWidth === '') { + var displayWidth = readUsedSize(canvas, 'width'); + if (displayWidth !== undefined) { + canvas.width = displayWidth; + } + } + + if (renderHeight === null || renderHeight === '') { + if (canvas.style.height === '') { + // If no explicit render height and style height, let's apply the aspect ratio, + // which one can be specified by the user but also by charts as default option + // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2. + canvas.height = canvas.width / (config.options.aspectRatio || 2); + } else { + var displayHeight = readUsedSize(canvas, 'height'); + if (displayWidth !== undefined) { + canvas.height = displayHeight; + } + } + } + + return canvas; +} + +/** + * Detects support for options object argument in addEventListener. + * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support + * @private + */ +var supportsEventListenerOptions = (function() { + var supports = false; + try { + var options = Object.defineProperty({}, 'passive', { + get: function() { + supports = true; + } + }); + window.addEventListener('e', null, options); + } catch (e) { + // continue regardless of error + } + return supports; +}()); + +// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events. +// https://github.com/chartjs/Chart.js/issues/4287 +var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false; + +function addEventListener(node, type, listener) { + node.addEventListener(type, listener, eventListenerOptions); +} + +function removeEventListener(node, type, listener) { + node.removeEventListener(type, listener, eventListenerOptions); +} + +function createEvent(type, chart, x, y, nativeEvent) { + return { + type: type, + chart: chart, + native: nativeEvent || null, + x: x !== undefined ? x : null, + y: y !== undefined ? y : null, + }; +} + +function fromNativeEvent(event, chart) { + var type = EVENT_TYPES[event.type] || event.type; + var pos = helpers.getRelativePosition(event, chart); + return createEvent(type, chart, pos.x, pos.y, event); +} + +function throttled(fn, thisArg) { + var ticking = false; + var args = []; + + return function() { + args = Array.prototype.slice.call(arguments); + thisArg = thisArg || this; + + if (!ticking) { + ticking = true; + helpers.requestAnimFrame.call(window, function() { + ticking = false; + fn.apply(thisArg, args); + }); + } + }; +} + +// Implementation based on https://github.com/marcj/css-element-queries +function createResizer(handler) { + var resizer = document.createElement('div'); + var cls = CSS_PREFIX + 'size-monitor'; + var maxSize = 1000000; + var style = + 'position:absolute;' + + 'left:0;' + + 'top:0;' + + 'right:0;' + + 'bottom:0;' + + 'overflow:hidden;' + + 'pointer-events:none;' + + 'visibility:hidden;' + + 'z-index:-1;'; + + resizer.style.cssText = style; + resizer.className = cls; + resizer.innerHTML = + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
'; + + var expand = resizer.childNodes[0]; + var shrink = resizer.childNodes[1]; + + resizer._reset = function() { + expand.scrollLeft = maxSize; + expand.scrollTop = maxSize; + shrink.scrollLeft = maxSize; + shrink.scrollTop = maxSize; + }; + var onScroll = function() { + resizer._reset(); + handler(); + }; + + addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand')); + addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink')); + + return resizer; +} + +// https://davidwalsh.name/detect-node-insertion +function watchForRender(node, handler) { + var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {}); + var proxy = expando.renderProxy = function(e) { + if (e.animationName === CSS_RENDER_ANIMATION) { + handler(); + } + }; + + helpers.each(ANIMATION_START_EVENTS, function(type) { + 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); +} + +function unwatchForRender(node) { + var expando = node[EXPANDO_KEY] || {}; + var proxy = expando.renderProxy; + + if (proxy) { + helpers.each(ANIMATION_START_EVENTS, function(type) { + removeEventListener(node, type, proxy); + }); + + delete expando.renderProxy; + } + + node.classList.remove(CSS_RENDER_MONITOR); +} + +function addResizeListener(node, listener, chart) { + var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {}); + + // Let's keep track of this added resizer and thus avoid DOM query when removing it. + var resizer = expando.resizer = createResizer(throttled(function() { + if (expando.resizer) { + return listener(createEvent('resize', chart)); + } + })); + + // The resizer needs to be attached to the node parent, so we first need to be + // sure that `node` is attached to the DOM before injecting the resizer element. + watchForRender(node, function() { + if (expando.resizer) { + var container = node.parentNode; + if (container && container !== resizer.parentNode) { + container.insertBefore(resizer, container.firstChild); + } + + // The container size might have changed, let's reset the resizer state. + resizer._reset(); + } + }); +} + +function removeResizeListener(node) { + var expando = node[EXPANDO_KEY] || {}; + var resizer = expando.resizer; + + delete expando.resizer; + unwatchForRender(node); + + if (resizer && resizer.parentNode) { + resizer.parentNode.removeChild(resizer); + } +} + +function injectCSS(platform, css) { + // http://stackoverflow.com/q/3922139 + var style = platform._style || document.createElement('style'); + if (!platform._style) { + platform._style = style; + css = '/* Chart.js */\n' + css; + style.setAttribute('type', 'text/css'); + document.getElementsByTagName('head')[0].appendChild(style); + } + + style.appendChild(document.createTextNode(css)); +} + +module.exports = { + /** + * This property holds whether this platform is enabled for the current environment. + * Currently used by platform.js to select the proper implementation. + * @private + */ + _enabled: typeof window !== 'undefined' && typeof document !== 'undefined', + + initialize: function() { + var keyframes = 'from{opacity:0.99}to{opacity:1}'; + + injectCSS(this, + // DOM rendering detection + // https://davidwalsh.name/detect-node-insertion + '@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' + + '@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' + + '.' + CSS_RENDER_MONITOR + '{' + + '-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' + + 'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' + + '}' + ); + }, + + acquireContext: function(item, config) { + if (typeof item === 'string') { + item = document.getElementById(item); + } else if (item.length) { + // Support for array based queries (such as jQuery) + item = item[0]; + } + + if (item && item.canvas) { + // Support for any object associated to a canvas (including a context2d) + item = item.canvas; + } + + // To prevent canvas fingerprinting, some add-ons undefine the getContext + // method, for example: https://github.com/kkapsner/CanvasBlocker + // https://github.com/chartjs/Chart.js/issues/2807 + var context = item && item.getContext && item.getContext('2d'); + + // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is + // inside an iframe or when running in a protected environment. We could guess the + // types from their toString() value but let's keep things flexible and assume it's + // a sufficient condition if the item has a context2D which has item as `canvas`. + // https://github.com/chartjs/Chart.js/issues/3887 + // https://github.com/chartjs/Chart.js/issues/4102 + // https://github.com/chartjs/Chart.js/issues/4152 + if (context && context.canvas === item) { + initCanvas(item, config); + return context; + } + + return null; + }, + + releaseContext: function(context) { + var canvas = context.canvas; + if (!canvas[EXPANDO_KEY]) { + return; + } + + var initial = canvas[EXPANDO_KEY].initial; + ['height', 'width'].forEach(function(prop) { + var value = initial[prop]; + if (helpers.isNullOrUndef(value)) { + canvas.removeAttribute(prop); + } else { + canvas.setAttribute(prop, value); + } + }); + + helpers.each(initial.style || {}, function(value, key) { + canvas.style[key] = value; + }); + + // The canvas render size might have been changed (and thus the state stack discarded), + // we can't use save() and restore() to restore the initial state. So make sure that at + // least the canvas context is reset to the default state by setting the canvas width. + // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html + canvas.width = canvas.width; + + delete canvas[EXPANDO_KEY]; + }, + + addEventListener: function(chart, type, listener) { + var canvas = chart.canvas; + if (type === 'resize') { + // Note: the resize event is not supported on all browsers. + addResizeListener(canvas, listener, chart); + return; + } + + var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {}); + var proxies = expando.proxies || (expando.proxies = {}); + var proxy = proxies[chart.id + '_' + type] = function(event) { + listener(fromNativeEvent(event, chart)); + }; + + addEventListener(canvas, type, proxy); + }, + + removeEventListener: function(chart, type, listener) { + var canvas = chart.canvas; + if (type === 'resize') { + // Note: the resize event is not supported on all browsers. + removeResizeListener(canvas, listener); + return; + } + + var expando = listener[EXPANDO_KEY] || {}; + var proxies = expando.proxies || {}; + var proxy = proxies[chart.id + '_' + type]; + if (!proxy) { + return; + } + + removeEventListener(canvas, type, proxy); + } +}; + +// DEPRECATIONS + +/** + * Provided for backward compatibility, use EventTarget.addEventListener instead. + * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+ + * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener + * @function Chart.helpers.addEvent + * @deprecated since version 2.7.0 + * @todo remove at version 3 + * @private + */ +helpers.addEvent = addEventListener; + +/** + * Provided for backward compatibility, use EventTarget.removeEventListener instead. + * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+ + * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener + * @function Chart.helpers.removeEvent + * @deprecated since version 2.7.0 + * @todo remove at version 3 + * @private + */ +helpers.removeEvent = removeEventListener; + +},{"45":45}],48:[function(require,module,exports){ +'use strict'; + +var helpers = require(45); +var basic = require(46); +var dom = require(47); + +// @TODO Make possible to select another platform at build time. +var implementation = dom._enabled ? dom : basic; + +/** + * @namespace Chart.platform + * @see https://chartjs.gitbooks.io/proposals/content/Platform.html + * @since 2.4.0 + */ +module.exports = helpers.extend({ + /** + * @since 2.7.0 + */ + initialize: function() {}, + + /** + * Called at chart construction time, returns a context2d instance implementing + * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}. + * @param {*} item - The native item from which to acquire context (platform specific) + * @param {Object} options - The chart options + * @returns {CanvasRenderingContext2D} context2d instance + */ + acquireContext: function() {}, + + /** + * Called at chart destruction time, releases any resources associated to the context + * previously returned by the acquireContext() method. + * @param {CanvasRenderingContext2D} context - The context2d instance + * @returns {Boolean} true if the method succeeded, else false + */ + releaseContext: function() {}, + + /** + * Registers the specified listener on the given chart. + * @param {Chart} chart - Chart from which to listen for event + * @param {String} type - The ({@link IEvent}) type to listen for + * @param {Function} listener - Receives a notification (an object that implements + * the {@link IEvent} interface) when an event of the specified type occurs. + */ + addEventListener: function() {}, + + /** + * Removes the specified listener previously registered with addEventListener. + * @param {Chart} chart -Chart from which to remove the listener + * @param {String} type - The ({@link IEvent}) type to remove + * @param {Function} listener - The listener function to remove from the event target. + */ + removeEventListener: function() {} + +}, implementation); + +/** + * @interface IPlatform + * Allows abstracting platform dependencies away from the chart + * @borrows Chart.platform.acquireContext as acquireContext + * @borrows Chart.platform.releaseContext as releaseContext + * @borrows Chart.platform.addEventListener as addEventListener + * @borrows Chart.platform.removeEventListener as removeEventListener + */ + +/** + * @interface IEvent + * @prop {String} type - The event type name, possible values are: + * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout', + * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize' + * @prop {*} native - The original native event (null for emulated events, e.g. 'resize') + * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events) + * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events) + */ + +},{"45":45,"46":46,"47":47}],49:[function(require,module,exports){ +/** + * Plugin based on discussion from the following Chart.js issues: + * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569 + * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897 + */ + +'use strict'; + +var defaults = require(25); +var elements = require(40); +var helpers = require(45); + +defaults._set('global', { + plugins: { + filler: { + propagate: true + } + } +}); + +module.exports = function() { + + var mappers = { + dataset: function(source) { + var index = source.fill; + var chart = source.chart; + var meta = chart.getDatasetMeta(index); + var visible = meta && chart.isDatasetVisible(index); + var points = (visible && meta.dataset._children) || []; + var length = points.length || 0; + + return !length ? null : function(point, i) { + return (i < length && points[i]._view) || null; + }; + }, + + boundary: function(source) { + var boundary = source.boundary; + var x = boundary ? boundary.x : null; + var y = boundary ? boundary.y : null; + + return function(point) { + return { + x: x === null ? point.x : x, + y: y === null ? point.y : y, + }; + }; + } + }; + + // @todo if (fill[0] === '#') + function decodeFill(el, index, count) { + var model = el._model || {}; + var fill = model.fill; + var target; + + if (fill === undefined) { + fill = !!model.backgroundColor; + } + + if (fill === false || fill === null) { + return false; + } + + if (fill === true) { + return 'origin'; + } + + target = parseFloat(fill, 10); + if (isFinite(target) && Math.floor(target) === target) { + if (fill[0] === '-' || fill[0] === '+') { + target = index + target; + } + + if (target === index || target < 0 || target >= count) { + return false; + } + + return target; + } + + switch (fill) { + // compatibility + case 'bottom': + return 'start'; + case 'top': + return 'end'; + case 'zero': + return 'origin'; + // supported boundaries + case 'origin': + case 'start': + case 'end': + return fill; + // invalid fill values + default: + return false; + } + } + + function computeBoundary(source) { + var model = source.el._model || {}; + var scale = source.el._scale || {}; + var fill = source.fill; + var target = null; + var horizontal; + + if (isFinite(fill)) { + return null; + } + + // Backward compatibility: until v3, we still need to support boundary values set on + // the model (scaleTop, scaleBottom and scaleZero) because some external plugins and + // controllers might still use it (e.g. the Smith chart). + + if (fill === 'start') { + target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom; + } else if (fill === 'end') { + target = model.scaleTop === undefined ? scale.top : model.scaleTop; + } else if (model.scaleZero !== undefined) { + target = model.scaleZero; + } else if (scale.getBasePosition) { + target = scale.getBasePosition(); + } else if (scale.getBasePixel) { + target = scale.getBasePixel(); + } + + if (target !== undefined && target !== null) { + if (target.x !== undefined && target.y !== undefined) { + return target; + } + + if (typeof target === 'number' && isFinite(target)) { + horizontal = scale.isHorizontal(); + return { + x: horizontal ? target : null, + y: horizontal ? null : target + }; + } + } + + return null; + } + + function resolveTarget(sources, index, propagate) { + var source = sources[index]; + var fill = source.fill; + var visited = [index]; + var target; + + if (!propagate) { + return fill; + } + + while (fill !== false && visited.indexOf(fill) === -1) { + if (!isFinite(fill)) { + return fill; + } + + target = sources[fill]; + if (!target) { + return false; + } + + if (target.visible) { + return fill; + } + + visited.push(fill); + fill = target.fill; + } + + return false; + } + + function createMapper(source) { + var fill = source.fill; + var type = 'dataset'; + + if (fill === false) { + return null; + } + + if (!isFinite(fill)) { + type = 'boundary'; + } + + return mappers[type](source); + } + + function isDrawable(point) { + return point && !point.skip; + } + + function drawArea(ctx, curve0, curve1, len0, len1) { + var i; + + if (!len0 || !len1) { + return; + } + + // building first area curve (normal) + ctx.moveTo(curve0[0].x, curve0[0].y); + for (i = 1; i < len0; ++i) { + helpers.canvas.lineTo(ctx, curve0[i - 1], curve0[i]); + } + + // joining the two area curves + ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y); + + // building opposite area curve (reverse) + for (i = len1 - 1; i > 0; --i) { + helpers.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true); + } + } + + function doFill(ctx, points, mapper, view, color, loop) { + var count = points.length; + var span = view.spanGaps; + var curve0 = []; + var curve1 = []; + var len0 = 0; + var len1 = 0; + var i, ilen, index, p0, p1, d0, d1; + + ctx.beginPath(); + + for (i = 0, ilen = (count + !!loop); i < ilen; ++i) { + index = i % count; + p0 = points[index]._view; + p1 = mapper(p0, index, view); + d0 = isDrawable(p0); + d1 = isDrawable(p1); + + if (d0 && d1) { + len0 = curve0.push(p0); + len1 = curve1.push(p1); + } else if (len0 && len1) { + if (!span) { + drawArea(ctx, curve0, curve1, len0, len1); + len0 = len1 = 0; + curve0 = []; + curve1 = []; + } else { + if (d0) { + curve0.push(p0); + } + if (d1) { + curve1.push(p1); + } + } + } + } + + drawArea(ctx, curve0, curve1, len0, len1); + + ctx.closePath(); + ctx.fillStyle = color; + ctx.fill(); + } + + return { + id: 'filler', + + afterDatasetsUpdate: function(chart, options) { + var count = (chart.data.datasets || []).length; + var propagate = options.propagate; + var sources = []; + var meta, i, el, source; + + for (i = 0; i < count; ++i) { + meta = chart.getDatasetMeta(i); + el = meta.dataset; + source = null; + + if (el && el._model && el instanceof elements.Line) { + source = { + visible: chart.isDatasetVisible(i), + fill: decodeFill(el, i, count), + chart: chart, + el: el + }; + } + + meta.$filler = source; + sources.push(source); + } + + for (i = 0; i < count; ++i) { + source = sources[i]; + if (!source) { + continue; + } + + source.fill = resolveTarget(sources, i, propagate); + source.boundary = computeBoundary(source); + source.mapper = createMapper(source); + } + }, + + beforeDatasetDraw: function(chart, args) { + var meta = args.meta.$filler; + if (!meta) { + return; + } + + var ctx = chart.ctx; + var el = meta.el; + var view = el._view; + var points = el._children || []; + var mapper = meta.mapper; + var color = view.backgroundColor || defaults.global.defaultColor; + + if (mapper && color && points.length) { + helpers.canvas.clipArea(ctx, chart.chartArea); + doFill(ctx, points, mapper, view, color, el._loop); + helpers.canvas.unclipArea(ctx); + } + } + }; +}; + +},{"25":25,"40":40,"45":45}],50:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); + +defaults._set('global', { + legend: { + display: true, + position: 'top', + fullWidth: true, + reverse: false, + weight: 1000, + + // a callback that will handle + onClick: function(e, legendItem) { + var index = legendItem.datasetIndex; + var ci = this.chart; + var meta = ci.getDatasetMeta(index); + + // See controller.isDatasetVisible comment + meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null; + + // We hid a dataset ... rerender the chart + ci.update(); + }, + + onHover: null, + + labels: { + boxWidth: 40, + padding: 10, + // Generates labels shown in the legend + // Valid properties to return: + // text : text to display + // fillStyle : fill of coloured box + // strokeStyle: stroke of coloured box + // hidden : if this legend item refers to a hidden item + // lineCap : cap style for line + // lineDash + // lineDashOffset : + // lineJoin : + // lineWidth : + generateLabels: function(chart) { + var data = chart.data; + return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) { + return { + text: dataset.label, + fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]), + hidden: !chart.isDatasetVisible(i), + lineCap: dataset.borderCapStyle, + lineDash: dataset.borderDash, + lineDashOffset: dataset.borderDashOffset, + lineJoin: dataset.borderJoinStyle, + lineWidth: dataset.borderWidth, + strokeStyle: dataset.borderColor, + pointStyle: dataset.pointStyle, + + // Below is extra data used for toggling the datasets + datasetIndex: i + }; + }, this) : []; + } + } + }, + + legendCallback: function(chart) { + var text = []; + text.push('
    '); + for (var i = 0; i < chart.data.datasets.length; i++) { + text.push('
  • '); + if (chart.data.datasets[i].label) { + text.push(chart.data.datasets[i].label); + } + text.push('
  • '); + } + text.push('
'); + return text.join(''); + } +}); + +module.exports = function(Chart) { + + var layout = Chart.layoutService; + var noop = helpers.noop; + + /** + * Helper function to get the box width based on the usePointStyle option + * @param labelopts {Object} the label options on the legend + * @param fontSize {Number} the label font size + * @return {Number} width of the color box area + */ + function getBoxWidth(labelOpts, fontSize) { + return labelOpts.usePointStyle ? + fontSize * Math.SQRT2 : + labelOpts.boxWidth; + } + + Chart.Legend = Element.extend({ + + initialize: function(config) { + helpers.extend(this, config); + + // Contains hit boxes for each dataset (in dataset order) + this.legendHitBoxes = []; + + // Are we in doughnut mode which has a different data type + this.doughnutMode = false; + }, + + // These methods are ordered by lifecycle. Utilities then follow. + // Any function defined here is inherited by all legend types. + // Any function can be extended by the legend type + + beforeUpdate: noop, + update: function(maxWidth, maxHeight, margins) { + var me = this; + + // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) + me.beforeUpdate(); + + // Absorb the master measurements + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me.margins = margins; + + // Dimensions + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + // Labels + me.beforeBuildLabels(); + me.buildLabels(); + me.afterBuildLabels(); + + // Fit + me.beforeFit(); + me.fit(); + me.afterFit(); + // + me.afterUpdate(); + + return me.minSize; + }, + afterUpdate: noop, + + // + + beforeSetDimensions: noop, + setDimensions: function() { + var me = this; + // Set the unconstrained dimension before label rotation + if (me.isHorizontal()) { + // Reset position before calculating rotation + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + + // Reset position before calculating rotation + me.top = 0; + me.bottom = me.height; + } + + // Reset padding + me.paddingLeft = 0; + me.paddingTop = 0; + me.paddingRight = 0; + me.paddingBottom = 0; + + // Reset minSize + me.minSize = { + width: 0, + height: 0 + }; + }, + afterSetDimensions: noop, + + // + + beforeBuildLabels: noop, + buildLabels: function() { + var me = this; + var labelOpts = me.options.labels || {}; + var legendItems = helpers.callback(labelOpts.generateLabels, [me.chart], me) || []; + + if (labelOpts.filter) { + legendItems = legendItems.filter(function(item) { + return labelOpts.filter(item, me.chart.data); + }); + } + + if (me.options.reverse) { + legendItems.reverse(); + } + + me.legendItems = legendItems; + }, + afterBuildLabels: noop, + + // + + beforeFit: noop, + fit: function() { + var me = this; + var opts = me.options; + var labelOpts = opts.labels; + var display = opts.display; + + var ctx = me.ctx; + + var globalDefault = defaults.global; + var valueOrDefault = helpers.valueOrDefault; + var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize); + var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle); + var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily); + var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily); + + // Reset hit boxes + var hitboxes = me.legendHitBoxes = []; + + var minSize = me.minSize; + var isHorizontal = me.isHorizontal(); + + if (isHorizontal) { + minSize.width = me.maxWidth; // fill all the width + minSize.height = display ? 10 : 0; + } else { + minSize.width = display ? 10 : 0; + minSize.height = me.maxHeight; // fill all the height + } + + // Increase sizes here + if (display) { + ctx.font = labelFont; + + if (isHorizontal) { + // Labels + + // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one + var lineWidths = me.lineWidths = [0]; + var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0; + + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; + + helpers.each(me.legendItems, function(legendItem, i) { + var boxWidth = getBoxWidth(labelOpts, fontSize); + var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + + if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) { + totalHeight += fontSize + (labelOpts.padding); + lineWidths[lineWidths.length] = me.left; + } + + // Store the hitbox width and height here. Final position will be updated in `draw` + hitboxes[i] = { + left: 0, + top: 0, + width: width, + height: fontSize + }; + + lineWidths[lineWidths.length - 1] += width + labelOpts.padding; + }); + + minSize.height += totalHeight; + + } else { + var vPadding = labelOpts.padding; + var columnWidths = me.columnWidths = []; + var totalWidth = labelOpts.padding; + var currentColWidth = 0; + var currentColHeight = 0; + var itemHeight = fontSize + vPadding; + + helpers.each(me.legendItems, function(legendItem, i) { + var boxWidth = getBoxWidth(labelOpts, fontSize); + var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + + // If too tall, go to new column + if (currentColHeight + itemHeight > minSize.height) { + totalWidth += currentColWidth + labelOpts.padding; + columnWidths.push(currentColWidth); // previous column width + + currentColWidth = 0; + currentColHeight = 0; + } + + // Get max width + currentColWidth = Math.max(currentColWidth, itemWidth); + currentColHeight += itemHeight; + + // Store the hitbox width and height here. Final position will be updated in `draw` + hitboxes[i] = { + left: 0, + top: 0, + width: itemWidth, + height: fontSize + }; + }); + + totalWidth += currentColWidth; + columnWidths.push(currentColWidth); + minSize.width += totalWidth; + } + } + + me.width = minSize.width; + me.height = minSize.height; + }, + afterFit: noop, + + // Shared Methods + isHorizontal: function() { + return this.options.position === 'top' || this.options.position === 'bottom'; + }, + + // Actually draw the legend on the canvas + draw: function() { + var me = this; + var opts = me.options; + var labelOpts = opts.labels; + var globalDefault = defaults.global; + var lineDefault = globalDefault.elements.line; + var legendWidth = me.width; + var lineWidths = me.lineWidths; + + if (opts.display) { + var ctx = me.ctx; + var valueOrDefault = helpers.valueOrDefault; + var fontColor = valueOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor); + var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize); + var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle); + var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily); + var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily); + var cursor; + + // Canvas setup + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + ctx.lineWidth = 0.5; + ctx.strokeStyle = fontColor; // for strikethrough effect + ctx.fillStyle = fontColor; // render in correct colour + ctx.font = labelFont; + + var boxWidth = getBoxWidth(labelOpts, fontSize); + var hitboxes = me.legendHitBoxes; + + // current position + var drawLegendBox = function(x, y, legendItem) { + if (isNaN(boxWidth) || boxWidth <= 0) { + return; + } + + // Set the ctx for the box + ctx.save(); + + ctx.fillStyle = valueOrDefault(legendItem.fillStyle, globalDefault.defaultColor); + ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle); + ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset); + ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle); + ctx.lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth); + ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, globalDefault.defaultColor); + var isLineWidthZero = (valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0); + + if (ctx.setLineDash) { + // IE 9 and 10 do not support line dash + ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash)); + } + + if (opts.labels && opts.labels.usePointStyle) { + // Recalculate x and y for drawPoint() because its expecting + // x and y to be center of figure (instead of top left) + var radius = fontSize * Math.SQRT2 / 2; + var offSet = radius / Math.SQRT2; + var centerX = x + offSet; + var centerY = y + offSet; + + // Draw pointStyle as legend symbol + helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY); + } else { + // Draw box as legend symbol + if (!isLineWidthZero) { + ctx.strokeRect(x, y, boxWidth, fontSize); + } + ctx.fillRect(x, y, boxWidth, fontSize); + } + + ctx.restore(); + }; + var fillText = function(x, y, legendItem, textWidth) { + var halfFontSize = fontSize / 2; + var xLeft = boxWidth + halfFontSize + x; + var yMiddle = y + halfFontSize; + + ctx.fillText(legendItem.text, xLeft, yMiddle); + + if (legendItem.hidden) { + // Strikethrough the text if hidden + ctx.beginPath(); + ctx.lineWidth = 2; + ctx.moveTo(xLeft, yMiddle); + ctx.lineTo(xLeft + textWidth, yMiddle); + ctx.stroke(); + } + }; + + // Horizontal + var isHorizontal = me.isHorizontal(); + if (isHorizontal) { + cursor = { + x: me.left + ((legendWidth - lineWidths[0]) / 2), + y: me.top + labelOpts.padding, + line: 0 + }; + } else { + cursor = { + x: me.left + labelOpts.padding, + y: me.top + labelOpts.padding, + line: 0 + }; + } + + var itemHeight = fontSize + labelOpts.padding; + helpers.each(me.legendItems, function(legendItem, i) { + var textWidth = ctx.measureText(legendItem.text).width; + var width = boxWidth + (fontSize / 2) + textWidth; + var x = cursor.x; + var y = cursor.y; + + if (isHorizontal) { + if (x + width >= legendWidth) { + y = cursor.y += itemHeight; + cursor.line++; + x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2); + } + } else if (y + itemHeight > me.bottom) { + x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding; + y = cursor.y = me.top + labelOpts.padding; + cursor.line++; + } + + drawLegendBox(x, y, legendItem); + + hitboxes[i].left = x; + hitboxes[i].top = y; + + // Fill the actual label + fillText(x, y, legendItem, textWidth); + + if (isHorizontal) { + cursor.x += width + (labelOpts.padding); + } else { + cursor.y += itemHeight; + } + + }); + } + }, + + /** + * Handle an event + * @private + * @param {IEvent} event - The event to handle + * @return {Boolean} true if a change occured + */ + handleEvent: function(e) { + var me = this; + var opts = me.options; + var type = e.type === 'mouseup' ? 'click' : e.type; + var changed = false; + + if (type === 'mousemove') { + if (!opts.onHover) { + return; + } + } else if (type === 'click') { + if (!opts.onClick) { + return; + } + } else { + return; + } + + // Chart event already has relative position in it + var x = e.x; + var y = e.y; + + if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) { + // See if we are touching one of the dataset boxes + var lh = me.legendHitBoxes; + for (var i = 0; i < lh.length; ++i) { + var hitBox = lh[i]; + + if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) { + // Touching an element + if (type === 'click') { + // use e.native for backwards compatibility + opts.onClick.call(me, e.native, me.legendItems[i]); + changed = true; + break; + } else if (type === 'mousemove') { + // use e.native for backwards compatibility + opts.onHover.call(me, e.native, me.legendItems[i]); + changed = true; + break; + } + } + } + } + + return changed; + } + }); + + function createNewLegendAndAttach(chart, legendOpts) { + var legend = new Chart.Legend({ + ctx: chart.ctx, + options: legendOpts, + chart: chart + }); + + layout.configure(chart, legend, legendOpts); + layout.addBox(chart, legend); + chart.legend = legend; + } + + return { + id: 'legend', + + beforeInit: function(chart) { + var legendOpts = chart.options.legend; + + if (legendOpts) { + createNewLegendAndAttach(chart, legendOpts); + } + }, + + beforeUpdate: function(chart) { + var legendOpts = chart.options.legend; + var legend = chart.legend; + + if (legendOpts) { + helpers.mergeIf(legendOpts, defaults.global.legend); + + if (legend) { + layout.configure(chart, legend, legendOpts); + legend.options = legendOpts; + } else { + createNewLegendAndAttach(chart, legendOpts); + } + } else if (legend) { + layout.removeBox(chart, legend); + delete chart.legend; + } + }, + + afterEvent: function(chart, e) { + var legend = chart.legend; + if (legend) { + legend.handleEvent(e); + } + } + }; +}; + +},{"25":25,"26":26,"45":45}],51:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var Element = require(26); +var helpers = require(45); + +defaults._set('global', { + title: { + display: false, + fontStyle: 'bold', + fullWidth: true, + lineHeight: 1.2, + padding: 10, + position: 'top', + text: '', + weight: 2000 // by default greater than legend (1000) to be above + } +}); + +module.exports = function(Chart) { + + var layout = Chart.layoutService; + var noop = helpers.noop; + + Chart.Title = Element.extend({ + initialize: function(config) { + var me = this; + helpers.extend(me, config); + + // Contains hit boxes for each dataset (in dataset order) + me.legendHitBoxes = []; + }, + + // These methods are ordered by lifecycle. Utilities then follow. + + beforeUpdate: noop, + update: function(maxWidth, maxHeight, margins) { + var me = this; + + // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) + me.beforeUpdate(); + + // Absorb the master measurements + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me.margins = margins; + + // Dimensions + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + // Labels + me.beforeBuildLabels(); + me.buildLabels(); + me.afterBuildLabels(); + + // Fit + me.beforeFit(); + me.fit(); + me.afterFit(); + // + me.afterUpdate(); + + return me.minSize; + + }, + afterUpdate: noop, + + // + + beforeSetDimensions: noop, + setDimensions: function() { + var me = this; + // Set the unconstrained dimension before label rotation + if (me.isHorizontal()) { + // Reset position before calculating rotation + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + + // Reset position before calculating rotation + me.top = 0; + me.bottom = me.height; + } + + // Reset padding + me.paddingLeft = 0; + me.paddingTop = 0; + me.paddingRight = 0; + me.paddingBottom = 0; + + // Reset minSize + me.minSize = { + width: 0, + height: 0 + }; + }, + afterSetDimensions: noop, + + // + + beforeBuildLabels: noop, + buildLabels: noop, + afterBuildLabels: noop, + + // + + beforeFit: noop, + fit: function() { + var me = this; + var valueOrDefault = helpers.valueOrDefault; + var opts = me.options; + var display = opts.display; + var fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize); + var minSize = me.minSize; + var lineCount = helpers.isArray(opts.text) ? opts.text.length : 1; + var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize); + var textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0; + + if (me.isHorizontal()) { + minSize.width = me.maxWidth; // fill all the width + minSize.height = textSize; + } else { + minSize.width = textSize; + minSize.height = me.maxHeight; // fill all the height + } + + me.width = minSize.width; + me.height = minSize.height; + + }, + afterFit: noop, + + // Shared Methods + isHorizontal: function() { + var pos = this.options.position; + return pos === 'top' || pos === 'bottom'; + }, + + // Actually draw the title block on the canvas + draw: function() { + var me = this; + var ctx = me.ctx; + var valueOrDefault = helpers.valueOrDefault; + var opts = me.options; + var globalDefaults = defaults.global; + + if (opts.display) { + var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize); + var fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle); + var fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily); + var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily); + var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize); + var offset = lineHeight / 2 + opts.padding; + var rotation = 0; + var top = me.top; + var left = me.left; + var bottom = me.bottom; + var right = me.right; + var maxWidth, titleX, titleY; + + ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour + ctx.font = titleFont; + + // Horizontal + if (me.isHorizontal()) { + titleX = left + ((right - left) / 2); // midpoint of the width + titleY = top + offset; + maxWidth = right - left; + } else { + titleX = opts.position === 'left' ? left + offset : right - offset; + titleY = top + ((bottom - top) / 2); + maxWidth = bottom - top; + rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5); + } + + ctx.save(); + ctx.translate(titleX, titleY); + ctx.rotate(rotation); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + + var text = opts.text; + if (helpers.isArray(text)) { + var y = 0; + for (var i = 0; i < text.length; ++i) { + ctx.fillText(text[i], 0, y, maxWidth); + y += lineHeight; + } + } else { + ctx.fillText(text, 0, 0, maxWidth); + } + + ctx.restore(); + } + } + }); + + function createNewTitleBlockAndAttach(chart, titleOpts) { + var title = new Chart.Title({ + ctx: chart.ctx, + options: titleOpts, + chart: chart + }); + + layout.configure(chart, title, titleOpts); + layout.addBox(chart, title); + chart.titleBlock = title; + } + + return { + id: 'title', + + beforeInit: function(chart) { + var titleOpts = chart.options.title; + + if (titleOpts) { + createNewTitleBlockAndAttach(chart, titleOpts); + } + }, + + beforeUpdate: function(chart) { + var titleOpts = chart.options.title; + var titleBlock = chart.titleBlock; + + if (titleOpts) { + helpers.mergeIf(titleOpts, defaults.global.title); + + if (titleBlock) { + layout.configure(chart, titleBlock, titleOpts); + titleBlock.options = titleOpts; + } else { + createNewTitleBlockAndAttach(chart, titleOpts); + } + } else if (titleBlock) { + Chart.layoutService.removeBox(chart, titleBlock); + delete chart.titleBlock; + } + } + }; +}; + +},{"25":25,"26":26,"45":45}],52:[function(require,module,exports){ +'use strict'; + +module.exports = function(Chart) { + + // Default config for a category scale + var defaultConfig = { + position: 'bottom' + }; + + var DatasetScale = Chart.Scale.extend({ + /** + * Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those + * else fall back to data.labels + * @private + */ + getLabels: function() { + var data = this.chart.data; + return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels; + }, + + determineDataLimits: function() { + var me = this; + var labels = me.getLabels(); + me.minIndex = 0; + me.maxIndex = labels.length - 1; + var findIndex; + + if (me.options.ticks.min !== undefined) { + // user specified min value + findIndex = labels.indexOf(me.options.ticks.min); + me.minIndex = findIndex !== -1 ? findIndex : me.minIndex; + } + + if (me.options.ticks.max !== undefined) { + // user specified max value + findIndex = labels.indexOf(me.options.ticks.max); + me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex; + } + + me.min = labels[me.minIndex]; + me.max = labels[me.maxIndex]; + }, + + buildTicks: function() { + var me = this; + var labels = me.getLabels(); + // If we are viewing some subset of labels, slice the original array + me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1); + }, + + getLabelForIndex: function(index, datasetIndex) { + var me = this; + var data = me.chart.data; + var isHorizontal = me.isHorizontal(); + + if (data.yLabels && !isHorizontal) { + return me.getRightValue(data.datasets[datasetIndex].data[index]); + } + return me.ticks[index - me.minIndex]; + }, + + // Used to get data value locations. Value can either be an index or a numerical value + getPixelForValue: function(value, index) { + var me = this; + var offset = me.options.offset; + // 1 is added because we need the length but we have the indexes + var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1); + + // If value is a data object, then index is the index in the data array, + // not the index of the scale. We need to change that. + var valueCategory; + if (value !== undefined && value !== null) { + valueCategory = me.isHorizontal() ? value.x : value.y; + } + if (valueCategory !== undefined || (value !== undefined && isNaN(index))) { + var labels = me.getLabels(); + value = valueCategory || value; + var idx = labels.indexOf(value); + index = idx !== -1 ? idx : index; + } + + if (me.isHorizontal()) { + var valueWidth = me.width / offsetAmt; + var widthOffset = (valueWidth * (index - me.minIndex)); + + if (offset) { + widthOffset += (valueWidth / 2); + } + + return me.left + Math.round(widthOffset); + } + var valueHeight = me.height / offsetAmt; + var heightOffset = (valueHeight * (index - me.minIndex)); + + if (offset) { + heightOffset += (valueHeight / 2); + } + + return me.top + Math.round(heightOffset); + }, + getPixelForTick: function(index) { + return this.getPixelForValue(this.ticks[index], index + this.minIndex, null); + }, + getValueForPixel: function(pixel) { + var me = this; + var offset = me.options.offset; + var value; + var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1); + var horz = me.isHorizontal(); + var valueDimension = (horz ? me.width : me.height) / offsetAmt; + + pixel -= horz ? me.left : me.top; + + if (offset) { + pixel -= (valueDimension / 2); + } + + if (pixel <= 0) { + value = 0; + } else { + value = Math.round(pixel / valueDimension); + } + + return value + me.minIndex; + }, + getBasePixel: function() { + return this.bottom; + } + }); + + Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig); + +}; + +},{}],53:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var helpers = require(45); +var Ticks = require(34); + +module.exports = function(Chart) { + + var defaultConfig = { + position: 'left', + ticks: { + callback: Ticks.formatters.linear + } + }; + + var LinearScale = Chart.LinearScaleBase.extend({ + + determineDataLimits: function() { + var me = this; + var opts = me.options; + var chart = me.chart; + var data = chart.data; + var datasets = data.datasets; + var isHorizontal = me.isHorizontal(); + var DEFAULT_MIN = 0; + var DEFAULT_MAX = 1; + + function IDMatches(meta) { + return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id; + } + + // First Calculate the range + me.min = null; + me.max = null; + + var hasStacks = opts.stacked; + if (hasStacks === undefined) { + helpers.each(datasets, function(dataset, datasetIndex) { + if (hasStacks) { + return; + } + + var meta = chart.getDatasetMeta(datasetIndex); + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) && + meta.stack !== undefined) { + hasStacks = true; + } + }); + } + + if (opts.stacked || hasStacks) { + var valuesPerStack = {}; + + helpers.each(datasets, function(dataset, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); + var key = [ + meta.type, + // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined + ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''), + meta.stack + ].join('.'); + + if (valuesPerStack[key] === undefined) { + valuesPerStack[key] = { + positiveValues: [], + negativeValues: [] + }; + } + + // Store these per type + var positiveValues = valuesPerStack[key].positiveValues; + var negativeValues = valuesPerStack[key].negativeValues; + + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { + helpers.each(dataset.data, function(rawValue, index) { + var value = +me.getRightValue(rawValue); + if (isNaN(value) || meta.data[index].hidden) { + return; + } + + positiveValues[index] = positiveValues[index] || 0; + negativeValues[index] = negativeValues[index] || 0; + + if (opts.relativePoints) { + positiveValues[index] = 100; + } else if (value < 0) { + negativeValues[index] += value; + } else { + positiveValues[index] += value; + } + }); + } + }); + + helpers.each(valuesPerStack, function(valuesForType) { + var values = valuesForType.positiveValues.concat(valuesForType.negativeValues); + var minVal = helpers.min(values); + var maxVal = helpers.max(values); + me.min = me.min === null ? minVal : Math.min(me.min, minVal); + me.max = me.max === null ? maxVal : Math.max(me.max, maxVal); + }); + + } else { + helpers.each(datasets, function(dataset, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { + helpers.each(dataset.data, function(rawValue, index) { + var value = +me.getRightValue(rawValue); + if (isNaN(value) || meta.data[index].hidden) { + return; + } + + if (me.min === null) { + me.min = value; + } else if (value < me.min) { + me.min = value; + } + + if (me.max === null) { + me.max = value; + } else if (value > me.max) { + me.max = value; + } + }); + } + }); + } + + me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN; + me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX; + + // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero + this.handleTickRangeOptions(); + }, + getTickLimit: function() { + var maxTicks; + var me = this; + var tickOpts = me.options.ticks; + + if (me.isHorizontal()) { + maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50)); + } else { + // The factor of 2 used to scale the font size has been experimentally determined. + var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize); + maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize))); + } + + return maxTicks; + }, + // Called after the ticks are built. We need + handleDirectionalChanges: function() { + if (!this.isHorizontal()) { + // We are in a vertical orientation. The top value is the highest. So reverse the array + this.ticks.reverse(); + } + }, + getLabelForIndex: function(index, datasetIndex) { + return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + }, + // Utils + getPixelForValue: function(value) { + // This must be called after fit has been run so that + // this.left, this.top, this.right, and this.bottom have been defined + var me = this; + var start = me.start; + + var rightValue = +me.getRightValue(value); + var pixel; + var range = me.end - start; + + if (me.isHorizontal()) { + pixel = me.left + (me.width / range * (rightValue - start)); + return Math.round(pixel); + } + + pixel = me.bottom - (me.height / range * (rightValue - start)); + return Math.round(pixel); + }, + getValueForPixel: function(pixel) { + var me = this; + var isHorizontal = me.isHorizontal(); + var innerDimension = isHorizontal ? me.width : me.height; + var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension; + return me.start + ((me.end - me.start) * offset); + }, + getPixelForTick: function(index) { + return this.getPixelForValue(this.ticksAsNumbers[index]); + } + }); + Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig); + +}; + +},{"25":25,"34":34,"45":45}],54:[function(require,module,exports){ +'use strict'; + +var helpers = require(45); +var Ticks = require(34); + +module.exports = function(Chart) { + + var noop = helpers.noop; + + Chart.LinearScaleBase = Chart.Scale.extend({ + getRightValue: function(value) { + if (typeof value === 'string') { + return +value; + } + return Chart.Scale.prototype.getRightValue.call(this, value); + }, + + handleTickRangeOptions: function() { + var me = this; + var opts = me.options; + var tickOpts = opts.ticks; + + // If we are forcing it to begin at 0, but 0 will already be rendered on the chart, + // do nothing since that would make the chart weird. If the user really wants a weird chart + // axis, they can manually override it + if (tickOpts.beginAtZero) { + var minSign = helpers.sign(me.min); + var maxSign = helpers.sign(me.max); + + if (minSign < 0 && maxSign < 0) { + // move the top up to 0 + me.max = 0; + } else if (minSign > 0 && maxSign > 0) { + // move the bottom down to 0 + me.min = 0; + } + } + + var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined; + var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined; + + if (tickOpts.min !== undefined) { + me.min = tickOpts.min; + } else if (tickOpts.suggestedMin !== undefined) { + if (me.min === null) { + me.min = tickOpts.suggestedMin; + } else { + me.min = Math.min(me.min, tickOpts.suggestedMin); + } + } + + if (tickOpts.max !== undefined) { + me.max = tickOpts.max; + } else if (tickOpts.suggestedMax !== undefined) { + if (me.max === null) { + me.max = tickOpts.suggestedMax; + } else { + me.max = Math.max(me.max, tickOpts.suggestedMax); + } + } + + if (setMin !== setMax) { + // We set the min or the max but not both. + // So ensure that our range is good + // Inverted or 0 length range can happen when + // ticks.min is set, and no datasets are visible + if (me.min >= me.max) { + if (setMin) { + me.max = me.min + 1; + } else { + me.min = me.max - 1; + } + } + } + + if (me.min === me.max) { + me.max++; + + if (!tickOpts.beginAtZero) { + me.min--; + } + } + }, + getTickLimit: noop, + handleDirectionalChanges: noop, + + buildTicks: function() { + var me = this; + var opts = me.options; + var tickOpts = opts.ticks; + + // Figure out what the max number of ticks we can support it is based on the size of + // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 + // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on + // the graph. Make sure we always have at least 2 ticks + var maxTicks = me.getTickLimit(); + maxTicks = Math.max(2, maxTicks); + + var numericGeneratorOptions = { + maxTicks: maxTicks, + min: tickOpts.min, + max: tickOpts.max, + stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize) + }; + var ticks = me.ticks = Ticks.generators.linear(numericGeneratorOptions, me); + + me.handleDirectionalChanges(); + + // At this point, we need to update our max and min given the tick values since we have expanded the + // range of the scale + me.max = helpers.max(ticks); + me.min = helpers.min(ticks); + + if (tickOpts.reverse) { + ticks.reverse(); + + me.start = me.max; + me.end = me.min; + } else { + me.start = me.min; + me.end = me.max; + } + }, + convertTicksToLabels: function() { + var me = this; + me.ticksAsNumbers = me.ticks.slice(); + me.zeroLineIndex = me.ticks.indexOf(0); + + Chart.Scale.prototype.convertTicksToLabels.call(me); + } + }); +}; + +},{"34":34,"45":45}],55:[function(require,module,exports){ +'use strict'; + +var helpers = require(45); +var Ticks = require(34); + +module.exports = function(Chart) { + + var defaultConfig = { + position: 'left', + + // label settings + ticks: { + callback: Ticks.formatters.logarithmic + } + }; + + var LogarithmicScale = Chart.Scale.extend({ + determineDataLimits: function() { + var me = this; + var opts = me.options; + var tickOpts = opts.ticks; + var chart = me.chart; + var data = chart.data; + var datasets = data.datasets; + var valueOrDefault = helpers.valueOrDefault; + var isHorizontal = me.isHorizontal(); + function IDMatches(meta) { + return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id; + } + + // Calculate Range + me.min = null; + me.max = null; + me.minNotZero = null; + + var hasStacks = opts.stacked; + if (hasStacks === undefined) { + helpers.each(datasets, function(dataset, datasetIndex) { + if (hasStacks) { + return; + } + + var meta = chart.getDatasetMeta(datasetIndex); + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) && + meta.stack !== undefined) { + hasStacks = true; + } + }); + } + + if (opts.stacked || hasStacks) { + var valuesPerStack = {}; + + helpers.each(datasets, function(dataset, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); + var key = [ + meta.type, + // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined + ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''), + meta.stack + ].join('.'); + + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { + if (valuesPerStack[key] === undefined) { + valuesPerStack[key] = []; + } + + helpers.each(dataset.data, function(rawValue, index) { + var values = valuesPerStack[key]; + var value = +me.getRightValue(rawValue); + if (isNaN(value) || meta.data[index].hidden) { + return; + } + + values[index] = values[index] || 0; + + if (opts.relativePoints) { + values[index] = 100; + } else { + // Don't need to split positive and negative since the log scale can't handle a 0 crossing + values[index] += value; + } + }); + } + }); + + helpers.each(valuesPerStack, function(valuesForType) { + var minVal = helpers.min(valuesForType); + var maxVal = helpers.max(valuesForType); + me.min = me.min === null ? minVal : Math.min(me.min, minVal); + me.max = me.max === null ? maxVal : Math.max(me.max, maxVal); + }); + + } else { + helpers.each(datasets, function(dataset, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { + helpers.each(dataset.data, function(rawValue, index) { + var value = +me.getRightValue(rawValue); + if (isNaN(value) || meta.data[index].hidden) { + return; + } + + if (me.min === null) { + me.min = value; + } else if (value < me.min) { + me.min = value; + } + + if (me.max === null) { + me.max = value; + } else if (value > me.max) { + me.max = value; + } + + if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) { + me.minNotZero = value; + } + }); + } + }); + } + + me.min = valueOrDefault(tickOpts.min, me.min); + me.max = valueOrDefault(tickOpts.max, me.max); + + if (me.min === me.max) { + if (me.min !== 0 && me.min !== null) { + me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1); + me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1); + } else { + me.min = 1; + me.max = 10; + } + } + }, + buildTicks: function() { + var me = this; + var opts = me.options; + var tickOpts = opts.ticks; + + var generationOptions = { + min: tickOpts.min, + max: tickOpts.max + }; + var ticks = me.ticks = Ticks.generators.logarithmic(generationOptions, me); + + if (!me.isHorizontal()) { + // We are in a vertical orientation. The top value is the highest. So reverse the array + ticks.reverse(); + } + + // At this point, we need to update our max and min given the tick values since we have expanded the + // range of the scale + me.max = helpers.max(ticks); + me.min = helpers.min(ticks); + + if (tickOpts.reverse) { + ticks.reverse(); + + me.start = me.max; + me.end = me.min; + } else { + me.start = me.min; + me.end = me.max; + } + }, + convertTicksToLabels: function() { + this.tickValues = this.ticks.slice(); + + Chart.Scale.prototype.convertTicksToLabels.call(this); + }, + // Get the correct tooltip label + getLabelForIndex: function(index, datasetIndex) { + return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + }, + getPixelForTick: function(index) { + return this.getPixelForValue(this.tickValues[index]); + }, + getPixelForValue: function(value) { + var me = this; + var start = me.start; + var newVal = +me.getRightValue(value); + var opts = me.options; + var tickOpts = opts.ticks; + var innerDimension, pixel, range; + + if (me.isHorizontal()) { + range = helpers.log10(me.end) - helpers.log10(start); // todo: if start === 0 + if (newVal === 0) { + pixel = me.left; + } else { + innerDimension = me.width; + pixel = me.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start))); + } + } else { + // Bottom - top since pixels increase downward on a screen + innerDimension = me.height; + if (start === 0 && !tickOpts.reverse) { + range = helpers.log10(me.end) - helpers.log10(me.minNotZero); + if (newVal === start) { + pixel = me.bottom; + } else if (newVal === me.minNotZero) { + pixel = me.bottom - innerDimension * 0.02; + } else { + pixel = me.bottom - innerDimension * 0.02 - (innerDimension * 0.98 / range * (helpers.log10(newVal) - helpers.log10(me.minNotZero))); + } + } else if (me.end === 0 && tickOpts.reverse) { + range = helpers.log10(me.start) - helpers.log10(me.minNotZero); + if (newVal === me.end) { + pixel = me.top; + } else if (newVal === me.minNotZero) { + pixel = me.top + innerDimension * 0.02; + } else { + pixel = me.top + innerDimension * 0.02 + (innerDimension * 0.98 / range * (helpers.log10(newVal) - helpers.log10(me.minNotZero))); + } + } else if (newVal === 0) { + pixel = tickOpts.reverse ? me.top : me.bottom; + } else { + range = helpers.log10(me.end) - helpers.log10(start); + innerDimension = me.height; + pixel = me.bottom - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start))); + } + } + return pixel; + }, + getValueForPixel: function(pixel) { + var me = this; + var range = helpers.log10(me.end) - helpers.log10(me.start); + var value, innerDimension; + + if (me.isHorizontal()) { + innerDimension = me.width; + value = me.start * Math.pow(10, (pixel - me.left) * range / innerDimension); + } else { // todo: if start === 0 + innerDimension = me.height; + value = Math.pow(10, (me.bottom - pixel) * range / innerDimension) / me.start; + } + return value; + } + }); + Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig); + +}; + +},{"34":34,"45":45}],56:[function(require,module,exports){ +'use strict'; + +var defaults = require(25); +var helpers = require(45); +var Ticks = require(34); + +module.exports = function(Chart) { + + var globalDefaults = defaults.global; + + var defaultConfig = { + display: true, + + // Boolean - Whether to animate scaling the chart from the centre + animate: true, + position: 'chartArea', + + angleLines: { + display: true, + color: 'rgba(0, 0, 0, 0.1)', + lineWidth: 1 + }, + + gridLines: { + circular: false + }, + + // label settings + ticks: { + // Boolean - Show a backdrop to the scale label + showLabelBackdrop: true, + + // String - The colour of the label backdrop + backdropColor: 'rgba(255,255,255,0.75)', + + // Number - The backdrop padding above & below the label in pixels + backdropPaddingY: 2, + + // Number - The backdrop padding to the side of the label in pixels + backdropPaddingX: 2, + + callback: Ticks.formatters.linear + }, + + pointLabels: { + // Boolean - if true, show point labels + display: true, + + // Number - Point label font size in pixels + fontSize: 10, + + // Function - Used to convert point labels + callback: function(label) { + return label; + } + } + }; + + function getValueCount(scale) { + var opts = scale.options; + return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0; + } + + function getPointLabelFontOptions(scale) { + var pointLabelOptions = scale.options.pointLabels; + var fontSize = helpers.valueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize); + var fontStyle = helpers.valueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle); + var fontFamily = helpers.valueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily); + var font = helpers.fontString(fontSize, fontStyle, fontFamily); + + return { + size: fontSize, + style: fontStyle, + family: fontFamily, + font: font + }; + } + + function measureLabelSize(ctx, fontSize, label) { + if (helpers.isArray(label)) { + return { + w: helpers.longestText(ctx, ctx.font, label), + h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize) + }; + } + + return { + w: ctx.measureText(label).width, + h: fontSize + }; + } + + function determineLimits(angle, pos, size, min, max) { + if (angle === min || angle === max) { + return { + start: pos - (size / 2), + end: pos + (size / 2) + }; + } else if (angle < min || angle > max) { + return { + start: pos - size - 5, + end: pos + }; + } + + return { + start: pos, + end: pos + size + 5 + }; + } + + /** + * Helper function to fit a radial linear scale with point labels + */ + function fitWithPointLabels(scale) { + /* + * Right, this is really confusing and there is a lot of maths going on here + * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9 + * + * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif + * + * Solution: + * + * We assume the radius of the polygon is half the size of the canvas at first + * at each index we check if the text overlaps. + * + * Where it does, we store that angle and that index. + * + * After finding the largest index and angle we calculate how much we need to remove + * from the shape radius to move the point inwards by that x. + * + * We average the left and right distances to get the maximum shape radius that can fit in the box + * along with labels. + * + * Once we have that, we can find the centre point for the chart, by taking the x text protrusion + * on each side, removing that from the size, halving it and adding the left x protrusion width. + * + * This will mean we have a shape fitted to the canvas, as large as it can be with the labels + * and position it in the most space efficient manner + * + * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif + */ + + var plFont = getPointLabelFontOptions(scale); + + // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width. + // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points + var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2); + var furthestLimits = { + r: scale.width, + l: 0, + t: scale.height, + b: 0 + }; + var furthestAngles = {}; + var i, textSize, pointPosition; + + scale.ctx.font = plFont.font; + scale._pointLabelSizes = []; + + var valueCount = getValueCount(scale); + for (i = 0; i < valueCount; i++) { + pointPosition = scale.getPointPosition(i, largestPossibleRadius); + textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || ''); + scale._pointLabelSizes[i] = textSize; + + // Add quarter circle to make degree 0 mean top of circle + var angleRadians = scale.getIndexAngle(i); + var angle = helpers.toDegrees(angleRadians) % 360; + var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); + var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); + + if (hLimits.start < furthestLimits.l) { + furthestLimits.l = hLimits.start; + furthestAngles.l = angleRadians; + } + + if (hLimits.end > furthestLimits.r) { + furthestLimits.r = hLimits.end; + furthestAngles.r = angleRadians; + } + + if (vLimits.start < furthestLimits.t) { + furthestLimits.t = vLimits.start; + furthestAngles.t = angleRadians; + } + + if (vLimits.end > furthestLimits.b) { + furthestLimits.b = vLimits.end; + furthestAngles.b = angleRadians; + } + } + + scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles); + } + + /** + * Helper function to fit a radial linear scale with no point labels + */ + function fit(scale) { + var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2); + scale.drawingArea = Math.round(largestPossibleRadius); + scale.setCenterPoint(0, 0, 0, 0); + } + + function getTextAlignForAngle(angle) { + if (angle === 0 || angle === 180) { + return 'center'; + } else if (angle < 180) { + return 'left'; + } + + return 'right'; + } + + function fillText(ctx, text, position, fontSize) { + if (helpers.isArray(text)) { + var y = position.y; + var spacing = 1.5 * fontSize; + + for (var i = 0; i < text.length; ++i) { + ctx.fillText(text[i], position.x, y); + y += spacing; + } + } else { + ctx.fillText(text, position.x, position.y); + } + } + + function adjustPointPositionForLabelHeight(angle, textSize, position) { + if (angle === 90 || angle === 270) { + position.y -= (textSize.h / 2); + } else if (angle > 270 || angle < 90) { + position.y -= textSize.h; + } + } + + function drawPointLabels(scale) { + var ctx = scale.ctx; + var valueOrDefault = helpers.valueOrDefault; + var opts = scale.options; + var angleLineOpts = opts.angleLines; + var pointLabelOpts = opts.pointLabels; + + ctx.lineWidth = angleLineOpts.lineWidth; + ctx.strokeStyle = angleLineOpts.color; + + var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max); + + // Point Label Font + var plFont = getPointLabelFontOptions(scale); + + ctx.textBaseline = 'top'; + + for (var i = getValueCount(scale) - 1; i >= 0; i--) { + if (angleLineOpts.display) { + var outerPosition = scale.getPointPosition(i, outerDistance); + ctx.beginPath(); + ctx.moveTo(scale.xCenter, scale.yCenter); + ctx.lineTo(outerPosition.x, outerPosition.y); + ctx.stroke(); + ctx.closePath(); + } + + if (pointLabelOpts.display) { + // Extra 3px out for some label spacing + var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5); + + // Keep this in loop since we may support array properties here + var pointLabelFontColor = valueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor); + ctx.font = plFont.font; + ctx.fillStyle = pointLabelFontColor; + + var angleRadians = scale.getIndexAngle(i); + var angle = helpers.toDegrees(angleRadians); + ctx.textAlign = getTextAlignForAngle(angle); + adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition); + fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size); + } + } + } + + function drawRadiusLine(scale, gridLineOpts, radius, index) { + var ctx = scale.ctx; + ctx.strokeStyle = helpers.valueAtIndexOrDefault(gridLineOpts.color, index - 1); + ctx.lineWidth = helpers.valueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1); + + if (scale.options.gridLines.circular) { + // Draw circular arcs between the points + ctx.beginPath(); + ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2); + ctx.closePath(); + ctx.stroke(); + } else { + // Draw straight lines connecting each index + var valueCount = getValueCount(scale); + + if (valueCount === 0) { + return; + } + + ctx.beginPath(); + var pointPosition = scale.getPointPosition(0, radius); + ctx.moveTo(pointPosition.x, pointPosition.y); + + for (var i = 1; i < valueCount; i++) { + pointPosition = scale.getPointPosition(i, radius); + ctx.lineTo(pointPosition.x, pointPosition.y); + } + + ctx.closePath(); + ctx.stroke(); + } + } + + function numberOrZero(param) { + return helpers.isNumber(param) ? param : 0; + } + + var LinearRadialScale = Chart.LinearScaleBase.extend({ + setDimensions: function() { + var me = this; + var opts = me.options; + var tickOpts = opts.ticks; + // Set the unconstrained dimension before label rotation + me.width = me.maxWidth; + me.height = me.maxHeight; + me.xCenter = Math.round(me.width / 2); + me.yCenter = Math.round(me.height / 2); + + var minSize = helpers.min([me.height, me.width]); + var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize); + me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2); + }, + determineDataLimits: function() { + var me = this; + var chart = me.chart; + var min = Number.POSITIVE_INFINITY; + var max = Number.NEGATIVE_INFINITY; + + helpers.each(chart.data.datasets, function(dataset, datasetIndex) { + if (chart.isDatasetVisible(datasetIndex)) { + var meta = chart.getDatasetMeta(datasetIndex); + + helpers.each(dataset.data, function(rawValue, index) { + var value = +me.getRightValue(rawValue); + if (isNaN(value) || meta.data[index].hidden) { + return; + } + + min = Math.min(value, min); + max = Math.max(value, max); + }); + } + }); + + me.min = (min === Number.POSITIVE_INFINITY ? 0 : min); + me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max); + + // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero + me.handleTickRangeOptions(); + }, + getTickLimit: function() { + var tickOpts = this.options.ticks; + var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize); + return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize))); + }, + convertTicksToLabels: function() { + var me = this; + + Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me); + + // Point labels + me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me); + }, + getLabelForIndex: function(index, datasetIndex) { + return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + }, + fit: function() { + if (this.options.pointLabels.display) { + fitWithPointLabels(this); + } else { + fit(this); + } + }, + /** + * Set radius reductions and determine new radius and center point + * @private + */ + setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) { + var me = this; + var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l); + var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r); + var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t); + var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b); + + radiusReductionLeft = numberOrZero(radiusReductionLeft); + radiusReductionRight = numberOrZero(radiusReductionRight); + radiusReductionTop = numberOrZero(radiusReductionTop); + radiusReductionBottom = numberOrZero(radiusReductionBottom); + + me.drawingArea = Math.min( + Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2), + Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2)); + me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom); + }, + setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) { + var me = this; + var maxRight = me.width - rightMovement - me.drawingArea; + var maxLeft = leftMovement + me.drawingArea; + var maxTop = topMovement + me.drawingArea; + var maxBottom = me.height - bottomMovement - me.drawingArea; + + me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left); + me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top); + }, + + getIndexAngle: function(index) { + var angleMultiplier = (Math.PI * 2) / getValueCount(this); + var startAngle = this.chart.options && this.chart.options.startAngle ? + this.chart.options.startAngle : + 0; + + var startAngleRadians = startAngle * Math.PI * 2 / 360; + + // Start from the top instead of right, so remove a quarter of the circle + return index * angleMultiplier + startAngleRadians; + }, + getDistanceFromCenterForValue: function(value) { + var me = this; + + if (value === null) { + return 0; // null always in center + } + + // Take into account half font size + the yPadding of the top value + var scalingFactor = me.drawingArea / (me.max - me.min); + if (me.options.ticks.reverse) { + return (me.max - value) * scalingFactor; + } + return (value - me.min) * scalingFactor; + }, + getPointPosition: function(index, distanceFromCenter) { + var me = this; + var thisAngle = me.getIndexAngle(index) - (Math.PI / 2); + return { + x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter, + y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter + }; + }, + getPointPositionForValue: function(index, value) { + return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); + }, + + getBasePosition: function() { + var me = this; + var min = me.min; + var max = me.max; + + return me.getPointPositionForValue(0, + me.beginAtZero ? 0 : + min < 0 && max < 0 ? max : + min > 0 && max > 0 ? min : + 0); + }, + + draw: function() { + var me = this; + var opts = me.options; + var gridLineOpts = opts.gridLines; + var tickOpts = opts.ticks; + var valueOrDefault = helpers.valueOrDefault; + + if (opts.display) { + var ctx = me.ctx; + var startAngle = this.getIndexAngle(0); + + // Tick Font + var tickFontSize = valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize); + var tickFontStyle = valueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle); + var tickFontFamily = valueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily); + var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily); + + helpers.each(me.ticks, function(label, index) { + // Don't draw a centre value (if it is minimum) + if (index > 0 || tickOpts.reverse) { + var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]); + + // Draw circular lines around the scale + if (gridLineOpts.display && index !== 0) { + drawRadiusLine(me, gridLineOpts, yCenterOffset, index); + } + + if (tickOpts.display) { + var tickFontColor = valueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor); + ctx.font = tickLabelFont; + + ctx.save(); + ctx.translate(me.xCenter, me.yCenter); + ctx.rotate(startAngle); + + if (tickOpts.showLabelBackdrop) { + var labelWidth = ctx.measureText(label).width; + ctx.fillStyle = tickOpts.backdropColor; + ctx.fillRect( + -labelWidth / 2 - tickOpts.backdropPaddingX, + -yCenterOffset - tickFontSize / 2 - tickOpts.backdropPaddingY, + labelWidth + tickOpts.backdropPaddingX * 2, + tickFontSize + tickOpts.backdropPaddingY * 2 + ); + } + + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillStyle = tickFontColor; + ctx.fillText(label, 0, -yCenterOffset); + ctx.restore(); + } + } + }); + + if (opts.angleLines.display || opts.pointLabels.display) { + drawPointLabels(me); + } + } + } + }); + Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig); + +}; + +},{"25":25,"34":34,"45":45}],57:[function(require,module,exports){ +/* global window: false */ +'use strict'; + +var moment = require(6); +moment = typeof moment === 'function' ? moment : window.moment; + +var defaults = require(25); +var helpers = require(45); + +// Integer constants are from the ES6 spec. +var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991; +var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; + +var INTERVALS = { + millisecond: { + common: true, + size: 1, + steps: [1, 2, 5, 10, 20, 50, 100, 250, 500] + }, + second: { + common: true, + size: 1000, + steps: [1, 2, 5, 10, 30] + }, + minute: { + common: true, + size: 60000, + steps: [1, 2, 5, 10, 30] + }, + hour: { + common: true, + size: 3600000, + steps: [1, 2, 3, 6, 12] + }, + day: { + common: true, + size: 86400000, + steps: [1, 2, 5] + }, + week: { + common: false, + size: 604800000, + steps: [1, 2, 3, 4] + }, + month: { + common: true, + size: 2.628e9, + steps: [1, 2, 3] + }, + quarter: { + common: false, + size: 7.884e9, + steps: [1, 2, 3, 4] + }, + year: { + common: true, + size: 3.154e10 + } +}; + +var UNITS = Object.keys(INTERVALS); + +function sorter(a, b) { + return a - b; +} + +function arrayUnique(items) { + var hash = {}; + var out = []; + var i, ilen, item; + + for (i = 0, ilen = items.length; i < ilen; ++i) { + item = items[i]; + if (!hash[item]) { + hash[item] = true; + out.push(item); + } + } + + return out; +} + +/** + * Returns an array of {time, pos} objects used to interpolate a specific `time` or position + * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is + * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other + * extremity (left + width or top + height). Note that it would be more optimized to directly + * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need + * to create the lookup table. The table ALWAYS contains at least two items: min and max. + * + * @param {Number[]} timestamps - timestamps sorted from lowest to highest. + * @param {String} distribution - If 'linear', timestamps will be spread linearly along the min + * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}. + * If 'series', timestamps will be positioned at the same distance from each other. In this + * case, only timestamps that break the time linearity are registered, meaning that in the + * best case, all timestamps are linear, the table contains only min and max. + */ +function buildLookupTable(timestamps, min, max, distribution) { + if (distribution === 'linear' || !timestamps.length) { + return [ + {time: min, pos: 0}, + {time: max, pos: 1} + ]; + } + + var table = []; + var items = [min]; + var i, ilen, prev, curr, next; + + for (i = 0, ilen = timestamps.length; i < ilen; ++i) { + curr = timestamps[i]; + if (curr > min && curr < max) { + items.push(curr); + } + } + + items.push(max); + + for (i = 0, ilen = items.length; i < ilen; ++i) { + next = items[i + 1]; + prev = items[i - 1]; + curr = items[i]; + + // only add points that breaks the scale linearity + if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) { + table.push({time: curr, pos: i / (ilen - 1)}); + } + } + + return table; +} + +// @see adapted from http://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/ +function lookup(table, key, value) { + var lo = 0; + var hi = table.length - 1; + var mid, i0, i1; + + while (lo >= 0 && lo <= hi) { + mid = (lo + hi) >> 1; + i0 = table[mid - 1] || null; + i1 = table[mid]; + + if (!i0) { + // given value is outside table (before first item) + return {lo: null, hi: i1}; + } else if (i1[key] < value) { + lo = mid + 1; + } else if (i0[key] > value) { + hi = mid - 1; + } else { + return {lo: i0, hi: i1}; + } + } + + // given value is outside table (after last item) + return {lo: i1, hi: null}; +} + +/** + * Linearly interpolates the given source `value` using the table items `skey` values and + * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos') + * returns the position for a timestamp equal to 42. If value is out of bounds, values at + * index [0, 1] or [n - 1, n] are used for the interpolation. + */ +function interpolate(table, skey, sval, tkey) { + var range = lookup(table, skey, sval); + + // Note: the lookup table ALWAYS contains at least 2 items (min and max) + var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo; + var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi; + + var span = next[skey] - prev[skey]; + var ratio = span ? (sval - prev[skey]) / span : 0; + var offset = (next[tkey] - prev[tkey]) * ratio; + + return prev[tkey] + offset; +} + +/** + * Convert the given value to a moment object using the given time options. + * @see http://momentjs.com/docs/#/parsing/ + */ +function momentify(value, options) { + var parser = options.parser; + var format = options.parser || options.format; + + if (typeof parser === 'function') { + return parser(value); + } + + if (typeof value === 'string' && typeof format === 'string') { + return moment(value, format); + } + + if (!(value instanceof moment)) { + value = moment(value); + } + + if (value.isValid()) { + return value; + } + + // Labels are in an incompatible moment format and no `parser` has been provided. + // The user might still use the deprecated `format` option to convert his inputs. + if (typeof format === 'function') { + return format(value); + } + + return value; +} + +function parse(input, scale) { + if (helpers.isNullOrUndef(input)) { + return null; + } + + var options = scale.options.time; + var value = momentify(scale.getRightValue(input), options); + if (!value.isValid()) { + return null; + } + + if (options.round) { + value.startOf(options.round); + } + + return value.valueOf(); +} + +/** + * Returns the number of unit to skip to be able to display up to `capacity` number of ticks + * in `unit` for the given `min` / `max` range and respecting the interval steps constraints. + */ +function determineStepSize(min, max, unit, capacity) { + var range = max - min; + var interval = INTERVALS[unit]; + var milliseconds = interval.size; + var steps = interval.steps; + var i, ilen, factor; + + if (!steps) { + return Math.ceil(range / ((capacity || 1) * milliseconds)); + } + + for (i = 0, ilen = steps.length; i < ilen; ++i) { + factor = steps[i]; + if (Math.ceil(range / (milliseconds * factor)) <= capacity) { + break; + } + } + + return factor; +} + +/** + * 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; + + for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { + interval = INTERVALS[UNITS[i]]; + factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER; + + if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { + return UNITS[i]; + } + } + + 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]].common) { + return UNITS[i]; + } + } +} + +/** + * Generates a maximum of `capacity` timestamps between min and max, rounded to the + * `minor` unit, aligned on the `major` unit and using the given scale time `options`. + * 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, 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; + var interval = INTERVALS[minor]; + var first = moment(min); + var last = moment(max); + var ticks = []; + var time; + + if (!stepSize) { + stepSize = determineStepSize(min, max, minor, capacity); + } + + // For 'week' unit, handle the first day of week option + if (weekday) { + first = first.isoWeekday(weekday); + last = last.isoWeekday(weekday); + } + + // Align first/last ticks on unit + first = first.startOf(weekday ? 'day' : minor); + last = last.startOf(weekday ? 'day' : minor); + + // Make sure that the last tick include max + if (last < max) { + last.add(1, minor); + } + + time = moment(first); + + if (majorTicksEnabled && major && !weekday && !timeOpts.round) { + // Align the first tick on the previous `minor` unit aligned on the `major` unit: + // we first aligned time on the previous `major` unit then add the number of full + // stepSize there is between first and the previous major time. + time.startOf(major); + time.add(~~((first - time) / (interval.size * stepSize)) * stepSize, minor); + } + + for (; time < last; time.add(stepSize, minor)) { + ticks.push(+time); + } + + ticks.push(+time); + + return ticks; +} + +/** + * Returns the right and left offsets from edges in the form of {left, right}. + * Offsets are added when the `offset` option is true. + */ +function computeOffsets(table, ticks, min, max, options) { + var left = 0; + var right = 0; + var upper, lower; + + if (options.offset && ticks.length) { + if (!options.time.min) { + upper = ticks.length > 1 ? ticks[1] : max; + lower = ticks[0]; + left = ( + interpolate(table, 'time', upper, 'pos') - + interpolate(table, 'time', lower, 'pos') + ) / 2; + } + if (!options.time.max) { + upper = ticks[ticks.length - 1]; + lower = ticks.length > 1 ? ticks[ticks.length - 2] : min; + right = ( + interpolate(table, 'time', upper, 'pos') - + interpolate(table, 'time', lower, 'pos') + ) / 2; + } + } + + return {left: left, right: right}; +} + +function ticksFromTimestamps(values, majorUnit) { + var ticks = []; + var i, ilen, value, major; + + for (i = 0, ilen = values.length; i < ilen; ++i) { + value = values[i]; + major = majorUnit ? value === +moment(value).startOf(majorUnit) : false; + + ticks.push({ + value: value, + major: major + }); + } + + return ticks; +} + +module.exports = function(Chart) { + + var defaultConfig = { + position: 'bottom', + + /** + * Data distribution along the scale: + * - 'linear': data are spread according to their time (distances can vary), + * - 'series': data are spread at the same distance from each other. + * @see https://github.com/chartjs/Chart.js/pull/4507 + * @since 2.7.0 + */ + distribution: 'linear', + + /** + * Scale boundary strategy (bypassed by min/max time options) + * - `data`: make sure data are fully visible, ticks outside are removed + * - `ticks`: make sure ticks are fully visible, data outside are truncated + * @see https://github.com/chartjs/Chart.js/pull/4556 + * @since 2.7.0 + */ + bounds: 'data', + + time: { + parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment + format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/ + unit: false, // false == automatic or override with week, month, year, etc. + round: false, // none, or override with week, month, year, etc. + displayFormat: false, // DEPRECATED + isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/ + minUnit: 'millisecond', + + // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/ + displayFormats: { + millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM, + second: 'h:mm:ss a', // 11:20:01 AM + minute: 'h:mm a', // 11:20 AM + hour: 'hA', // 5PM + day: 'MMM D', // Sep 4 + week: 'll', // Week 46, or maybe "[W]WW - YYYY" ? + month: 'MMM YYYY', // Sept 2015 + quarter: '[Q]Q - YYYY', // Q3 + year: 'YYYY' // 2015 + }, + }, + ticks: { + autoSkip: false, + + /** + * Ticks generation input values: + * - 'auto': generates "optimal" ticks based on scale size and time options. + * - 'data': generates ticks from data (including labels from data {t|x|y} objects). + * - 'labels': generates ticks from user given `data.labels` values ONLY. + * @see https://github.com/chartjs/Chart.js/pull/4507 + * @since 2.7.0 + */ + source: 'auto', + + major: { + enabled: false + } + } + }; + + var TimeScale = Chart.Scale.extend({ + initialize: function() { + if (!moment) { + throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com'); + } + + this.mergeTicksOptions(); + + Chart.Scale.prototype.initialize.call(this); + }, + + update: function() { + var me = this; + var options = me.options; + + // DEPRECATIONS: output a message only one time per update + if (options.time && options.time.format) { + console.warn('options.time.format is deprecated and replaced by options.time.parser.'); + } + + return Chart.Scale.prototype.update.apply(me, arguments); + }, + + /** + * Allows data to be referenced via 't' attribute + */ + getRightValue: function(rawValue) { + if (rawValue && rawValue.t !== undefined) { + rawValue = rawValue.t; + } + return Chart.Scale.prototype.getRightValue.call(this, rawValue); + }, + + determineDataLimits: function() { + var me = this; + var chart = me.chart; + var timeOpts = me.options.time; + var min = MAX_INTEGER; + var max = MIN_INTEGER; + var timestamps = []; + var datasets = []; + var labels = []; + var i, j, ilen, jlen, data, timestamp; + + // Convert labels to timestamps + for (i = 0, ilen = chart.data.labels.length; i < ilen; ++i) { + labels.push(parse(chart.data.labels[i], me)); + } + + // Convert data to timestamps + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + if (chart.isDatasetVisible(i)) { + data = chart.data.datasets[i].data; + + // Let's consider that all data have the same format. + if (helpers.isObject(data[0])) { + datasets[i] = []; + + for (j = 0, jlen = data.length; j < jlen; ++j) { + timestamp = parse(data[j], me); + timestamps.push(timestamp); + datasets[i][j] = timestamp; + } + } else { + timestamps.push.apply(timestamps, labels); + datasets[i] = labels.slice(0); + } + } else { + datasets[i] = []; + } + } + + if (labels.length) { + // Sort labels **after** data have been converted + labels = arrayUnique(labels).sort(sorter); + min = Math.min(min, labels[0]); + max = Math.max(max, labels[labels.length - 1]); + } + + if (timestamps.length) { + timestamps = arrayUnique(timestamps).sort(sorter); + min = Math.min(min, timestamps[0]); + 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; + + // Make sure that max is strictly higher than min (required by the lookup table) + me.min = Math.min(min, max); + me.max = Math.max(min + 1, max); + + // PRIVATE + me._horizontal = me.isHorizontal(); + me._table = []; + me._timestamps = { + data: timestamps, + datasets: datasets, + labels: labels + }; + }, + + buildTicks: function() { + var me = this; + var min = me.min; + var max = me.max; + var options = me.options; + var timeOpts = options.time; + var timestamps = []; + var ticks = []; + var i, ilen, timestamp; + + switch (options.ticks.source) { + case 'data': + timestamps = me._timestamps.data; + break; + case 'labels': + timestamps = me._timestamps.labels; + break; + case 'auto': + default: + timestamps = generate(min, max, me.getLabelCapacity(min), options); + } + + if (options.bounds === 'ticks' && timestamps.length) { + min = timestamps[0]; + max = timestamps[timestamps.length - 1]; + } + + // Enforce limits with user min/max options + min = parse(timeOpts.min, me) || min; + max = parse(timeOpts.max, me) || max; + + // Remove ticks outside the min/max range + for (i = 0, ilen = timestamps.length; i < ilen; ++i) { + timestamp = timestamps[i]; + if (timestamp >= min && timestamp <= max) { + ticks.push(timestamp); + } + } + + me.min = min; + me.max = max; + + // PRIVATE + 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, me._majorUnit); + }, + + getLabelForIndex: function(index, datasetIndex) { + var me = this; + var data = me.chart.data; + var timeOpts = me.options.time; + var label = data.labels && index < data.labels.length ? data.labels[index] : ''; + var value = data.datasets[datasetIndex].data[index]; + + if (helpers.isObject(value)) { + label = me.getRightValue(value); + } + if (timeOpts.tooltipFormat) { + label = momentify(label, timeOpts).format(timeOpts.tooltipFormat); + } + + return label; + }, + + /** + * Function to format an individual tick mark + * @private + */ + 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 = 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(formatOverride ? formatOverride : major ? majorFormat : minorFormat); + var tickOpts = major ? majorTickOpts : options.ticks.minor; + var formatter = helpers.valueOrDefault(tickOpts.callback, tickOpts.userCallback); + + return formatter ? formatter(label, index, ticks) : label; + }, + + convertTicksToLabels: function(ticks) { + var labels = []; + var i, ilen; + + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + labels.push(this.tickFormatFunction(moment(ticks[i].value), i, ticks)); + } + + return labels; + }, + + /** + * @private + */ + getPixelForOffset: function(time) { + var me = this; + var size = me._horizontal ? me.width : me.height; + var start = me._horizontal ? me.left : me.top; + var pos = interpolate(me._table, 'time', time, 'pos'); + + return start + size * (me._offsets.left + pos) / (me._offsets.left + 1 + me._offsets.right); + }, + + getPixelForValue: function(value, index, datasetIndex) { + var me = this; + var time = null; + + if (index !== undefined && datasetIndex !== undefined) { + time = me._timestamps.datasets[datasetIndex][index]; + } + + if (time === null) { + time = parse(value, me); + } + + if (time !== null) { + return me.getPixelForOffset(time); + } + }, + + getPixelForTick: function(index) { + var ticks = this.getTicks(); + return index >= 0 && index < ticks.length ? + this.getPixelForOffset(ticks[index].value) : + null; + }, + + getValueForPixel: function(pixel) { + var me = this; + var size = me._horizontal ? me.width : me.height; + var start = me._horizontal ? me.left : me.top; + var pos = (size ? (pixel - start) / size : 0) * (me._offsets.left + 1 + me._offsets.left) - me._offsets.right; + var time = interpolate(me._table, 'pos', pos, 'time'); + + return moment(time); + }, + + /** + * Crude approximation of what the label width might be + * @private + */ + getLabelWidth: function(label) { + var me = this; + var ticksOpts = me.options.ticks; + var tickLabelWidth = me.ctx.measureText(label).width; + var angle = helpers.toRadians(ticksOpts.maxRotation); + var cosRotation = Math.cos(angle); + var sinRotation = Math.sin(angle); + var tickFontSize = helpers.valueOrDefault(ticksOpts.fontSize, defaults.global.defaultFontSize); + + return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation); + }, + + /** + * @private + */ + getLabelCapacity: function(exampleTime) { + var me = this; + + var formatOverride = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation + + var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, [], formatOverride); + var tickLabelWidth = me.getLabelWidth(exampleLabel); + var innerWidth = me.isHorizontal() ? me.width : me.height; + + return Math.floor(innerWidth / tickLabelWidth); + } + }); + + Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig); +}; + +},{"25":25,"45":45,"6":6}]},{},[7])(7) +}); \ No newline at end of file diff --git a/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.roundedBarCharts.min.js b/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.roundedBarCharts.min.js new file mode 100644 index 000000000..2cb31f771 --- /dev/null +++ b/infosouth-admin/src/main/resources/static/oneself/chartjs/Chart.roundedBarCharts.min.js @@ -0,0 +1 @@ +Chart.elements.Rectangle.prototype.draw=function(){function t(t){return s[(f+t)%4]}var r,e,i,o,_,h,l,a,b=this._chart.ctx,d=this._view,n=d.borderWidth,u=this._chart.config.options.cornerRadius;if(u<0&&(u=0),void 0===u&&(u=0),d.horizontal?(r=d.base,e=d.x,i=d.y-d.height/2,o=d.y+d.height/2,_=e>r?1:-1,h=1,l=d.borderSkipped||"left"):(r=d.x-d.width/2,e=d.x+d.width/2,i=d.y,_=1,h=(o=d.base)>i?1:-1,l=d.borderSkipped||"bottom"),n){var T=Math.min(Math.abs(r-e),Math.abs(i-o)),v=(n=n>T?T:n)/2,g=r+("left"!==l?v*_:0),c=e+("right"!==l?-v*_:0),C=i+("top"!==l?v*h:0),w=o+("bottom"!==l?-v*h:0);g!==c&&(i=C,o=w),C!==w&&(r=g,e=c)}b.beginPath(),b.fillStyle=d.backgroundColor,b.strokeStyle=d.borderColor,b.lineWidth=n;var s=[[r,o],[r,i],[e,i],[e,o]],f=["bottom","left","top","right"].indexOf(l,0);-1===f&&(f=0);var q=t(0);b.moveTo(q[0],q[1]);for(var m=1;m<4;m++)q=t(m),nextCornerId=m+1,4==nextCornerId&&(nextCornerId=0),nextCorner=t(nextCornerId),width=s[2][0]-s[1][0],height=s[0][1]-s[1][1],x=s[1][0],y=s[1][1],(a=u)>Math.abs(height)/2&&(a=Math.floor(Math.abs(height)/2)),a>Math.abs(width)/2&&(a=Math.floor(Math.abs(width)/2)),height<0?(x_tl=x,x_tr=x+width,y_tl=y+height,y_tr=y+height,x_bl=x,x_br=x+width,y_bl=y,y_br=y,b.moveTo(x_bl+a,y_bl),b.lineTo(x_br-a,y_br),b.quadraticCurveTo(x_br,y_br,x_br,y_br-a),b.lineTo(x_tr,y_tr+a),b.quadraticCurveTo(x_tr,y_tr,x_tr-a,y_tr),b.lineTo(x_tl+a,y_tl),b.quadraticCurveTo(x_tl,y_tl,x_tl,y_tl+a),b.lineTo(x_bl,y_bl-a),b.quadraticCurveTo(x_bl,y_bl,x_bl+a,y_bl)):width<0?(x_tl=x+width,x_tr=x,y_tl=y,y_tr=y,x_bl=x+width,x_br=x,y_bl=y+height,y_br=y+height,b.moveTo(x_bl+a,y_bl),b.lineTo(x_br-a,y_br),b.quadraticCurveTo(x_br,y_br,x_br,y_br-a),b.lineTo(x_tr,y_tr+a),b.quadraticCurveTo(x_tr,y_tr,x_tr-a,y_tr),b.lineTo(x_tl+a,y_tl),b.quadraticCurveTo(x_tl,y_tl,x_tl,y_tl+a),b.lineTo(x_bl,y_bl-a),b.quadraticCurveTo(x_bl,y_bl,x_bl+a,y_bl)):(b.moveTo(x+a,y),b.lineTo(x+width-a,y),b.quadraticCurveTo(x+width,y,x+width,y+a),b.lineTo(x+width,y+height-a),b.quadraticCurveTo(x+width,y+height,x+width-a,y+height),b.lineTo(x+a,y+height),b.quadraticCurveTo(x,y+height,x,y+height-a),b.lineTo(x,y+a),b.quadraticCurveTo(x,y,x+a,y));b.fill(),n&&b.stroke()}; \ No newline at end of file diff --git a/infosouth-admin/src/main/resources/static/oneself/chartjs/chartjs-plugin-datalabels.js b/infosouth-admin/src/main/resources/static/oneself/chartjs/chartjs-plugin-datalabels.js new file mode 100644 index 000000000..d8491b6d6 --- /dev/null +++ b/infosouth-admin/src/main/resources/static/oneself/chartjs/chartjs-plugin-datalabels.js @@ -0,0 +1,1017 @@ +/*! + * @license + * chartjs-plugin-datalabels + * http://chartjs.org/ + * Version: 0.3.0 + * + * Copyright 2018 Chart.js Contributors + * Released under the MIT license + * https://github.com/chartjs/chartjs-plugin-datalabels/blob/master/LICENSE.md + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('chart.js')) : + typeof define === 'function' && define.amd ? define(['chart.js'], factory) : + (factory(global.Chart)); +}(this, (function (Chart) { 'use strict'; + +Chart = Chart && Chart.hasOwnProperty('default') ? Chart['default'] : Chart; + +'use strict'; + +var helpers$2 = Chart.helpers; + +var HitBox = function() { + this._rect = null; + this._rotation = 0; +}; + +helpers$2.extend(HitBox.prototype, { + update: function(center, rect, rotation) { + var margin = 1; + var cx = center.x; + var cy = center.y; + var x = cx + rect.x; + var y = cy + rect.y; + + this._rotation = rotation; + this._rect = { + x0: x - margin, + y0: y - margin, + x1: x + rect.w + margin * 2, + y1: y + rect.h + margin * 2, + cx: cx, + cy: cy, + }; + }, + + contains: function(x, y) { + var me = this; + var rect = me._rect; + var cx, cy, r, rx, ry; + + if (!rect) { + return false; + } + + cx = rect.cx; + cy = rect.cy; + r = me._rotation; + rx = cx + (x - cx) * Math.cos(r) + (y - cy) * Math.sin(r); + ry = cy - (x - cx) * Math.sin(r) + (y - cy) * Math.cos(r); + + return !(rx < rect.x0 + || ry < rect.y0 + || rx > rect.x1 + || ry > rect.y1); + } +}); + +'use strict'; + +var helpers$3 = Chart.helpers; + +var utils = { + // @todo move this in Chart.helpers.toTextLines + toTextLines: function(inputs) { + var lines = []; + var input; + + inputs = [].concat(inputs); + while (inputs.length) { + input = inputs.pop(); + if (typeof input === 'string') { + lines.unshift.apply(lines, input.split('\n')); + } else if (Array.isArray(input)) { + inputs.push.apply(inputs, input); + } else if (!helpers$3.isNullOrUndef(inputs)) { + lines.unshift('' + input); + } + } + + return lines; + }, + + // @todo move this method in Chart.helpers.canvas.toFont (deprecates helpers.fontString) + // @see https://developer.mozilla.org/en-US/docs/Web/CSS/font + toFontString: function(font) { + if (!font || helpers$3.isNullOrUndef(font.size) || helpers$3.isNullOrUndef(font.family)) { + return null; + } + + return (font.style ? font.style + ' ' : '') + + (font.weight ? font.weight + ' ' : '') + + font.size + 'px ' + + font.family; + }, + + // @todo move this in Chart.helpers.canvas.textSize + // @todo cache calls of measureText if font doesn't change?! + textSize: function(ctx, lines, font) { + var items = [].concat(lines); + var ilen = items.length; + var prev = ctx.font; + var width = 0; + var i; + + ctx.font = font.string; + + for (i = 0; i < ilen; ++i) { + width = Math.max(ctx.measureText(items[i]).width, width); + } + + ctx.font = prev; + + return { + height: ilen * font.lineHeight, + width: width + }; + }, + + // @todo move this method in Chart.helpers.options.toFont + parseFont: function(value) { + var global = Chart.defaults.global; + var size = helpers$3.valueOrDefault(value.size, global.defaultFontSize); + var font = { + family: helpers$3.valueOrDefault(value.family, global.defaultFontFamily), + lineHeight: helpers$3.options.toLineHeight(value.lineHeight, size), + size: size, + style: helpers$3.valueOrDefault(value.style, global.defaultFontStyle), + weight: helpers$3.valueOrDefault(value.weight, null), + string: '' + }; + + font.string = utils.toFontString(font); + return font; + }, + + /** + * Returns value bounded by min and max. This is equivalent to max(min, min(value, max)). + * @todo move this method in Chart.helpers.bound + * https://doc.qt.io/qt-5/qtglobal.html#qBound + */ + bound: function(min, value, max) { + return Math.max(min, Math.min(value, max)); + }, + + /** + * Returns an array of pair [value, state] where state is: + * * -1: value is only in a0 (removed) + * * 1: value is only in a1 (added) + */ + arrayDiff: function(a0, a1) { + var prev = a0.slice(); + var updates = []; + var i, j, ilen, v; + + for (i = 0, ilen = a1.length; i < ilen; ++i) { + v = a1[i]; + j = prev.indexOf(v); + + if (j === -1) { + updates.push([v, 1]); + } else { + prev.splice(j, 1); + } + } + + for (i = 0, ilen = prev.length; i < ilen; ++i) { + updates.push([prev[i], -1]); + } + + return updates; + } +}; + +'use strict'; + +function orient(point, origin) { + var x0 = origin.x; + var y0 = origin.y; + + if (x0 === null) { + return {x: 0, y: -1}; + } + if (y0 === null) { + return {x: 1, y: 0}; + } + + var dx = point.x - x0; + var dy = point.y - y0; + var ln = Math.sqrt(dx * dx + dy * dy); + return { + x: ln ? dx / ln : 0, + y: ln ? dy / ln : -1 + }; +} + +function aligned(x, y, vx, vy, align) { + switch (align) { + case 'center': + vx = vy = 0; + break; + case 'bottom': + vx = 0; + vy = 1; + break; + case 'right': + vx = 1; + vy = 0; + break; + case 'left': + vx = -1; + vy = 0; + break; + case 'top': + vx = 0; + vy = -1; + break; + case 'start': + vx = -vx; + vy = -vy; + break; + case 'end': + // keep the natural orientation + break; + default: + // clockwise rotation (in degree) + align *= (Math.PI / 180); + vx = Math.cos(align); + vy = Math.sin(align); + break; + } + + return { + x: x, + y: y, + vx: vx, + vy: vy + }; +} + +var positioners = { + arc: function(vm, anchor, align) { + var angle = (vm.startAngle + vm.endAngle) / 2; + var vx = Math.cos(angle); + var vy = Math.sin(angle); + var r0 = vm.innerRadius; + var r1 = vm.outerRadius; + var d; + + if (anchor === 'start') { + d = r0; + } else if (anchor === 'end') { + d = r1; + } else { + d = (r0 + r1) / 2; + } + + return aligned( + vm.x + vx * d, + vm.y + vy * d, + vx, + vy, + align); + }, + + point: function(vm, anchor, align, origin) { + var v = orient(vm, origin); + var r = vm.radius; + var d = 0; + + if (anchor === 'start') { + d = -r; + } else if (anchor === 'end') { + d = r; + } + + return aligned( + vm.x + v.x * d, + vm.y + v.y * d, + v.x, + v.y, + align); + }, + + rect: function(vm, anchor, align, origin) { + var horizontal = vm.horizontal; + var size = Math.abs(vm.base - (horizontal ? vm.x : vm.y)); + var x = horizontal ? Math.min(vm.x, vm.base) : vm.x; + var y = horizontal ? vm.y : Math.min(vm.y, vm.base); + var v = orient(vm, origin); + + if (anchor === 'center') { + if (horizontal) { + x += size / 2; + } else { + y += size / 2; + } + } else if (anchor === 'start' && !horizontal) { + y += size; + } else if (anchor === 'end' && horizontal) { + x += size; + } + + return aligned( + x, + y, + v.x, + v.y, + align); + }, + + fallback: function(vm, anchor, align, origin) { + var v = orient(vm, origin); + return aligned( + vm.x, + vm.y, + v.x, + v.y, + align); + } +}; + +'use strict'; + +var helpers$1 = Chart.helpers; + +function boundingRects(size, padding) { + var th = size.height; + var tw = size.width; + var tx = -tw / 2; + var ty = -th / 2; + + return { + frame: { + x: tx - padding.left, + y: ty - padding.top, + w: tw + padding.width, + h: th + padding.height, + }, + text: { + x: tx, + y: ty, + w: tw, + h: th + } + }; +} + +function getScaleOrigin(el) { + var horizontal = el._model.horizontal; + var scale = el._scale || (horizontal && el._xScale) || el._yScale; + + if (!scale) { + return null; + } + + if (scale.xCenter !== undefined && scale.yCenter !== undefined) { + return {x: scale.xCenter, y: scale.yCenter}; + } + + var pixel = scale.getBasePixel(); + return horizontal ? + {x: pixel, y: null} : + {x: null, y: pixel}; +} + +function getPositioner(el) { + if (el instanceof Chart.elements.Arc) { + return positioners.arc; + } + if (el instanceof Chart.elements.Point) { + return positioners.point; + } + if (el instanceof Chart.elements.Rectangle) { + return positioners.rect; + } + return positioners.fallback; +} + +function coordinates(el, model, rect) { + var point = model.positioner(el._view, model.anchor, model.align, model.origin); + var vx = point.vx; + var vy = point.vy; + + if (!vx && !vy) { + // if aligned center, we don't want to offset the center point + return {x: point.x, y: point.y}; + } + + // include borders to the bounding rect + var borderWidth = model.borderWidth || 0; + var w = (rect.w + borderWidth * 2); + var h = (rect.h + borderWidth * 2); + + // take in account the label rotation + var rotation = model.rotation; + var dx = Math.abs(w / 2 * Math.cos(rotation)) + Math.abs(h / 2 * Math.sin(rotation)); + var dy = Math.abs(w / 2 * Math.sin(rotation)) + Math.abs(h / 2 * Math.cos(rotation)); + + // scale the unit vector (vx, vy) to get at least dx or dy equal to w or h respectively + // (else we would calculate the distance to the ellipse inscribed in the bounding rect) + var vs = 1 / Math.max(Math.abs(vx), Math.abs(vy)); + dx *= vx * vs; + dy *= vy * vs; + + // finally, include the explicit offset + dx += model.offset * vx; + dy += model.offset * vy; + + return { + x: point.x + dx, + y: point.y + dy + }; +} + +function drawFrame(ctx, rect, model) { + var bgColor = model.backgroundColor; + var borderColor = model.borderColor; + var borderWidth = model.borderWidth; + + if (!bgColor && (!borderColor || !borderWidth)) { + return; + } + + ctx.beginPath(); + + helpers$1.canvas.roundedRect( + ctx, + Math.round(rect.x) - borderWidth / 2, + Math.round(rect.y) - borderWidth / 2, + Math.round(rect.w) + borderWidth, + Math.round(rect.h) + borderWidth, + model.borderRadius); + + ctx.closePath(); + + if (bgColor) { + ctx.fillStyle = bgColor; + ctx.fill(); + } + + if (borderColor && borderWidth) { + ctx.strokeStyle = borderColor; + ctx.lineWidth = borderWidth; + ctx.lineJoin = 'miter'; + ctx.stroke(); + } +} + +function drawText(ctx, lines, rect, model) { + var align = model.textAlign; + var font = model.font; + var lh = font.lineHeight; + var color = model.color; + var ilen = lines.length; + var x, y, i; + + if (!ilen || !color) { + return; + } + + x = rect.x; + y = rect.y + lh / 2; + + if (align === 'center') { + x += rect.w / 2; + } else if (align === 'end' || align === 'right') { + x += rect.w; + } + + ctx.font = model.font.string; + ctx.fillStyle = color; + ctx.textAlign = align; + ctx.textBaseline = 'middle'; + + for (i = 0; i < ilen; ++i) { + ctx.fillText( + lines[i], + Math.round(x), + Math.round(y), + Math.round(rect.w)); + + y += lh; + } +} + +var Label = function(config, ctx, el, index) { + var me = this; + + me._hitbox = new HitBox(); + me._config = config; + me._index = index; + me._model = null; + me._ctx = ctx; + me._el = el; +}; + +helpers$1.extend(Label.prototype, { + /** + * @private + */ + _modelize: function(lines, config, context) { + var me = this; + var index = me._index; + var resolve = helpers$1.options.resolve; + var font = utils.parseFont(resolve([config.font, {}], context, index)); + + return { + align: resolve([config.align, 'center'], context, index), + anchor: resolve([config.anchor, 'center'], context, index), + backgroundColor: resolve([config.backgroundColor, null], context, index), + borderColor: resolve([config.borderColor, null], context, index), + borderRadius: resolve([config.borderRadius, 0], context, index), + borderWidth: resolve([config.borderWidth, 0], context, index), + color: resolve([config.color, Chart.defaults.global.defaultFontColor], context, index), + font: font, + lines: lines, + offset: resolve([config.offset, 0], context, index), + opacity: resolve([config.opacity, 1], context, index), + origin: getScaleOrigin(me._el), + padding: helpers$1.options.toPadding(resolve([config.padding, 0], context, index)), + positioner: getPositioner(me._el), + rotation: resolve([config.rotation, 0], context, index) * (Math.PI / 180), + size: utils.textSize(me._ctx, lines, font), + textAlign: resolve([config.textAlign, 'start'], context, index) + }; + }, + + update: function(context) { + var me = this; + var model = null; + var index = me._index; + var config = me._config; + var value, label, lines; + + if (helpers$1.options.resolve([config.display, true], context, index)) { + value = context.dataset.data[index]; + label = helpers$1.valueOrDefault(helpers$1.callback(config.formatter, [value, context]), value); + lines = helpers$1.isNullOrUndef(label) ? [] : utils.toTextLines(label); + model = lines.length ? me._modelize(lines, config, context) : null; + } + + me._model = model; + }, + + draw: function(ctx) { + var me = this; + var model = me._model; + var rects, center; + + if (!model || !model.opacity) { + return; + } + + rects = boundingRects(model.size, model.padding); + center = coordinates(me._el, model, rects.frame); + me._hitbox.update(center, rects.frame, model.rotation); + + ctx.save(); + ctx.globalAlpha = utils.bound(0, model.opacity, 1); + ctx.translate(Math.round(center.x), Math.round(center.y)); + ctx.rotate(model.rotation); + + drawFrame(ctx, rects.frame, model); + drawText(ctx, model.lines, rects.text, model); + + ctx.restore(); + }, + + contains: function(x, y) { + return this._hitbox.contains(x, y); + } +}); + +/** + * @module Options + */ + +'use strict'; + +var helpers$4 = Chart.helpers; + +var defaults = { + /** + * The label box alignment relative to `anchor` that can be expressed either by a number + * representing the clockwise angle (in degree) or by one of the following string presets: + * - 'start': before the anchor point, following the same direction + * - 'end': after the anchor point, following the same direction + * - 'center': centered on the anchor point + * - 'right': 0° + * - 'bottom': 90° + * - 'left': 180° + * - 'top': 270° + * @member {String|Number|Array|Function} + * @default 'center' + */ + align: 'center', + + /** + * The label box alignment relative to the element ('start'|'center'|'end') + * @member {String|Array|Function} + * @default 'center' + */ + anchor: 'center', + + /** + * The color used to draw the background of the surrounding frame. + * @member {String|Array|Function|null} + * @default null (no background) + */ + backgroundColor: null, + + /** + * The color used to draw the border of the surrounding frame. + * @member {String|Array|Function|null} + * @default null (no border) + */ + borderColor: null, + + /** + * The border radius used to add rounded corners to the surrounding frame. + * @member {Number|Array|Function} + * @default 0 (not rounded) + */ + borderRadius: 0, + + /** + * The border width of the surrounding frame. + * @member {Number|Array|Function} + * @default 0 (no border) + */ + borderWidth: 0, + + /** + * The color used to draw the label text. + * @member {String|Array|Function} + * @default undefined (use Chart.defaults.global.defaultFontColor) + */ + color: undefined, + + /** + * Whether to display labels global (boolean) or per data (function) + * @member {Boolean|Array|Function} + * @default true + */ + display: true, + + /** + * The font options used to draw the label text. + * @member {Object|Array|Function} + * @prop {String} font.family - defaults to Chart.defaults.global.defaultFontFamily + * @prop {Number} font.lineHeight - defaults to 1.2 + * @prop {Number} font.size - defaults to Chart.defaults.global.defaultFontSize + * @prop {String} font.style - defaults to Chart.defaults.global.defaultFontStyle + * @prop {Number} font.weight - defaults to 'normal' + * @default Chart.defaults.global.defaultFont.* + */ + font: { + family: undefined, + lineHeight: 1.2, + size: undefined, + style: undefined, + weight: null + }, + + /** + * The distance (in pixels) to pull the label away from the anchor point, the direction + * being determined by the `align` value (only applicable if `align` is `start` or `end`). + * @member {Number|Array|Function} + * @default 4 + */ + offset: 4, + + /** + * The label global opacity, including the text, background, borders, etc., specified as + * a number between 0.0 (fully transparent) and 1.0 (fully opaque). + * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalAlpha + * @member {Number|Array|Function} + * @default 1 + */ + opacity: 1, + + /** + * The padding (in pixels) to apply between the text and the surrounding frame. + * @member {Number|Object|Array|Function} + * @prop {Number} padding.top - Space above the text. + * @prop {Number} padding.right - Space on the right of the text. + * @prop {Number} padding.bottom - Space below the text. + * @prop {Number} padding.left - Space on the left of the text. + * @default 4 (all values) + */ + padding: { + top: 4, + right: 4, + bottom: 4, + left: 4 + }, + + /** + * Clockwise rotation of the label relative to its center. + * @member {Number|Array|Function} + * @default 0 + */ + rotation: 0, + + /** + * Text alignment for multi-lines labels ('left'|'right'|'start'|'center'|'end'). + * @member {String|Array|Function} + * @default 'start' + */ + textAlign: 'start', + + /** + * Allows to customize the label text by transforming input data. + * @member {Function|null} + * @prop {*} value - The data value + * @prop {Object} context - The function unique argument: + * @prop {Chart} context.chart - The current chart + * @prop {Number} context.dataIndex - Index of the current data + * @prop {Object} context.dataset - The current dataset + * @prop {Number} context.datasetIndex - Index of the current dataset + * @default data[index] + */ + formatter: function(value) { + if (helpers$4.isNullOrUndef(value)) { + return null; + } + + var label = value; + var keys, klen, k; + if (helpers$4.isObject(value)) { + if (!helpers$4.isNullOrUndef(value.label)) { + label = value.label; + } else if (!helpers$4.isNullOrUndef(value.r)) { + label = value.r; + } else { + label = ''; + keys = Object.keys(value); + for (k = 0, klen = keys.length; k < klen; ++k) { + label += (k !== 0 ? ', ' : '') + keys[k] + ': ' + value[keys[k]]; + } + } + } + return '' + label; + }, + + /** + * Event listeners, where the property is the type of the event to listen and the value + * a callback with a unique `context` argument containing the same information as for + * scriptable options. If a callback explicitly returns `true`, the label is updated + * with the current context and the chart re-rendered. This allows to implement visual + * interactions with labels such as highlight, selection, etc. + * + * Event currently supported are: + * - 'click': a mouse click is detected within a label + * - 'enter': the mouse enters a label + * -' leave': the mouse leaves a label + * + * @member {Object} + * @default {} + */ + listeners: {} +}; + +/** + * @see https://github.com/chartjs/Chart.js/issues/4176 + */ + +'use strict'; + +var helpers = Chart.helpers; +var EXPANDO_KEY = '$datalabels'; + +Chart.defaults.global.plugins.datalabels = defaults; + +function configure(dataset, options) { + var override = dataset.datalabels; + var config = {}; + + if (override === false) { + return null; + } + if (override === true) { + override = {}; + } + + return helpers.merge(config, [options, override]); +} + +function drawLabels(chart, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); + var elements = meta.data || []; + var ilen = elements.length; + var i, el, label; + + for (i = 0; i < ilen; ++i) { + el = elements[i]; + label = el[EXPANDO_KEY]; + if (label) { + label.draw(chart.ctx); + } + } +} + +function labelAtXY(chart, x, y) { + var items = chart[EXPANDO_KEY].labels; + var i, j, labels, label; + + // Until we support z-index, let's hit test in the drawing reverse order + for (i = items.length - 1; i >= 0; --i) { + labels = items[i] || []; + for (j = labels.length - 1; j >= 0; --j) { + label = labels[j]; + if (label.contains(x, y)) { + return {dataset: i, label: label}; + } + } + } + + return null; +} + +function dispatchEvent(chart, listeners, target) { + var callback = listeners && listeners[target.dataset]; + if (!callback) { + return; + } + + var label = target.label; + var context = label.$context; + + if (helpers.callback(callback, [context]) === true) { + // Users are allowed to tweak the given context by injecting values that can be + // used in scriptable options to display labels differently based on the current + // event (e.g. highlight an hovered label). That's why we update the label with + // the output context and schedule a new chart render by setting it dirty. + chart[EXPANDO_KEY].dirty = true; + label.update(context); + } +} + +function dispatchMoveEvents(chart, listeners, previous, target) { + var enter, leave; + + if (!previous && !target) { + return; + } + + if (!previous) { + enter = true; + } else if (!target) { + leave = true; + } else if (previous.label !== target.label) { + leave = enter = true; + } + + if (leave) { + dispatchEvent(chart, listeners.leave, previous); + } + if (enter) { + dispatchEvent(chart, listeners.enter, target); + } +} + +function handleMoveEvents(chart, event) { + var expando = chart[EXPANDO_KEY]; + var listeners = expando.listeners; + var previous, target; + + if (!listeners.enter && !listeners.leave) { + return; + } + + if (event.type === 'mousemove') { + target = labelAtXY(chart, event.x, event.y); + } else if (event.type !== 'mouseout') { + return; + } + + previous = expando.hovered; + expando.hovered = target; + dispatchMoveEvents(chart, listeners, previous, target); +} + +function handleClickEvents(chart, event) { + var handlers = chart[EXPANDO_KEY].listeners.click; + var target = handlers && labelAtXY(chart, event.x, event.y); + if (target) { + dispatchEvent(chart, handlers, target); + } +} + +Chart.defaults.global.plugins.datalabels = defaults; + +Chart.plugins.register({ + id: 'datalabels', + + beforeInit: function(chart) { + chart[EXPANDO_KEY] = { + actives: [] + }; + }, + + beforeUpdate: function(chart) { + var expando = chart[EXPANDO_KEY]; + expando.listened = false; + expando.listeners = {}; // {event-type: {dataset-index: function}} + expando.labels = []; // [dataset-index: [labels]] + }, + + afterDatasetUpdate: function(chart, args, options) { + var datasetIndex = args.index; + var expando = chart[EXPANDO_KEY]; + var labels = expando.labels[datasetIndex] = []; + var dataset = chart.data.datasets[datasetIndex]; + var config = configure(dataset, options); + var elements = args.meta.data || []; + var ilen = elements.length; + var ctx = chart.ctx; + var i, el, label; + + ctx.save(); + + for (i = 0; i < ilen; ++i) { + el = elements[i]; + + if (el && !el.hidden && !el._model.skip) { + labels.push(label = new Label(config, ctx, el, i)); + label.update(label.$context = { + active: false, + chart: chart, + dataIndex: i, + dataset: dataset, + datasetIndex: datasetIndex + }); + } else { + label = null; + } + + el[EXPANDO_KEY] = label; + } + + ctx.restore(); + + // Store listeners at the chart level and per event type to optimize + // cases where no listeners are registered for a specific event + helpers.merge(expando.listeners, config.listeners || {}, { + merger: function(key, target, source) { + target[key] = target[key] || {}; + target[key][args.index] = source[key]; + expando.listened = true; + } + }); + }, + + // Draw labels on top of all dataset elements + // https://github.com/chartjs/chartjs-plugin-datalabels/issues/29 + // https://github.com/chartjs/chartjs-plugin-datalabels/issues/32 + afterDatasetsDraw: function(chart) { + for (var i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { + drawLabels(chart, i); + } + }, + + beforeEvent: function(chart, event) { + // If there is no listener registered for this chart, `listened` will be false, + // meaning we can immediately ignore the incoming event and avoid useless extra + // computation for users who don't implement label interactions. + if (chart[EXPANDO_KEY].listened) { + switch (event.type) { + case 'mousemove': + case 'mouseout': + handleMoveEvents(chart, event); + break; + case 'click': + handleClickEvents(chart, event); + break; + default: + } + } + }, + + afterEvent: function(chart) { + var expando = chart[EXPANDO_KEY]; + var previous = expando.actives; + var actives = expando.actives = chart.lastActive || []; // public API?! + var updates = utils.arrayDiff(previous, actives); + var i, ilen, update, label; + + for (i = 0, ilen = updates.length; i < ilen; ++i) { + update = updates[i]; + if (update[1]) { + label = update[0][EXPANDO_KEY]; + label.$context.active = (update[1] === 1); + label.update(label.$context); + } + } + + if ((expando.dirty || updates.length) && !chart.animating) { + chart.render(); + } + + delete expando.dirty; + } +}); + +}))); diff --git a/infosouth-admin/src/main/resources/static/oneself/chartjs/chartjs-plugin-zoom.js b/infosouth-admin/src/main/resources/static/oneself/chartjs/chartjs-plugin-zoom.js new file mode 100644 index 000000000..f34793d4a --- /dev/null +++ b/infosouth-admin/src/main/resources/static/oneself/chartjs/chartjs-plugin-zoom.js @@ -0,0 +1,583 @@ +/*! + * chartjs-plugin-zoom + * http://chartjs.org/ + * Version: 0.6.3 + * + * Copyright 2016 Evert Timberg + * Released under the MIT license + * https://github.com/chartjs/chartjs-plugin-zoom/blob/master/LICENSE.md + */ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o rangeMax) { + newMax = rangeMax; + } + } + return newMax; +} + +function rangeMinLimiter(zoomPanOptions, newMin) { + if (zoomPanOptions.scaleAxes && zoomPanOptions.rangeMin && + !helpers.isNullOrUndef(zoomPanOptions.rangeMin[zoomPanOptions.scaleAxes])) { + var rangeMin = zoomPanOptions.rangeMin[zoomPanOptions.scaleAxes]; + if (newMin < rangeMin) { + newMin = rangeMin; + } + } + return newMin; +} + +function zoomIndexScale(scale, zoom, center, zoomOptions) { + var labels = scale.chart.data.labels; + var minIndex = scale.minIndex; + var lastLabelIndex = labels.length - 1; + var maxIndex = scale.maxIndex; + var sensitivity = zoomOptions.sensitivity; + var chartCenter = scale.isHorizontal() ? scale.left + (scale.width/2) : scale.top + (scale.height/2); + var centerPointer = scale.isHorizontal() ? center.x : center.y; + + zoomNS.zoomCumulativeDelta = zoom > 1 ? zoomNS.zoomCumulativeDelta + 1 : zoomNS.zoomCumulativeDelta - 1; + + if (Math.abs(zoomNS.zoomCumulativeDelta) > sensitivity){ + if(zoomNS.zoomCumulativeDelta < 0){ + if(centerPointer >= chartCenter){ + if (minIndex <= 0){ + maxIndex = Math.min(lastLabelIndex, maxIndex + 1); + } else{ + minIndex = Math.max(0, minIndex - 1); + } + } else if(centerPointer < chartCenter){ + if (maxIndex >= lastLabelIndex){ + minIndex = Math.max(0, minIndex - 1); + } else{ + maxIndex = Math.min(lastLabelIndex, maxIndex + 1); + } + } + zoomNS.zoomCumulativeDelta = 0; + } + else if(zoomNS.zoomCumulativeDelta > 0){ + if(centerPointer >= chartCenter){ + minIndex = minIndex < maxIndex ? minIndex = Math.min(maxIndex, minIndex + 1) : minIndex; + } else if(centerPointer < chartCenter){ + maxIndex = maxIndex > minIndex ? maxIndex = Math.max(minIndex, maxIndex - 1) : maxIndex; + } + zoomNS.zoomCumulativeDelta = 0; + } + scale.options.ticks.min = rangeMinLimiter(zoomOptions, labels[minIndex]); + scale.options.ticks.max = rangeMaxLimiter(zoomOptions, labels[maxIndex]); + } +} + +function zoomTimeScale(scale, zoom, center, zoomOptions) { + var options = scale.options; + + var range; + var min_percent; + if (scale.isHorizontal()) { + range = scale.right - scale.left; + min_percent = (center.x - scale.left) / range; + } else { + range = scale.bottom - scale.top; + min_percent = (center.y - scale.top) / range; + } + + var max_percent = 1 - min_percent; + var newDiff = range * (zoom - 1); + + var minDelta = newDiff * min_percent; + var maxDelta = newDiff * max_percent; + + var newMin = scale.getValueForPixel(scale.getPixelForValue(scale.min) + minDelta); + var newMax = scale.getValueForPixel(scale.getPixelForValue(scale.max) - maxDelta); + + var diffMinMax = newMax.diff(newMin); + var minLimitExceeded = rangeMinLimiter(zoomOptions, diffMinMax) != diffMinMax; + var maxLimitExceeded = rangeMaxLimiter(zoomOptions, diffMinMax) != diffMinMax; + + if (!minLimitExceeded && !maxLimitExceeded) { + options.time.min = newMin; + options.time.max = newMax; + } +} + +function zoomNumericalScale(scale, zoom, center, zoomOptions) { + var range = scale.max - scale.min; + var newDiff = range * (zoom - 1); + + var cursorPixel = scale.isHorizontal() ? center.x : center.y; + var min_percent = (scale.getValueForPixel(cursorPixel) - scale.min) / range; + var max_percent = 1 - min_percent; + + var minDelta = newDiff * min_percent; + var maxDelta = newDiff * max_percent; + + scale.options.ticks.min = rangeMinLimiter(zoomOptions, scale.min + minDelta); + scale.options.ticks.max = rangeMaxLimiter(zoomOptions, scale.max - maxDelta); +} + +function zoomScale(scale, zoom, center, zoomOptions) { + var fn = zoomFunctions[scale.options.type]; + if (fn) { + fn(scale, zoom, center, zoomOptions); + } +} + +function doZoom(chartInstance, zoom, center, whichAxes) { + var ca = chartInstance.chartArea; + if (!center) { + center = { + x: (ca.left + ca.right) / 2, + y: (ca.top + ca.bottom) / 2, + }; + } + + var zoomOptions = chartInstance.options.zoom; + + if (zoomOptions && helpers.getValueOrDefault(zoomOptions.enabled, defaultOptions.zoom.enabled)) { + // Do the zoom here + var zoomMode = helpers.getValueOrDefault(chartInstance.options.zoom.mode, defaultOptions.zoom.mode); + zoomOptions.sensitivity = helpers.getValueOrDefault(chartInstance.options.zoom.sensitivity, defaultOptions.zoom.sensitivity); + + // Which axe should be modified when figers were used. + var _whichAxes; + if (zoomMode == 'xy' && whichAxes !== undefined) { + // based on fingers positions + _whichAxes = whichAxes; + } else { + // no effect + _whichAxes = 'xy'; + } + + helpers.each(chartInstance.scales, function(scale, id) { + if (scale.isHorizontal() && directionEnabled(zoomMode, 'x') && directionEnabled(_whichAxes, 'x')) { + zoomOptions.scaleAxes = "x"; + zoomScale(scale, zoom, center, zoomOptions); + } else if (!scale.isHorizontal() && directionEnabled(zoomMode, 'y') && directionEnabled(_whichAxes, 'y')) { + // Do Y zoom + zoomOptions.scaleAxes = "y"; + zoomScale(scale, zoom, center, zoomOptions); + } + }); + + chartInstance.update(0); + } +} + +function panIndexScale(scale, delta, panOptions) { + var labels = scale.chart.data.labels; + var lastLabelIndex = labels.length - 1; + var offsetAmt = Math.max((scale.ticks.length - ((scale.options.gridLines.offsetGridLines) ? 0 : 1)), 1); + var panSpeed = panOptions.speed; + var minIndex = scale.minIndex; + var step = Math.round(scale.width / (offsetAmt * panSpeed)); + var maxIndex; + + zoomNS.panCumulativeDelta += delta; + + minIndex = zoomNS.panCumulativeDelta > step ? Math.max(0, minIndex -1) : zoomNS.panCumulativeDelta < -step ? Math.min(lastLabelIndex - offsetAmt + 1, minIndex + 1) : minIndex; + zoomNS.panCumulativeDelta = minIndex !== scale.minIndex ? 0 : zoomNS.panCumulativeDelta; + + maxIndex = Math.min(lastLabelIndex, minIndex + offsetAmt - 1); + + scale.options.ticks.min = rangeMinLimiter(panOptions, labels[minIndex]); + scale.options.ticks.max = rangeMaxLimiter(panOptions, labels[maxIndex]); +} + +function panTimeScale(scale, delta, panOptions) { + var options = scale.options; + var limitedMax = rangeMaxLimiter(panOptions, scale.getValueForPixel(scale.getPixelForValue(scale.max) - delta)); + var limitedMin = rangeMinLimiter(panOptions, scale.getValueForPixel(scale.getPixelForValue(scale.min) - delta)); + + var limitedTimeDelta = delta < 0 ? limitedMax - scale.max : limitedMin - scale.min; + + options.time.max = scale.max + limitedTimeDelta; + options.time.min = scale.min + limitedTimeDelta; +} + +function panNumericalScale(scale, delta, panOptions) { + var tickOpts = scale.options.ticks; + var start = scale.start, + end = scale.end; + + if (tickOpts.reverse) { + tickOpts.max = scale.getValueForPixel(scale.getPixelForValue(start) - delta); + tickOpts.min = scale.getValueForPixel(scale.getPixelForValue(end) - delta); + } else { + tickOpts.min = scale.getValueForPixel(scale.getPixelForValue(start) - delta); + tickOpts.max = scale.getValueForPixel(scale.getPixelForValue(end) - delta); + } + tickOpts.min = rangeMinLimiter(panOptions, tickOpts.min); + tickOpts.max = rangeMaxLimiter(panOptions, tickOpts.max); +} + +function panScale(scale, delta, panOptions) { + var fn = panFunctions[scale.options.type]; + if (fn) { + fn(scale, delta, panOptions); + } +} + +function doPan(chartInstance, deltaX, deltaY) { + var panOptions = chartInstance.options.pan; + if (panOptions && helpers.getValueOrDefault(panOptions.enabled, defaultOptions.pan.enabled)) { + var panMode = helpers.getValueOrDefault(chartInstance.options.pan.mode, defaultOptions.pan.mode); + panOptions.speed = helpers.getValueOrDefault(chartInstance.options.pan.speed, defaultOptions.pan.speed); + + helpers.each(chartInstance.scales, function(scale, id) { + if (scale.isHorizontal() && directionEnabled(panMode, 'x') && deltaX !== 0) { + panOptions.scaleAxes = "x"; + panScale(scale, deltaX, panOptions); + } else if (!scale.isHorizontal() && directionEnabled(panMode, 'y') && deltaY !== 0) { + panOptions.scaleAxes = "y"; + panScale(scale, deltaY, panOptions); + } + }); + + chartInstance.update(0); + } +} + +function positionInChartArea(chartInstance, position) { + return (position.x >= chartInstance.chartArea.left && position.x <= chartInstance.chartArea.right) && + (position.y >= chartInstance.chartArea.top && position.y <= chartInstance.chartArea.bottom); +} + +function getYAxis(chartInstance) { + var scales = chartInstance.scales; + + for (var scaleId in scales) { + var scale = scales[scaleId]; + + if (!scale.isHorizontal()) { + return scale; + } + } +} + +// Store these for later +zoomNS.zoomFunctions.category = zoomIndexScale; +zoomNS.zoomFunctions.time = zoomTimeScale; +zoomNS.zoomFunctions.linear = zoomNumericalScale; +zoomNS.zoomFunctions.logarithmic = zoomNumericalScale; +zoomNS.panFunctions.category = panIndexScale; +zoomNS.panFunctions.time = panTimeScale; +zoomNS.panFunctions.linear = panNumericalScale; +zoomNS.panFunctions.logarithmic = panNumericalScale; +// Globals for catergory pan and zoom +zoomNS.panCumulativeDelta = 0; +zoomNS.zoomCumulativeDelta = 0; + +// Chartjs Zoom Plugin +var zoomPlugin = { + afterInit: function(chartInstance) { + helpers.each(chartInstance.scales, function(scale) { + scale.originalOptions = JSON.parse(JSON.stringify(scale.options)); + }); + + chartInstance.resetZoom = function() { + helpers.each(chartInstance.scales, function(scale, id) { + var timeOptions = scale.options.time; + var tickOptions = scale.options.ticks; + + if (timeOptions) { + delete timeOptions.min; + delete timeOptions.max; + } + + if (tickOptions) { + delete tickOptions.min; + delete tickOptions.max; + } + + scale.options = helpers.configMerge(scale.options, scale.originalOptions); + }); + + helpers.each(chartInstance.data.datasets, function(dataset, id) { + dataset._meta = null; + }); + + chartInstance.update(); + }; + + }, + beforeInit: function(chartInstance) { + chartInstance.zoom = {}; + + var node = chartInstance.zoom.node = chartInstance.chart.ctx.canvas; + + var options = chartInstance.options; + var panThreshold = helpers.getValueOrDefault(options.pan ? options.pan.threshold : undefined, zoomNS.defaults.pan.threshold); + if (!options.zoom || !options.zoom.enabled) { + return; + } + if (options.zoom.drag) { + // Only want to zoom horizontal axis + options.zoom.mode = 'x'; + + chartInstance.zoom._mouseDownHandler = function(event) { + chartInstance.zoom._dragZoomStart = event; + }; + node.addEventListener('mousedown', chartInstance.zoom._mouseDownHandler); + + chartInstance.zoom._mouseMoveHandler = function(event){ + if (chartInstance.zoom._dragZoomStart) { + chartInstance.zoom._dragZoomEnd = event; + chartInstance.update(0); + } + + chartInstance.update(0); + }; + node.addEventListener('mousemove', chartInstance.zoom._mouseMoveHandler); + + chartInstance.zoom._mouseUpHandler = function(event){ + if (chartInstance.zoom._dragZoomStart) { + var chartArea = chartInstance.chartArea; + var yAxis = getYAxis(chartInstance); + var beginPoint = chartInstance.zoom._dragZoomStart; + var offsetX = beginPoint.target.getBoundingClientRect().left; + var startX = Math.min(beginPoint.clientX, event.clientX) - offsetX; + var endX = Math.max(beginPoint.clientX, event.clientX) - offsetX; + var dragDistance = endX - startX; + var chartDistance = chartArea.right - chartArea.left; + var zoom = 1 + ((chartDistance - dragDistance) / chartDistance ); + + if (dragDistance > 0) { + doZoom(chartInstance, zoom, { + x: (dragDistance / 2) + startX, + y: (yAxis.bottom - yAxis.top) / 2, + }); + } + + chartInstance.zoom._dragZoomStart = null; + chartInstance.zoom._dragZoomEnd = null; + } + }; + node.addEventListener('mouseup', chartInstance.zoom._mouseUpHandler); + } else { + chartInstance.zoom._wheelHandler = function(event) { + var rect = event.target.getBoundingClientRect(); + var offsetX = event.clientX - rect.left; + var offsetY = event.clientY - rect.top; + + var center = { + x : offsetX, + y : offsetY + }; + + if (event.deltaY < 0) { + doZoom(chartInstance, 1.1, center); + } else { + doZoom(chartInstance, 0.909, center); + } + // Prevent the event from triggering the default behavior (eg. Content scrolling). + event.preventDefault(); + }; + + node.addEventListener('wheel', chartInstance.zoom._wheelHandler); + } + + if (Hammer) { + var mc = new Hammer.Manager(node); + mc.add(new Hammer.Pinch()); + mc.add(new Hammer.Pan({ + threshold: panThreshold + })); + + // Hammer reports the total scaling. We need the incremental amount + var currentPinchScaling; + var handlePinch = function handlePinch(e) { + var diff = 1 / (currentPinchScaling) * e.scale; + var rect = e.target.getBoundingClientRect(); + var offsetX = e.center.x - rect.left; + var offsetY = e.center.y - rect.top; + var center = { + x : offsetX, + y : offsetY + }; + + // fingers position difference + var x = Math.abs(e.pointers[0].clientX - e.pointers[1].clientX); + var y = Math.abs(e.pointers[0].clientY - e.pointers[1].clientY); + + // diagonal fingers will change both (xy) axes + var p = x / y; + var xy; + if (p > 0.3 && p < 1.7) { + xy = 'xy'; + } + // x axis + else if (x > y) { + xy = 'x'; + } + // y axis + else { + xy = 'y'; + } + + doZoom(chartInstance, diff, center, xy); + + // Keep track of overall scale + currentPinchScaling = e.scale; + }; + + mc.on('pinchstart', function(e) { + currentPinchScaling = 1; // reset tracker + }); + mc.on('pinch', handlePinch); + mc.on('pinchend', function(e) { + handlePinch(e); + currentPinchScaling = null; // reset + zoomNS.zoomCumulativeDelta = 0; + }); + + var currentDeltaX = null, currentDeltaY = null, panning = false; + var handlePan = function handlePan(e) { + if (currentDeltaX !== null && currentDeltaY !== null) { + panning = true; + var deltaX = e.deltaX - currentDeltaX; + var deltaY = e.deltaY - currentDeltaY; + currentDeltaX = e.deltaX; + currentDeltaY = e.deltaY; + doPan(chartInstance, deltaX, deltaY); + } + }; + + mc.on('panstart', function(e) { + currentDeltaX = 0; + currentDeltaY = 0; + handlePan(e); + }); + mc.on('panmove', handlePan); + mc.on('panend', function(e) { + currentDeltaX = null; + currentDeltaY = null; + zoomNS.panCumulativeDelta = 0; + setTimeout(function() { panning = false; }, 500); + }); + + chartInstance.zoom._ghostClickHandler = function(e) { + if (panning) { + e.stopImmediatePropagation(); + e.preventDefault(); + } + }; + node.addEventListener('click', chartInstance.zoom._ghostClickHandler); + + chartInstance._mc = mc; + } + }, + + beforeDatasetsDraw: function(chartInstance) { + var ctx = chartInstance.chart.ctx; + var chartArea = chartInstance.chartArea; + ctx.save(); + ctx.beginPath(); + + if (chartInstance.zoom._dragZoomEnd) { + var yAxis = getYAxis(chartInstance); + var beginPoint = chartInstance.zoom._dragZoomStart; + var endPoint = chartInstance.zoom._dragZoomEnd; + var offsetX = beginPoint.target.getBoundingClientRect().left; + var startX = Math.min(beginPoint.clientX, endPoint.clientX) - offsetX; + var endX = Math.max(beginPoint.clientX, endPoint.clientX) - offsetX; + var rectWidth = endX - startX; + + + ctx.fillStyle = 'rgba(225,225,225,0.3)'; + ctx.lineWidth = 5; + ctx.fillRect(startX, yAxis.top, rectWidth, yAxis.bottom - yAxis.top); + } + + ctx.rect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + ctx.clip(); + }, + + afterDatasetsDraw: function(chartInstance) { + chartInstance.chart.ctx.restore(); + }, + + destroy: function(chartInstance) { + if (chartInstance.zoom) { + var options = chartInstance.options; + var node = chartInstance.zoom.node; + + if (options.zoom && options.zoom.drag) { + node.removeEventListener('mousedown', chartInstance.zoom._mouseDownHandler); + node.removeEventListener('mousemove', chartInstance.zoom._mouseMoveHandler); + node.removeEventListener('mouseup', chartInstance.zoom._mouseUpHandler); + } else { + node.removeEventListener('wheel', chartInstance.zoom._wheelHandler); + } + + if (Hammer) { + node.removeEventListener('click', chartInstance.zoom._ghostClickHandler); + } + + delete chartInstance.zoom; + + var mc = chartInstance._mc; + if (mc) { + mc.remove('pinchstart'); + mc.remove('pinch'); + mc.remove('pinchend'); + mc.remove('panstart'); + mc.remove('pan'); + mc.remove('panend'); + } + } + } +}; + +module.exports = zoomPlugin; +Chart.pluginService.register(zoomPlugin); + +},{"chart.js":1,"hammerjs":1}]},{},[2]); diff --git a/infosouth-admin/src/main/resources/static/oneself/chartjs/customer_utils.js b/infosouth-admin/src/main/resources/static/oneself/chartjs/customer_utils.js new file mode 100644 index 000000000..214e45159 --- /dev/null +++ b/infosouth-admin/src/main/resources/static/oneself/chartjs/customer_utils.js @@ -0,0 +1,349 @@ +function drawCharts(result_paramsArr_data,filesNameStr){ + var paramAllData = []; + if(filesNameStr!='allFiles'){//如果不是选择的所有文件 + //解析filesNameArr,获取新的result_paramsArr_data--------------------- + result_paramsArr_data = getNewresult_paramsArr_data(result_paramsArr_data,filesNameStr); + //解析filesNameArr,获取新的result_paramsArr_data--------------------- + } + + var result_paramsArr_dataLen = result_paramsArr_data.length; + //每个图表容器的高度 + chart_containerHeight = parseInt(page_total_height/result_paramsArr_dataLen); + //注销之前的图形缓存,图表1,初始图表 + myLineChart.destroy(); + //注销之前的图形缓存,2个以上的图表 + for(var charti=0;charti-1){ + for(var ii=0;ii\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",f=a.console&&(a.console.warn||a.console.log);return f&&f.call(a.console,e,d),b.apply(this,arguments)}}function i(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&la(d,c)}function j(a,b){return function(){return a.apply(b,arguments)}}function k(a,b){return typeof a==oa?a.apply(b?b[0]||d:d,b):a}function l(a,b){return a===d?b:a}function m(a,b,c){g(q(b),function(b){a.addEventListener(b,c,!1)})}function n(a,b,c){g(q(b),function(b){a.removeEventListener(b,c,!1)})}function o(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function p(a,b){return a.indexOf(b)>-1}function q(a){return a.trim().split(/\s+/g)}function r(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;dc[b]}):d.sort()),d}function u(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g1&&!c.firstMultiple?c.firstMultiple=D(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=E(d);b.timeStamp=ra(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=I(h,i),b.distance=H(h,i),B(c,b),b.offsetDirection=G(b.deltaX,b.deltaY);var j=F(b.deltaTime,b.deltaX,b.deltaY);b.overallVelocityX=j.x,b.overallVelocityY=j.y,b.overallVelocity=qa(j.x)>qa(j.y)?j.x:j.y,b.scale=g?K(g.pointers,d):1,b.rotation=g?J(g.pointers,d):0,b.maxPointers=c.prevInput?b.pointers.length>c.prevInput.maxPointers?b.pointers.length:c.prevInput.maxPointers:b.pointers.length,C(c,b);var k=a.element;o(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function B(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};b.eventType!==Ea&&f.eventType!==Ga||(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function C(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ha&&(i>Da||h.velocity===d)){var j=b.deltaX-h.deltaX,k=b.deltaY-h.deltaY,l=F(i,j,k);e=l.x,f=l.y,c=qa(l.x)>qa(l.y)?l.x:l.y,g=G(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function D(a){for(var b=[],c=0;ce;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:pa(c/b),y:pa(d/b)}}function F(a,b,c){return{x:b/a||0,y:c/a||0}}function G(a,b){return a===b?Ia:qa(a)>=qa(b)?0>a?Ja:Ka:0>b?La:Ma}function H(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function I(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function J(a,b){return I(b[1],b[0],Ra)+I(a[1],a[0],Ra)}function K(a,b){return H(b[0],b[1],Ra)/H(a[0],a[1],Ra)}function L(){this.evEl=Ta,this.evWin=Ua,this.pressed=!1,x.apply(this,arguments)}function M(){this.evEl=Xa,this.evWin=Ya,x.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function N(){this.evTarget=$a,this.evWin=_a,this.started=!1,x.apply(this,arguments)}function O(a,b){var c=s(a.touches),d=s(a.changedTouches);return b&(Ga|Ha)&&(c=t(c.concat(d),"identifier",!0)),[c,d]}function P(){this.evTarget=bb,this.targetIds={},x.apply(this,arguments)}function Q(a,b){var c=s(a.touches),d=this.targetIds;if(b&(Ea|Fa)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=s(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return o(a.target,i)}),b===Ea)for(e=0;e-1&&d.splice(a,1)};setTimeout(e,cb)}}function U(a){for(var b=a.srcEvent.clientX,c=a.srcEvent.clientY,d=0;d=f&&db>=g)return!0}return!1}function V(a,b){this.manager=a,this.set(b)}function W(a){if(p(a,jb))return jb;var b=p(a,kb),c=p(a,lb);return b&&c?jb:b||c?b?kb:lb:p(a,ib)?ib:hb}function X(){if(!fb)return!1;var b={},c=a.CSS&&a.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(d){b[d]=c?a.CSS.supports("touch-action",d):!0}),b}function Y(a){this.options=la({},this.defaults,a||{}),this.id=v(),this.manager=null,this.options.enable=l(this.options.enable,!0),this.state=nb,this.simultaneous={},this.requireFail=[]}function Z(a){return a&sb?"cancel":a&qb?"end":a&pb?"move":a&ob?"start":""}function $(a){return a==Ma?"down":a==La?"up":a==Ja?"left":a==Ka?"right":""}function _(a,b){var c=b.manager;return c?c.get(a):a}function aa(){Y.apply(this,arguments)}function ba(){aa.apply(this,arguments),this.pX=null,this.pY=null}function ca(){aa.apply(this,arguments)}function da(){Y.apply(this,arguments),this._timer=null,this._input=null}function ea(){aa.apply(this,arguments)}function fa(){aa.apply(this,arguments)}function ga(){Y.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function ha(a,b){return b=b||{},b.recognizers=l(b.recognizers,ha.defaults.preset),new ia(a,b)}function ia(a,b){this.options=la({},ha.defaults,b||{}),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=a,this.input=y(this),this.touchAction=new V(this,this.options.touchAction),ja(this,!0),g(this.options.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function ja(a,b){var c=a.element;if(c.style){var d;g(a.options.cssProps,function(e,f){d=u(c.style,f),b?(a.oldCssProps[d]=c.style[d],c.style[d]=e):c.style[d]=a.oldCssProps[d]||""}),b||(a.oldCssProps={})}}function ka(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var la,ma=["","webkit","Moz","MS","ms","o"],na=b.createElement("div"),oa="function",pa=Math.round,qa=Math.abs,ra=Date.now;la="function"!=typeof Object.assign?function(a){if(a===d||null===a)throw new TypeError("Cannot convert undefined or null to object");for(var b=Object(a),c=1;ch&&(b.push(a),h=b.length-1):e&(Ga|Ha)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Za={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},$a="touchstart",_a="touchstart touchmove touchend touchcancel";i(N,x,{handler:function(a){var b=Za[a.type];if(b===Ea&&(this.started=!0),this.started){var c=O.call(this,a,b);b&(Ga|Ha)&&c[0].length-c[1].length===0&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}}});var ab={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},bb="touchstart touchmove touchend touchcancel";i(P,x,{handler:function(a){var b=ab[a.type],c=Q.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}});var cb=2500,db=25;i(R,x,{handler:function(a,b,c){var d=c.pointerType==za,e=c.pointerType==Ba;if(!(e&&c.sourceCapabilities&&c.sourceCapabilities.firesTouchEvents)){if(d)S.call(this,b,c);else if(e&&U.call(this,c))return;this.callback(a,b,c)}},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var eb=u(na.style,"touchAction"),fb=eb!==d,gb="compute",hb="auto",ib="manipulation",jb="none",kb="pan-x",lb="pan-y",mb=X();V.prototype={set:function(a){a==gb&&(a=this.compute()),fb&&this.manager.element.style&&mb[a]&&(this.manager.element.style[eb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){k(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),W(a.join(" "))},preventDefaults:function(a){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=p(d,jb)&&!mb[jb],f=p(d,lb)&&!mb[lb],g=p(d,kb)&&!mb[kb];if(e){var h=1===a.pointers.length,i=a.distance<2,j=a.deltaTime<250;if(h&&i&&j)return}return g&&f?void 0:e||f&&c&Na||g&&c&Oa?this.preventSrc(b):void 0},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var nb=1,ob=2,pb=4,qb=8,rb=qb,sb=16,tb=32;Y.prototype={defaults:{},set:function(a){return la(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=_(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=_(a,this),-1===r(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=_(a,this);var b=r(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(b,a)}var c=this,d=this.state;qb>d&&b(c.options.event+Z(d)),b(c.options.event),a.additionalEvent&&b(a.additionalEvent),d>=qb&&b(c.options.event+Z(d))},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=tb)},canEmit:function(){for(var a=0;af?Ja:Ka,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ia:0>g?La:Ma,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return aa.prototype.attrTest.call(this,a)&&(this.state&ob||!(this.state&ob)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$(a.direction);b&&(a.additionalEvent=this.options.event+b),this._super.emit.call(this,a)}}),i(ca,aa,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&ob)},emit:function(a){if(1!==a.scale){var b=a.scale<1?"in":"out";a.additionalEvent=this.options.event+b}this._super.emit.call(this,a)}}),i(da,Y,{defaults:{event:"press",pointers:1,time:251,threshold:9},getTouchAction:function(){return[hb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distanceb.time;if(this._input=a,!d||!c||a.eventType&(Ga|Ha)&&!f)this.reset();else if(a.eventType&Ea)this.reset(),this._timer=e(function(){this.state=rb,this.tryEmit()},b.time,this);else if(a.eventType&Ga)return rb;return tb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===rb&&(a&&a.eventType&Ga?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=ra(),this.manager.emit(this.options.event,this._input)))}}),i(ea,aa,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&ob)}}),i(fa,aa,{defaults:{event:"swipe",threshold:10,velocity:.3,direction:Na|Oa,pointers:1},getTouchAction:function(){return ba.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Na|Oa)?b=a.overallVelocity:c&Na?b=a.overallVelocityX:c&Oa&&(b=a.overallVelocityY),this._super.attrTest.call(this,a)&&c&a.offsetDirection&&a.distance>this.options.threshold&&a.maxPointers==this.options.pointers&&qa(b)>this.options.velocity&&a.eventType&Ga},emit:function(a){var b=$(a.offsetDirection);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),i(ga,Y,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:9,posThreshold:10},getTouchAction:function(){return[ib]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance{XX9s8XB6AkU%672L}f$Dk|pZ=bM_E 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 literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/b2.gif b/infosouth-admin/src/main/resources/static/oneself/images/b2.gif new file mode 100644 index 0000000000000000000000000000000000000000..21b9e2c4ff31ef4627193cb4d261554f79083d49 GIT binary patch literal 4987 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 Qd;P7LfwrF*5C}N?e>PW|!~g&Q literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/b3.gif b/infosouth-admin/src/main/resources/static/oneself/images/b3.gif new file mode 100644 index 0000000000000000000000000000000000000000..641bedd16f06ff4879f2027e1cd6e036c0f402d2 GIT binary patch literal 6049 zcmb7<_dnDRz`#Fu&fOW+*-~U>g_MLeE*Xcz5t-@8&Nw4`oW1ut`|Q2X$ zlarHApFS-vF5cPM(bv~^c6M%TY&m^=S->V3CK z!kAzCYR&TU^6~L8g+c-T|L~ka{x1^!U;pnD0Hq+)a41oZxZy(Q5xYmZ)1|JeRfaW- zm2P9dyn5DZJ<#HrQ#*}b6Am4#{G} zXO+k2fB#W_oVL*>0J@_qW=LkeGs?*KCa>;2F_dW!X=uPUtg$ z^0Kah`>uEco$qB=m>vlgb~L4jT@#HIAjQ`w8xm=rh;kn1fhThk9L=!AI>nIr0)fV1 zOdhY1`3f*&1y`rwLJ4=?fO3K*G(uiop@6<8VePlZPv4G1o2utqzyTzsF5+OCGJ0!K9CLHpF zg#cwDxglPvUyma#=vr@D_39(q?d)$faoaE*77y%mPpDPdUQaWJ(9tb7~svMT{<1xN$Df=I8hFr^Hl zYV(C})288*Dx7Gt6pY{3f;{M5Nt>yRcBpK_gwKQP_h``g=TH#T#_YM;f9~dQRQj|R z^)wY9zRkW`E=15w`IQKwy1|b$(sJT>KMgS{R$Nn$y0;!ch-N7Y(303{Ni%QAR#{NZ ze~)C*+nA81HM@xl{gms?HTzt_A58N_*-DIN)^eD$0V`}JU%J{@kGRmW1DLVT0v;yam zu;GL90JNTZ#hV5a?t&q;&<7tMPCFtep1!3Rp(`(waQ`OOIe$=qipOI*z^4Fd$<^KI zQERFy^G8lKhGwNOzIl@4XJlqjj+=}!;TX|$y7X6u>CL0U=d)tx3T#WxLsmK^icTbu*H`tO-r4cf)XZ`v z>IG|@%$-jLHUV;3lw8O>YbfYBvvZD&xKOsu3DnF2+wsejj!zclHq=Nv2|vqm{8A{y zddudCZhYsxQmYXpb+-NR(krX`=5@mNXWkRnhojUhSk!UYVK9)3_aFRl_)ph00)5iaDayy3%oNXF(8n@ z{qGbq@D4%(XxG4?jf5C+BJw8Rhwlh_1Z#Rdb>Gt_wxkPOBV!BBc+tda)+=E6Wg3RpNT@-5#P z3J&VLf29m9Po-}#0^byHlH1ma<((1w*Ja7`|g}x=v{AVb2r4s;Q z0fPo@Fu{{aIYFd#4wf}_zYLeui{MS=IOLdgvvc7KeL(&-Su^6k3xY!L`vTxyQ;(^h zqo&5-5#o^_k&kCVk0z{87s7M=^rTE$ZcAnkY8XY*q{JWVnKS$j^zbW>xsyxN}B8n1l}kZijhpL{3*u&Vq_5a-8r#+ zrOLHLZRNY+N&DhNwOh;B%AVIr$J&(|k0G`H4l_4nfn`F-hU*TWub4~L z4@N`6T?7}{K}}bIT!CMbA@8D0d#eqm(I%2+6sHK_i-uHX!sU)x+fUfksA&^)#abCw zu}gESZ7$>?IPY}^WLoKd*2CL@+?k_4cxt__LE!?NooE9d(Y2%|u6u&poiA6mnEO9+ z2HHv623N8^AB!n+=1#P?l_BX)h%ep&6zqT4yiF?Y`FB4q0&8U-l`$4D@ZLDDGE8Y9 zuj*Y+Sy_R-IjZ?nrn3~-Y5jaXIh3_tctBL6;%6Y0d3qvVpA@l7JWw(F4XXe3z~GJ@ zgpp}(;d7SsXbcwrhLNYP>66pI?_rfK#`F!DskTY?$=^8_m)po|?bBfzNBKAY?w~Z= zXVR=!i{<|AV&dB8-nJf<8~y#RKh-|pGD$hE_Wt_=d#z(}NaIg^=HH*znsRLBq7)%X&6TDMfDD;!0S^SyMG(qaT`$=5bfz5 z|K4ZhnU*kq2*}gIRci9)u}_cMoJ=fV`!7xBDFxnH@qtXy1uVUHkh{eiV>Kd>IRO!r zx5R=moEPJS#OsKhjsHI1!ob-F!)=;~} zP|dJV9DA6vOqi>Fn43qK2O-R>HOyx*%T$&%2}i)wpg9dMbrGT>Z5iP zmD2ew;NMnirG)ejnA2Jvf~5<@7)|@6hT3dx1cC|5RqT$!Y|$t@sxmF8u*m0Im;)a9 zZex*p+X{8F$nU}$`%BP)`?lj~qjtz<9H*{-fC8ka1vXq7`*zxY5^4`Jz*4bmcsApj z=ADv5BaNH=M_X~;xPUD;bdW`&Y+Ax8;a$#FaO!~PwO#+>IcMFJK!>J4D)$7)AOl)@{h_W~y0iL^^K4T~2uWxCp4o zj;1Ia{~i_u7Ys5q@MEwIQaSVKaCiD#46~L>b>I$GkV)Yy$+2^FmM?Q2Nsmqo^Fuvy zc_pN6&`vO3Dl$1Q!g3UwJt{UgEVlG2wia>oXe+i`Dz?uk#&MK5KPquGEOGNH@yICg zYA^9wDzQ(e7c~KvUKtvo|FG8|X-m zZe^?ZYmq&$8((6jv#jDnb(|gF91R1MD^&uL-C{qUW&nKVS}qO|QJ0Fw#wi9Zkl|O(qvj*c;7ea?R#O%@o5s5uSzR7ThX6 zQcm$Ac3UE*T~ZoN)F^9jl`NZZWg;q?zf5$X!2wcby9_H|RC#IZ`A(OPPIm- zRrQrxi|ebBr9jP6yAL|>o^bTmcTdOUJSG8kdCQngwH$^e_0R#&bsddu*G6+(o#nK~ zC`9v+xrM<}b9!5Iv9+#wM0R`|Uhd?jcXP+x^6bAVH5vnji)x)7*eX-JuA!n9@lFeb<<(73 z^mVU79YT;@N)oOq<&3@F2B)VOujjosJ;PRmNVdq$eXyp zW*-}9EyX^?Fx(>g+JAR%TiCi??l2IFJ>UnrlS8Ui| zx%}bjb)60ZFkm;IQV1KN)Vbc_dH`3&f14H#Zlpvz6g z9+rNU2`?f9$EKEgrL~N0mj=+4NeyOj4t2X>0K$S@FriF-K7w+dk;s=j-qY)y_hd7C2_MZTM8NvWa#iPgG-M z$?Lx}>sr_0nn6?lQJp!C)?L}b*P^3zmpLmUxgfS`${;ITZ(g~a9(vJ+Z`jJs`C_!PT{?=pzFr4#JQk% z#6qpMJ_XVgSY_~uTD$^w@{&JaLb_3|smG9`%IM|{?~@t+*E0gXGeX%jA~C7xFEiqQ zXVPkC?mwA*@Ot*4@2pJr?4zz(tqnC(mGC#?=HaMxIim*a%2Ml}>2Z(V=Cu_$io%`8 z)#UVtBHV|#C!&7RW(Km9H=YgE%#D?nX9ghgl-IlEJ!Qk6?JW1d4<}@0RhLYp&|CdB zhW+LrxfmVkJ+JB1t8C8bGSeMhX{#*ljPXU{KP*DGRN_7vj{ns49r;<^H(b~HSgqYB z&VTw<`gqHEMD=C57h_C9_2=rnvthQ0an37%i6kAt;7wp4$<(<2dxfiQwfbz(OoA0Itu`G zNAQ)x)Z_X`LJfGV*`!qi*U5B4bb-d`hqzC@55}E2#2WR=jdeXfJ@#Ea&0an4TD@FZ z{r7hjaG;iWvIa3(3q!2IbJl3P*XaLSqg?&BhT!_@q_0uT|8|BG8YnUsoMEs~WfJYt z60FnWL;bB>H8)Udj(}42a_xJMRk}(>6K(`m#4IOpjm{ZJ)y#z4Tq@grSw8 zN!PvJuW8jKzAt^mNiM{#tmHmh+{8b_?}hGWPdb~6=q42DU(?XW4GK1z(jcXLd^`S@;8X@Rie1ltWj(KGoZI!H}8>Y*R? z3_prK26{E7VYh0xQ28TnumEJQGk=nDM>J$&e2$T8@7vS84U@eszrCHDz3<(7E;eg> z|Mv99_70!!ADQg`@!LPm*+1{zzx;3iU-up_9>R?ULEeyA0T2QJi%XE9t7KLpSrG~5 zM>Y%L$*le$);O}z8dwkq;@UsBjRf&(f>_tUcO(vZ{Xsm>4(}i#0!WZZ+@S!ui6xFK zOg`Yp9^9BBv(|#yaA4@QgU5~__BUii4;di=7LGsQ;|5D!YvztW;`9ge0U%AsL%!7` zAx)6jK3L`1;XO?dMfWa*RRYY+eJqXz@ghOWt4%^kuULWFAn@ZrE_72x-jgV?wO!T1vd_QWTSO#AFCj&guNLWGE5UT!d- z1laysGaKem0eQsW4>EdoDi47C??M9ZLMn5?e8@A2{ZnB?v+1+L+lULgHz!uP2fWW9 z2yQUE2FxBu9$Y=YgFInFf~lXKMQWZSrpZZ;r?=z5w`>0h_568(2Qw4Fh1W-1R-XsteHH?Pt$~6Y2*W61S zoXgx9$y|y;p=b@1lB$k^xY82p6|2f)wM*ugx_Smiuix~dXDp|pL;tf}4Oh@1h>NW$ z@#tvSnZ_j~rKF{2X6NP=6qS@!RMpfqG_|yKboKOp7#JEEo0$4I`)T3x^2+Mh_08?w uAHVhwejlHlUHqkhpv*Gy*ylko1_7Pcc+(eQ*LakYWfIH=T%H4f-2VVso?Joz literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/b4.gif b/infosouth-admin/src/main/resources/static/oneself/images/b4.gif new file mode 100644 index 0000000000000000000000000000000000000000..f423c722de6adb0ff3276a1812eb27bcc47b42c6 GIT binary patch literal 4240 zcmd6q`!~~%ot+&W9rf|?@$&M*U@&YpJ2*HPjYbgnGa=F~C ztt|?L^5e&kzP`S;wzlNto-2s6eynqR6{M3x=FhRE)?T|56^eN)h+j|B*PopM2 zKO7@b$I-{zP`4XrpN>q`)z%6G0^t8yPV9jHj|lO<{@*5mh#(Rfjg7&@#>L|a2`>|q zl2cx#64TO28Dt7IGb=kMmzI}bP*_x4Qc5pllvh+%RoB$k)iWDdg*G}>Dq?dyME+B5KBc;sW!(CEbERK29QxMbq^r`fsr0_pwxrR86KTUcFNPnC$? zr@GAD*!}ZwEJXCoNN)*)_67@)RdwsC&TEg8QnbplsLAh0IH2wOsjEhzP;9zwZo|A* z=|WVr4(fnUZBei90b$>+*7c(P%q~Q@iGt1X_qj&&W>Kqp@9Mm(MAahPGx~5z8TCrG zm3-PrnRDH(#xf>jjC!Y?aQkgw`9$UYfwCfMP=%|#vcRgzXgxm$@8LhaDBf{Gn4la9 zDu{pcrF5V<-Yx(l!`7Nnz`dBeZoP9utds0nes)z|X}pJak+Pk@(IRjwr0NyJ&euP@ ze#*-8%+O+##c0)I3}ndoYMj)u$mW!v+h&X?u%YUm_f4FQg~5VrxyPW`sD~9#f48q; z@xNE5U(E2#j%cfiGcG?|7!zs=Te;Yk@wgAh;cu;9m941aNz+k!Sdb0H&71xw2z9xl&S4Ahj%ZTcXXqt-aRHH^y0bkxd z%QFC|O$HSW-6M4-9yh0c=n=0sYMwn~LPke_H=*3g_PIuNZx3GG^)rc^214Q4Zl<(I6wS@?So`%YKhfeNciyZb#vQ855zMj$#hSKGb$=7hVL0u zik7fjOelfHTkVxLl7Z`0ztdMEFt3n%_DGlx0?6*`B}=t^=YA~J4F+vOgryOyF+w_D zylz&Z*Y~uGD5;#NWGjUO?dpl|*LiT!a(+zU?^kdA$?VqFcJ?-*x1GZ*RO@Xlu@Cca zAS^ZZH=(|+8@GtPKqb7c0sLUX(`?31!8M3RK(F|hvoAHEdYcJ8Bqa&V&3CNv8Ljqn z@qVh^YSbq6Hr7)0lNLj^wOZfVo|jtv4RQh6EoMA1#DG43Nv5YkEW2t*L0Hr|=a1&? zgyHQg{&^$5S0;TgI}S&0v2ST~>3-aex!61YmDE2yVZ|zJK=`SB`4xr^dwzD%sqT3& z!9wUD%kpXGjo;In!V$AGr{pDiztkIvCA@7oP@ed$%IH$UY?ZBh!rTOEnJ{0AUM4IQ z@J5U(*Z7JUwZcvhj9O`ehcTuC+s_)0Fu!z`daKOi&a%TwOVCQDAmYI){Ta*#IdoOy z-^~%H$N!q9B3dQZd=4Y^){E4Rs|YseU!Sgh_{EfSI;tM$e>3k6mKB4G~fXz48Az)|ZC5m)Ip`!T z$$L(G(0KamDGDSAZ0&ijE_2ekK+!Re4 z4@)DWi(q#x;Vu%1q|k3>&_F2QezGS+PpDYkzlb2Fa4mwQP^`5R)0YmH4LLQHCiGvI z-d%h`ZSkcl`art7EmP(8DeT*!W{GrO?>jf+uC`aH?NPzs1&Gi5aI)yd`zFD^26H}k=1{6tG}@eDM)_A# z3Kf)2!+hhhgtK{@Jv@XSrannIG5tixg2fipFyh8gZi!GS!p+x`tZZHUy3l8Y1V?0f zTq$HLz~R;ySX$DRBDz39^<-k1R-y7ux~u2n2pSG8{d}dYfK~=CSA~^d!KNl_GSmlE zVN6nVMIQPGyuQr5(s9^x%+38A4mw6y)G50lPeXP?>?ffP(K!DYw}-}Kw&Uq?A$xJ| z*WZlk@;@?0!HkKwle%q>JZkGp5h`a434IYBbwxbH{>xK(vC0E^(YR8d75rerS(*As z`JYo3T$o7t`&)A9OLqsT&cbKTr6l%Gdz!q8ic-#yF3raIUVd}Sjy)<{%>-W)Ju#*H zffU>ze*96V-nhNr%(=Y@CE*L#ruhxBGFbt@lROvvQjZ5WhxbUOWeUG~!{eyJ^Tj6% zlWvlieishmW(3cSYa~7eYS)h6*1Ufh(Jtbo+jcTb^Ymzq!M1XKQ^uyha#U}1YpoND zZM3H1;AXY&@^yBI;u#mkFVoHdTXv7|-YEUMD7&uhbe*K4#JX6|)(LyGO|xn8-8D}e z@Q$p>XVX_E0kgN2IT_cKU5T>4XFJUFsfTRTd4l8wP3TPFZ=wjX-2}%oM$Y@-*fpM<#Oo!-(nZ;Ly|}43g1iV-ND2c zHl{RJEuOU;RW|OOY5v6;-o`PF<|Wsv-N}SjTSbqNaur==n`XTI9gmOM-hl=59dE9g zK|0ZW4z4OdeG+y?w3IY&zR*^GcippL*zwP^(??L3yf=OowM#tk*TuLd&5sr^j0OU~ zBm9rwL5QG$nKn4(vH)EW202=+5U$(sJ z*5Hlj^^T7hA3dc$onQX*@nZ7UzytAbw;nuaxF-9IVRyH_#6B&5Qh2G0a0a<}EpS*9PfYc{QPp35S~^!q{|1>|}j;T`JavzQWFhX$HEIxFY?xyA^s z<+`ogl{EFKBR5`}gf79(7-9$hUUZhV9ThHQ9-aO?#y-Bap;sA}WIg~3RCewOI~_Q! zz8j1XX{o?g#ej4)-PiZENW~$|zN*!PSnK4-B;PUJf=Y+hA&>n`ciNqsIQGo`Ko-d;gyH5}12|EPRAQ!o8Kl4qpvh z^bC6v6ZWhytavpd+BTvtID(lG#9{?;#)7y`k)|`8Vcle7H=hmz?wEecKiX4p<)Qk{dIJOvJ&a%%T4TL#OqiUoxP_&PORYN1Y6b zQX)qwpSRr6bKU*zL|cgN62_hr3A<#0J?@P?L5@&lN1PguIPHzeio@iTU~YC|93I3v zEd;5QzEI_PBfS0YsbIoYf-WA2^7Y2~#p528;?P~VCp_E>NNkjaAC~8_lo1+X5hv^& z2Z@h!FNs41$A`ql5}f07L*n$var*2yLzPIpx6kExA7hBQiG_`sw~e_94DO^LblSH& z<6$rBR)5KZfefc1Jt$j7YHBzD3(cD}@b zvjo^BMQ9>rE#=7(mbfTXe214}c>^lTagxW29mFdfJ?MIvBDS9+e*&I*gf0(G0rn^W zP?Wk*bt-}mU{QdO0z_B=qy>k7BZ*K2B9aEE!a-mf3=9x2?tnF*#69SvmZ52uP~un~ zOhf^+i%U}rO+!Wknl8lXRzR&goemJM?10VaX%JhICLTa?Qtjw4F@WSqA>QMpdQPO@ znGh4U1>88mnS<#cL#iun)}w47P~4)n{%OojmVC40E!{4`4p5ylAI6H{9QPj+SjP znazY36j2IG0pea7)qs+#NJzVefguUxN;*-^rwEBozoehT;)n?YG}^kp#60H>^!zawd4nFVTOywwDtQt9BqjH`sa3kHzGzS($6de{0- zQkFrE2?1e9pwxvHI8rOi01#>-a~hh}$InDo12VQ*N_--eMt#$mUDs1duO>&+fIXuY8e!Zz{{nfB~i_Cf}ZoTzX zz0GdD?P2B(L#Dke(=m+coXNb!Wx7o<-FKO&-F+aN4pK^ b!>lKUtY@yQpfFZQCJV!5g>xIC0Ko7+(C*tV literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/b5.gif b/infosouth-admin/src/main/resources/static/oneself/images/b5.gif new file mode 100644 index 0000000000000000000000000000000000000000..94f6f0164d849b52242b04a4d3aba3e7c63adc9d GIT binary patch literal 5418 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 U+P&S}-QC^?{oUaGUI76BJ5w2|AOHXW literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/b6.gif b/infosouth-admin/src/main/resources/static/oneself/images/b6.gif new file mode 100644 index 0000000000000000000000000000000000000000..cbacd6c4681e57f62df71472abc44f24ed635311 GIT binary patch literal 50223 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 literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/body_dl.jpg b/infosouth-admin/src/main/resources/static/oneself/images/body_dl.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c706d8dafb1d13a78626f0543ee5cdc01739589d GIT binary patch literal 66401 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 literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/body_dl2.jpg b/infosouth-admin/src/main/resources/static/oneself/images/body_dl2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d55dbbe09995f6322cda8df59f93ad2b70715a58 GIT binary patch literal 151307 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≈#HnaG8P``=9aBK|9QVKXS+K>v6BrGdWj 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 RlDR>$nn$+jg)lH!0{{zs67>K8 literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/close.png b/infosouth-admin/src/main/resources/static/oneself/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..06c1cf41f6121e8ce77b7abcb678fd1094c449bf GIT binary patch literal 820 zcmV-41Izr0P)}U_u{Bum+lzzAd$%uagx;7ro=n zy}z8~oI^BC!~cx<`=YtIndwcYevwMOR-4UEh;}@cOl|;lwjv92?-mymhwsT@1+5p` zx-I6Ksmtx{wWph!AW0GkAt;qfh;fd$%gc#uHq-rjVPWYA;8I6No73rfbJpvXi-iIj zPc?#43PLFeA&6~lL6&7~@mL|g`}OLpxfk;QKmnk$v(sX;+U6UaPWi(5R@}NdfcLAb z*iWaSsw!4jR&cGS2j^N^P-m}|trqK4*PSj_1yII%+-{d8dys|S?}y9f!pQJ2K5cH| z!^Q>%`ugDYdg1r`p{i*(>+5Un2loCdKyNVgN|Fe@UWdn_5Vp6s;cz%`e{>YL2M6Kv z`M^0xG#Z7;Y=*=n7>vdnRe&T=Pdpw+T2-OwbqE9>RUto~L*Wo=EG8UeGuYeRg(wK- zs*Q?{B`Kk`g+d;sQW3e_0Wz6P)g28QilriQxhw=KK$1jILQPc#OlAp%F(`~7pUWW_ z2*T&{A;x3ioTI_rfM6hqOgaOZ$zY6uDeU7 zgHEqN6vaJF6X$*jQXnwiO$GWqmD*?JQW^F-8$?lrAP6Xz%lNVrhs7k*a{9nuTFY_G^L<)uENwA#&0000-ATX1NqW_?xzaZMW$bzI)qR5Rzi=c&BZX$v_Q)78Sp`39pjhz{1#;=88_f5Ua z_ww-GenM-_|Cs#M5fMTuMHf<@G^?wt0B_;br!j=+H}dAa>QpNBW4`#YgXv<~YE)Kq z7aeKwyS8mdSZXgAKGD0ItlXCjYqr)Q3dg|D^cT^u^3D7dFGxy zr|iN-tiAil*90u#_jgA^A+-X4qIMaqEz2fTtZr!Xqu=B8bghgqTfgb4tA5)7Ed+^ZoSGXqafd==$0Ow8305^Uka-(s^87hU zYpM~#AU_@%Ui);UdAS2&Y|ednPazhi#BDOsaf)o@9V%G6TpYHUIMa#OTY{dSr!YMQ zQu@B1QK>kF;nxcbka5rpS@MYl-)?}`8lBCuluRKEz%W3{((gM^Rt%*;StK)gHuT=1 zxM2^DJ%(f36xG!e=)FVoivyO0PzqtG@Cv|it3II=>BS`icl+_|*okA?OmucI+1c?8 zQb*v{ZPE)4SPJcS_pbob9$$~J)T~RId>$Rev27;1PP3-69IwBE$+KNJVVlpRFK}5F zLdxh;j(a~n(#Mv=t=cdLGRc(6X;@Y6LzpH)2(;Fu=jM^ppvYI66`Dhp1NVo2d*#{V zNB5h8hd}vXv@;9(LRJ5R!9QvNV5Y6D%;ln88{!0-EkIlgVrcr(DW|7)Xej$vG5w2u Y1(}Hs6VG)aApigX07*qoM6N<$g8E8uIRF3v literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/grid-18px-masked.png b/infosouth-admin/src/main/resources/static/oneself/images/grid-18px-masked.png new file mode 100644 index 0000000000000000000000000000000000000000..1bc82b03ab97f8173d664744abf93e831fe92a07 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^Q49=>Ml8%gR!7*aO+ZRFz$e5NNaF|p|Nn<8;5jP$ z6v*K(3GxeOVCQ9IW@TdIX5nGr;^b(LY)J%Kz~SlQ7*Y}U_J)1lAp?nHiSmkf8osei ztYYL}Q9SM4G%dsG2Mj&3whAiS`a+k>H1^1#Y1ZdKVvdV%@=2YIXOud-d-8TSFsJN7 z#6NK2T)lcr^-Qhqth{*IqWe9+uab|=?QKi5d)G;4n(WG3#vf$gY2)X%O9&Kp Mp00i_>zopr02z0cQvd(} literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/input.png b/infosouth-admin/src/main/resources/static/oneself/images/input.png new file mode 100644 index 0000000000000000000000000000000000000000..73d431bbc3d7ffcba6beb86d406036ac2b06bcb7 GIT binary patch literal 903 zcmV;219<$2P)FNLf{{#dC1qB5L z1_lQQ2M7oV2?+@b3JMDg3k(bl4Gj$r4h|0w4-gO#5fKp*5)u;=6BHB_6%`d078Vy5 z7Z?~A85tQG8X6lL8yp-Q9UUDW9v&YbA0QwgAt50mA|fLrBP1jwB_$;$CMG8*CnzW= zDJdx`Dk>{0D=aK5EiElBE-o)GFEB7LF)=YRGBPtWGc+_bH8nLhHa0gmH#j&rIXO8x zIyyT$J3Kr*Jv}`>K0ZG`KR`f0K|w)6LPA4BLqtSGMMXtMMn*?RM@UFWNl8gcN=i#h zOH52mO-)TsPEJoxPf$=$QBhG+Qc_b>Q&dz`RaI41R#sP6S6EnBSy@?HT3TCMTU=aR zU0q#XUS3~cUtnNhVPRonVq#-sV`OAxWo2b%W@cw+XJ}|>X=!O{YHDk1Yiw+6ZEbCC zZf7mzbECnVFfInwp!No1C1Sot>SYo}QndpP-Ll?si~=|s;aB2tE{Z7t*x!DuCA}IuduMNv9YnTva++Y zv$V9dwY9ajwzjvox45{txw*Nzy1Ki&yS%)-y}iA@zP`V|zreu2!NI}8!otJD!^FhI z#l^+O#>U6T$H>UY$;rve%F4^j%goHo&CSiu&d$%z&(P4&(b3V;($dq@)6~?|)z#J3 z*4Ee8*Vx$D+1c6J+S=RO+uYpT-QC^Z-rnEe-{9cj;o;%p;^O1ulq(=H}<; z=jiC@>FMd}>gwz3>+J08?d|RE?(XmJ@9^;O@$vEU^78ZZ^Yrxe_4W1k_V)Mp_xSku z`T6fSKA`}HA1Hv~KMEM- d;^6`W7yvxaK7w5Rvi36k4^MgnE03g0ASI7 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 literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/jobResultShow_imgStep/step2.png b/infosouth-admin/src/main/resources/static/oneself/images/jobResultShow_imgStep/step2.png new file mode 100644 index 0000000000000000000000000000000000000000..866e3d6a29d58b8b2e58024d483700d8d49ca318 GIT binary patch literal 20949 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 Kb6Mw<&;$U@=gi~) literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/loading.gif b/infosouth-admin/src/main/resources/static/oneself/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..4574c238a3ee5ff6bcd2a361b908230b10367e3a GIT binary patch literal 3413 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 S*&H9U9UikEP9YEgyZ-^t%%z3^ literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/logo_dl.png b/infosouth-admin/src/main/resources/static/oneself/images/logo_dl.png new file mode 100644 index 0000000000000000000000000000000000000000..bc885ff0ec8a65f46cedfc2f15ae4e7263deaa51 GIT binary patch literal 7158 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 literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/logo_x.png b/infosouth-admin/src/main/resources/static/oneself/images/logo_x.png new file mode 100644 index 0000000000000000000000000000000000000000..d100d5a9470d9dbfcd4be5ae71ad8d9557a6d8b7 GIT binary patch literal 1357 zcmV-T1+w~yP)tPtNl=lh$03`rB+(CML%e<_+eE9tEg=QDk`>W@zrX5Au39t)v6UW zpy|U$A86dvXEyPXhnw|3^1m=#lHAGeM*6{lABTJQ%sDgX%*;7=omec^0i2IDE#=@n z;Itq^!EcSse-{)srmG*;#r$O-Xxjn~tc=;D$j=F3lVPAsAR|e}j|Bf39rzlIwm2c| zG7MM(0tpzO3f35n-v-)%u3#Zp1akeH5RMrJ|0zxf-U2rbesk5Yk-zWMxA)GQy z^nEjomk``xT>XvI$p_b(==X`A6At6wPl^o=6tTki$t}>IIxCD0ck`P(9sFe&XnrI5 z62}LO#(YklK_G1CFOf3BvJ*l!&j~-7jCs|H7OeV|q#9^}5f*W8v=*}EFY#2krcdEsvcu(B%#uapE_*#a; zT4Sz!12V1lBy#U5GA5$*U2Zh~Hj}(rwj_Fin_;|XWr3MK{nqhL!n{J{ zfz6(BdR5(#;v(glCyC1kV7;N=O0WZT03AUX98Y-mB!1WwFqy3vy!2$vovfYE(iUWZ zde8d+Xa!n>DsVSh6SjmC&s|S>O(+mA>EsC- z>PGp#6S%4>&>Ns1-^uUUAQjYrTOgC~c7gjKpE~mUQSi6N{@1{0o#m@pIqrkYs*+Um zx!Uu$Nnbvn1{=U0@Fmy+4yjYRQq3_1{J{6;z^7m_KmOg@s(ep(Vt={X?^YjPL0)6p zgURmr0p(RT+g_kAn5w*$=V5$q#r6@~E#OB!e+W8*Kfr!)5mc%<%D4j#cS}|}5A*;P zAOeEi6_G!|a;3WmoCHU}PVP*ucA}c?J+>8WZ+qIPr<~7bC~&2OMylT={AtBAoYCsi@v_VmK2s!quDw z7OIk1M(gM?!c7X=&K-PYZ>82=WtrBFBNb!s#b7UlPV!y(W`<)?}!kw&QX?4r?J*Cryi7C>K z<+ontWFf=wY;z0=#OZ*Py17i=c8u5cJfX)h1ZCxZ0rRLc8=O{SY-MBsmtvT zqnxzbi?iOm`wxcVNS5Y_rs~SJ?hD8AOxN~}=lag~{tpZahs2`sh)gP%%%<}RjY_A~ zs`ZM^YPa03_X`e-$K{!c!-#&s8qP< z_y`#((T literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/openclose.png b/infosouth-admin/src/main/resources/static/oneself/images/openclose.png new file mode 100644 index 0000000000000000000000000000000000000000..be9d0d2391ca9ad7b152541a8975f676e390fa04 GIT binary patch literal 3666 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 literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/openclose2.gif b/infosouth-admin/src/main/resources/static/oneself/images/openclose2.gif new file mode 100644 index 0000000000000000000000000000000000000000..0b17fa2c94f5e1d952174f61dc3b8032f48ab0f0 GIT binary patch literal 1093 zcmZ?wbhEHbRArE300PDT+U3h*4EC>&febM!NI}N(b37t$=TW2#l^+d)z!_-&E4JI z!^6YV)6>h#%iG)A$H&Ll*VoU_FEB7LBqSs4 zMWC|M^0KlDASy2hqRNVjs;a7*>gw9s+PeDshNi~m*4DO;j?S*muI{exp6;IB-oC!R z{{H?66DLfZG;#9eNmHgwo-$?1)TvXZO`SS@+O+A@r_Go?eddfAGiS}3J!j6`dGqEk zT(D^I;w8(LEnl^A_1d-THf`Lzb<5W6+qUo6z5|MO?AWRa#IeYfp`STYp zUc7Ya(&fvSuUx%)?b@~L*RS8WdE@4-o40P=x_ujnZr{Fh`wkkqd*|-GyZ7$jyZ`XP z!$*%EKY9G*>653=o;`p5{KX3(dhzn*%U59V`t|EKK=kI#TOfM-_8l0!fB*gi5PkUY z5ez8+7~uIJ=TAmFXijcqO>r!xt8CGZ=O#|XZw40-QFAb9fNZ-xW8RKCgK#E%Mq(~ y#ZBC)BsXH0?G?7zL*AE8%1xRR5LULf-AtXIXL*c);w8@0k3;9zSsrR&um%8}kN-3P literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/ruler.gif b/infosouth-admin/src/main/resources/static/oneself/images/ruler.gif new file mode 100644 index 0000000000000000000000000000000000000000..6dbcef8d9e640256fec10f8148ccca1067ec9a63 GIT binary patch literal 291 zcmZ?wbhEHbtYF}0*vtR||NsC0_xJz5fB%nP{BZo@`+q?0zrX*0{Qv*K@+gGjPZmZ7 z22KVYkSNFu29^s3Cp=g0wRnAY_j~4#y(yXV7Idu3dF}O3`@D(R^@@AS_soY50-l7+l&0T#`{GFtaV@P64MgrIL-A@(&RLjl3 zqh8ri-6&LF+Eh{7+T2yl-YLS?+rl_0W18@!&Y~GYbEi)3oxgbD9G2Q+xNXmly#ed?9on|x!0w}mk8L`*{m9;(o6j7$aQyQ1Ll@7Ux^wHq gmHlV#-#C5b@%e|(p4`3m;@#6-uTS24Ey!RE01r}>!~g&Q literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/so.gif b/infosouth-admin/src/main/resources/static/oneself/images/so.gif new file mode 100644 index 0000000000000000000000000000000000000000..598d920b5da4af71f117a938cd714ec89e71f7be GIT binary patch literal 221 zcmZ?wbhEHblw*)$IKsfN|K`<lWXWCKok!%-*o8tgY|#v(KHgmmIkHEIy~mH$28K zGR`w7JiD@C%bDwi4eirbZ8`J&3j@(W@h1ydtqzC;*~!2fm7vm>k~uG9)w-P5`wDc< zf5{SPR^Vv~lx}xoVBiqp+b6j&K}#T`xk1xl0Vji6!+|c{%!QYPrf$=5lshjO;K8FK f5o_vq+*?Cn>txya`ld3qjZMuht!?dUiVW5O#CJtj literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt1.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt1.png new file mode 100644 index 0000000000000000000000000000000000000000..d7245eaad16ad431e9f4190f189530a4da0f6fdb GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5^!3HEh?&5F8U}fi7AzZCsS>JivD=IIEGZ*dNX}5Z?l0wtKum>%}7<{CC-wHve8SVAmgf&8E~7<(AgYaJ<j`HXA~pVuCjGVx+v0t^QRPgg&ebxsLQ0AetMzW@LL literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt10.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt10.png new file mode 100644 index 0000000000000000000000000000000000000000..89c2a848e50e724ff2869f1ad19655ac051cc1f7 GIT binary patch literal 1181 zcmV;O1Y-M%P)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ=BS}O-RCwC#+k0r$WgN%xmzQNy+OoOGGS^)!vYS+z8ljbCEou^$NMKjH2ht6K zE>x67bTNgrf+DF=nFg!%M?pa&uq%?;O-pB>qGV`JU4Q((!^2oL=Q+Cb+w*}R=j?ZR zp0oG)KHu;2e4edWYip~duB&%KkN_rt319-4lmI4x319-4lmI4x319-4lmPBU_1)VY zwmer?%;pZlIE=wcyo=`ld#K{p`tk)>L=C{Rm>BPO;7Z(x@6!dRkQ$tWq4C9Ef?1dw_kD}icrPOHnVt^tkN`Ffmtwzm*SDde-MP=O z21lb8T6-$MQ}IB6>m3E+^N6xF7=asb9DXf$ZfFeS!{fOfJrUqEJdMFv5kvGNEXUsk z_toM){DE&!jeBq;hD2_hRceUc4d8WnF^a{!0Qtke+3Ai(&@h0r- z303$qJRhIwZruDI@I?L_i&wEB^55i$;3@bsD)SRPAp(bCeiVv_cjK2{5yQ4mL|NN# z{Sb9gk#EPBcs;KX*c%UF5bC3N?2dM#rGs487&)?UK&;6tz~Pu4)pd3e+ii{E-GEV; zlvjW=3nHee$ZfBW)F39;)g8F2+{8Q=&e;!q*rd^Thsn0yqqn*cb`F6#6kH z;cyI&$`imdA|ie-@v>`eypF_ad78#l#T4W(nYXv8ME$Ia*BWfkO9W2DRWX;Vmf28K z0%)Sz;$tq!N7v^1LNFUY%XGd zBO~Ab7Vy@Udlg<3>)!kE7#76&>EWi#!LmIJiVC~D!%4CFcniNMvbD7@0RANN`A&{y z+{}V&U*OR_X#04~h$8iA4A~iRtw9NV!F@Fk+z=5rRkk@aK(_x;8FRzcU1;+>ycW^6 z45#3VXm56`wR2@AY?Qgr7vX%o9K~Y+j@`|+hT!q|VkX$N*({~OAC9x*=aV{!%sQE+UlMi4ZOzTHzi(NB2V+Q|AhYGSM`c|Z z=c=M;^a(d-Y8Vp>aRKg{;21)~9HMwB*|vI0Y|^zW|uDk2GB0+^Hl vCV&ZG0+^HlCV&ZG0+^HlCV&ZGzV*)l7WdfxR?pc;00000NkvXXu0mjf`S~a} literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt11.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt11.png new file mode 100644 index 0000000000000000000000000000000000000000..704365ede7335d5bd6aec443047a66e4d7c3eecf GIT binary patch literal 725 zcmeAS@N?(olHy`uVBq!ia0vp^0YGfW!3HGvyr0t!q&N#aB8wRqxP?KOkzv*x380`t zvPY0F14ET614BbI1H;e%K>8&EL#Y7+!>a@a2CEqi4C48d;*Yv9Ffc`Xx;TbZ+$sJTRY!q?+^&zDxh;qT5riT z)}{y%N3Ch+Ear-Rj_xS6&ux{u*$LQZ6 ze?VG#x7W6h(iZ$Zv(~=WWPG!^kZFhfg>#}0bPeWY@vLG0_t(ZGWU9-*W=m~ucNu2w z)(7({Z(3YA{`IX3=Ld}ft_r@GO`JQKcCa7VEA;5jwAz+c>4&!m_X|Eqe$W)#ZRUAj zIfhg2QA6^91y?7}=X!cU@j=QOxr)Pab!3s~rsW8Z^ZJ(>8$zIJZl*JgBfQ;zP@^$ z>A^9*X;DX~z1|~UZ9L1JRro-T7K3@Ca&Fb_x#!;68eB^{tn^DINNkCpQSpX8hc1DH zWPYQ9NetU_WFEY~7RJH5^wufg%QiRmv7L#Wru$pj>Osrh{ocF}oFC|XXnJmdKI;Vst0JYyK AU;qFB literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt2.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt2.png new file mode 100644 index 0000000000000000000000000000000000000000..dcd503b1aed1beedcd375e701123171b3de3d103 GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5^!3HEh?&5F8U}fi7AzZCsS>Jir#y=IEGZ*dNbo9=OF`uw(3iaw*=?7Z2xev?*ZF2+nSEa zFF5vDySR0P`>1rB;4D|w{D08jd*`R`uT@`~ia2FV6Ih+5$SBajz@osw$l<`iG{MS& zPe=cP<+J`ZerId59#4Iu&iQAXj(D75*3azbJ1mu)hcv5RH*u_*<6N>PR#)M$d56yV z?4R3@b)P(NYeUD@^w>wHUo+ApBriA5c0BV}*6{Ar4eL(WTE`#nvfx$@y2JO$<;wDt z|1M8?VSDrEg~hHL<)U8phTk^%6j1qRVzus8CG~58m-1`x1m8(H{vYHZxZ6(kEoWe6 Z;Cz{NA!tqQ4xrZ=JYD@<);T3K0RW++h8U}fi7AzZCsS=07#M>*T^vIyZoRpo=)oK)bNu7oMQ2kAj07h88uA!si1ajf zi*2-eW8@Pi*nDt-LR01g~t# zzu)_xE3V=hB-t9aw#Oq_fHe?~CVXPEbZg1~+!v;(%v*ml6F3tzPV!6&31U{*cFA z;;@BYQA~OJEdOrX^X9v|tGE0YZLyvI?u3z^@h_8thR`>QbDxWUXj;bq`vilqWUbl8 z4)xpaZLEpxpJyE1#qY?sF*RFt?cT)OX2+Mw-haScJLgwWopr=v(_Nai^VVL8OO)C! zc5e4v+byp0OMk@PsO8xZ(l*z2b&UU`i%;9xs!~=da4kYYLEFA5A7E&Evec6IpQko3 P3K%?H{an^LB{Ts54Q{Wo literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt4.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt4.png new file mode 100644 index 0000000000000000000000000000000000000000..d028e09d299f9054dba08d3801929bb4fb32701c GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5^!3HEh?&5F8U}fi7AzZCsS>Jihg>!IEGZ*dUL~;ugO7xHQ|~7m$h`Y_BzMMj5}IbMco&E z5-^LdW_;f;_aj5ejEIi>$(kqHQWPb54w|1lt!7a8GvT`Z<tiyTfRyT;AK6 zoZ7N_ZqL#lyJL!eO`+Pl9lLL+PpUdz>!Vt&bn)I4sR?X5m3DqFxy0BrTYvWByGPG_ z3EuuvcjLcFyA-zHGt^Grx5QRx)g<{2`=%S5wMQo@-fY>YJY7t&WsUqNC%NLiJ08xz j0dX1Fc`dKB4>0UBJn-rA)T0`}Kw$86^>bP0l+XkKwrh<- literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt5.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt5.png new file mode 100644 index 0000000000000000000000000000000000000000..3378a62576ed6b485ede46286559ebe854ab7375 GIT binary patch literal 407 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5^!3HEh?&5F8U}fi7AzZCsS=07#J-*T^vIyZYBNs|KI*_0fP_EVV0h%lq<@MWE0IqfHdmDSH=dAfJav+PsYIfxbKZriQSl3w zif$8nb2>n4>!F29ujHs~v<%o-5Ou?IwL~S?5&i}XR*|rPIXp+EFD!Ci=Tw-<*;?OAV@6M1+kl{A!Nyw`WXhKRD%P z?gGh~BDS9#{_w7vo@5@N?RL%irGwSW#gRRG)QwYe7gVwP_WW7AfMto7um9Rd<#Mc5 s;(X7xUCRhBM-K{M=txwuC>&t8SG9yMCgNfvFr*ngUHx3vIVCg!0M**0!2kdN literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt6.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt6.png new file mode 100644 index 0000000000000000000000000000000000000000..92d1a00505402a671f45eed56957d6521a3d92d7 GIT binary patch literal 484 zcmeAS@N?(olHy`uVBq!ia0vp^MnJ5^!3HEh?&5F8U}fi7AzZCsS=07#Q0;T^vIyZoQfQF!!*6K4jPwW;V1=Wf z(JwtGp8Tsm!6dS~%Kg@)sF>>=w|6@%y}W)x)g*P+OX9D@zUy?e-+9eCUzhEXfn#&o z@mG;-g?!JJI4qeqO`TO^YUkC@LEIgm{{`pD%{17_m+LH*@M&U++TP9oWPep_PDpRO z@1Yj=@a%K*KaJ-9y0UkbtNeXnrMQjxMLBPp|I>gUhwr}#KgN5^m9u{f)BQJs(K`Rz zzvb-yyY_v|n?yOu2i-YY#f$roUdrN<4^94NeyR1R^7{y9!l8KyW zkTHJ(OYlwcI>~IGj$$_d&U{FlGg^mQV`Dz8~3-)wob z=IG<)QRk!noSCXVzvu|tSKeEar#S7yWtOx&I(qkGq!MSKeW|F6qX-O%@fC?CFtA8&EL#Y7+!>a@a2CEqi4C48d;*Yv9Ffj3Yx;TbZ+J+pdF}twH&tBd9zi~ES(}M+iee3d?9z9sn?6+(8&Yc`x3oJYxUEB|P zir??z*!So{u*TA?tl3L^>*ZUPI9E;5e|~RHwSHmDb=N=hg)}EPa87aH6cN&B1R^IU z)c_#!Sis_ya4|qE?Zfx06NMLuSFrD^;d_3gEY@!CO<~SP2lW8n9OnMA=DG(=OAjnK zs-ndt`+!MetIn6%r3pq}wGYG#k|l*$*6-{SEn`daeZBv=@6CN|H`x1{{ASb$%s9JM zpE>lJ=$T4^6-H`jzgm0#%`BX1Xm=^+`!}{bTFl1kY%z?{S%;)LQ+!Pg__o~q$X1}$ zcyA?hT4UMo+G+kw+zUDDZyEUeS~R!Ms@Ndk8sPp^TKIrr0f$K>+bh*cjB_34%Z4-Q zpE~g7_^Gd_9Nxc)e72YI{I+-xtz^GRzm8W5$7DZOjbMsu_?#p#!%Da|A=)V0e$QO- z`XA>-`!{m!K7Pe9{r!y!EN$nmkC$&1HKFL347F~PrA50 zSfM7|v`|z+dEc^$eNxpQkEj^f-aWGXeSNYWPvb29o(MKR2IB+HUT?2GE#$fDT2pH| zQDW->y^miXEE2fE$g`Zor{MeXoxKMFyezLU-1%L3u+PpcL>@gN7O-%EVrYuP!`}Cd Z3~keci)SoWy9P`|44$rjF6*2UngG5l|C9g# literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt8.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt8.png new file mode 100644 index 0000000000000000000000000000000000000000..d05496071f43dc96e5b4d30dfdc5b1009531bc84 GIT binary patch literal 1239 zcmV;|1StE7P)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ=T}ebiRCwC#+i8fEbri?(&x~W5wokNYwqm8WnGslFQ3SS^6c+7fo2>>#%Zq~Q zMK21a#f1thEGj67qRooR7Zqi+fQizci7lGD&h+B`1|GthiO{jR_kZAW@BQC<|Mz*m zbI$plbDld*?d|P~{da3F2nxUgumCIoixq$cU;$VF7ApV?zyh!UELH&aptWp{FI_wN zoSyost+6+5!(X@$3;RxdzP(oi>_K=lF%*Nb9-}Z8Uz8B;+78AyI1S5iS6~jomAyWM zH?a-FJLr$=F*)nU;Y{pX0CsM}@fP}G0-mb8HWEAF*?I$b0=C5({D|e4_aF8dftRo) zuD~;u*9PN!{Eipv3E%~o5`eG>OYwCcufr;=#80{ZCTk!41Kta0#l@Iad2O47@gcYh zE9wDYpTK)KFwVwk?36@5D&e*v`z@bYfYnjggRtWU;BA%fI0e%&E${F30PoJp4#2CJ zjaO0?^urdp@0+z|?2h9D_OJlkDMHoU-?{n zV692`u88PV;k9B$;LXG(n+o3lMTKYPCPnTMfp&LpD>lK19zv){cq7f&Wl)L$>$ zg*{pknXwUvV{l8>f5LMK&#yY!VkR-8jMpv0qzFm> zbjfp9(Kk(7#~nW(ylG7?Ab?c4)}3B z18h;76kn09;p=!=TW$;0=6d@jY^SEYnT}%v_6J-Z#h#IUzmEtVUC#gq;Of+Q>(gPh zVLR-S+$L+&QrjIBcti0}Lim8}GrY3*+^BGKJ%?~}`rVG2Z+pC}cFm$$?K(zFI*-pY z40r^41l$9ax^Pj-oUP-*10y1b*0YE#$AdY^X*e7c)6(6ccFp2_d=M|ZKSP7lEAXgY zD0)8OIy!4}vVUtm18h$pI~UhR7;cInT$MaFHD1^+Vlq2=Li%-l7V+q=tN1g8b_;f^{2}@^dMEN)a^*#p0=qN&J*nWVh|S`3D-8{BirV#$ zNrBUqeWG?r;Ea?+iyA$IJG|=Clp}+>0rFQ$o))!VA&lyYQC4plCfrvk_~&=?-gyBz zA)!B}5rzrf*@v07d>7B^%HBxc9D!5uWdT^L@2>ur;kYV!v)xAg^;LJ)RQ}zyzH?v! zSO69)01LnZumCJp02Y7+U;$XH04x9t!1}Vk2LRTG2Ai!_F`@tf002ovPDHLkV1m~2 BLrnkx literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/tmt9.png b/infosouth-admin/src/main/resources/static/oneself/images/tmt9.png new file mode 100644 index 0000000000000000000000000000000000000000..1e9211b2ca5f3e3997c04295dc55a1e07da5e525 GIT binary patch literal 1596 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 AnE(I) literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/userinfo.jpg b/infosouth-admin/src/main/resources/static/oneself/images/userinfo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..44bc2ada706e0ae68dc9330fae1fa8f5c420f501 GIT binary patch literal 3139 zcmbW2c{J4PAIHDb&@f~S#&%;STZ70FvWJEwF?K3TLXt$;*Ay}?u5F~UG{`c>Bukbe zOSVMHuB?d>WiU)*ncsBpJ@1P-iVMCa55F71?7b z|3J6v-nT09PXT`mbO6l8>XL&K%Ed~k`2x=zy@dM zJEClGkRR&?k?qy}0;<`-!;pjLa;2_Jf>h9_N@NsB(WOQtNVs>u+%fi>iCCV~&ePffhwN3xY z_{9YRz<*(};$L9@!3Ae=9bk=x4f2Z%bRd{zFr1D3i1I-`11!YNpI<`d4u^nY+LNkQ zPDxd(HN@qBL8zeAiCJmtFSI|&{yVVP|BLJ&uzzz+0Nh{@Yj|KdpbzXQ;?M;Le)*AP zg?~-Dk}Vc5H3Rx~o~%XRu24(3CuCvDefej1z3WX(%oAIpn(!+bR(A-O#pk&03%=tGQ~NefmKs841m~JT=g#hEnJ&;b4-b%ojuu~mcazB zAhRMNF0%U*8quC3l?A$rx6RD+ZJM(68N3CshrVAsd3?sBpiBPK<8@V~=p42hnI0W-dkSAIg%ETn3hN$xo>uNB&Tw`8Kk)xCO z^`|P9WOfq+C;1Z0-d1J!xyGvwTF6pbCH}*A`8eT|H)cjtdF&g$4dh(!+=~@oNS(i= zf2UYEvc#eX{UBW_9Ndb`->6XWF=`87rvexE=!c^)=7DajqGg3CuNF+72F2ntY8Ar0 z{t&=ofL|6XCEx)0Mc8C^yS7J6=z~>uh;q>w&U$$GOXZtu4<$v ziFDMu&g_wP{XPf>iRV&eDk5NNg#(o-E&}Xg zBDN&>;*4{?yL~NY8~p6}nVZMQ__qqz_|{6fekK4!3>OL(C~p(8r=|Bg~f{QOCbrvB3A? z$OuB#k4xQwd)=a8ev_>05mLm)S5bmW8J=}V{`it_G}cDMCS6c1xQo3yRw!1%!=V(@*%g90#DW@9j%s z3Pyh*yJtG>zHal@U@>7{dH>vy@;q{x14S$11tYF6Xp72SU9|@(+d_DTO2!M}?QKq5 z_4VBZ#7xQj!)lH%y-Dg%)E7SZK2AczKrNI)m^Fh(*N4m*hnEOidZFp>P&zvs++yTs zOO3B43#OXEiYQ%oWRVoU)EnLUs^8^#qM_az-P2d&@;o(F1!W8)O?9J12k&uH-`mAC zZjvM2D1)iTurrM`xwj9`tup~$I^XvWosrb7`yBns@rcDn{9~g(Y+_-k6ilR!grht9 zHLp(wRVao;GZlFvBl76GR!YhH6xxPJr{k(iZ80@)LoWl}m!-CHZC6((HQ%oLd#C&} zx?i!kz38&TvfW_IgaL1Zvz0-2*C=F@3Pn|1ZJO_5N<4*K1i?Cj5I?=g0IRS~9`HkWI3N_oO3ZI5Un zY}1seMCF;xylGOuI5t|~bkQK#SL|I)&oLFnFSoD9ix-Tt-%LE_;K5y?Jz|$sZa%YT zA)T{nmawkCmh`C9S`x>etl;%Hqok=LMUZ>3qE6y_0fvKwumZqjt`QLb>EfED&)*O?lu z=|qf3pzgMk>)xhkp(m@T^lzOt!GK#MnNV~Njf8`SI5;j6o zmAj=*$e5~-s!bD^qPcliidbnCS`MYm6cX?DKK{5Ht?_8)lIwA*qiO0JANl^dT=IFD zwc@^WV=yHC){+Bsow|8D>C#GA2y~(+^y2l?CO!h8vzEud$m`oRBkgT4U}3Ao`z7%y zWaloiW4dS82faTvtfiXfb)Cw_zDy)E4J~Z+K5IYb>IT|XiJq~Y_`s9-inu6e6DaeQ zk#BS!`q;+)6d@fK`-Xr+A4sV!qD+kBOUIXaBZh18!!(5?^$P3t=F^;AND)Ve6r@z> zUJi$Zd@iiyHn$n{>lIQ7I7<7xyjw1%w@WudL2h{%(Z^Y1AwpTfOvm3S2GdtBc|g{z z^FQPq>U>J7bAf&HPuu&(8BKqPCf|tnb}HXa*9jXBl=J(1{dsm+nrjt3+UbuS2eZ@x zUzZm(RF46{W}#Q&8(H^ZJ4<&l2)v{+k)2?isU)z_&v38&G^IywI1A(pe;I&5z*Zdq}?%FPN%+EWTH4=1@rZxKgpX<55>t f8#{rZ96p0EnUQ-VV6VP-)((nh{VOc%Gspi0kWIS= literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/userinfobig.jpg b/infosouth-admin/src/main/resources/static/oneself/images/userinfobig.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dec47e047822b5c910025e47201b436766973b55 GIT binary patch literal 9659 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 literal 0 HcmV?d00001 diff --git a/infosouth-admin/src/main/resources/static/oneself/images/xtb2.gif b/infosouth-admin/src/main/resources/static/oneself/images/xtb2.gif new file mode 100644 index 0000000000000000000000000000000000000000..002757cd6b8912f8c90dec8379b13ee4def621cc GIT binary patch literal 183 zcmV;o07(BwNk%w1VX6Qi0Du4heZl1a|NkNR1ONa4001li0002003ZMW0*-_csmtvT zqnxzbi|IkR`wxa3Q$-U+2F6
- +
查看更多
diff --git a/infosouth-arj21/src/main/java/cn/com/infosouth/arj21/controller/defaultIndex/DefaultIndexController.java b/infosouth-arj21/src/main/java/cn/com/infosouth/arj21/controller/defaultIndex/DefaultIndexController.java new file mode 100644 index 000000000..bba7901b4 --- /dev/null +++ b/infosouth-arj21/src/main/java/cn/com/infosouth/arj21/controller/defaultIndex/DefaultIndexController.java @@ -0,0 +1,204 @@ +package cn.com.infosouth.arj21.controller.defaultIndex; + +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import cn.com.infosouth.common.core.controller.BaseController; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +import cn.com.amas.job.HttpReqUriUtils; +import cn.com.infosouth.amas.modules.analysis.entity.InfoDutySchedule; +import cn.com.infosouth.amas.modules.analysis.service.InfoDutyScheduleService; +import cn.com.infosouth.amas.modules.csvmanager.service.InfoFlightService; +import cn.com.infosouth.amas.modules.parameter.service.computed.InfoParameterComputedService; +import cn.com.infosouth.amas.modules.virtual.entity.InfoVersion; +import cn.com.infosouth.amas.modules.virtual.service.InfoAcTypeService; +import cn.com.infosouth.amas.modules.virtual.service.InfoVersionService; +import org.slf4j.Logger; + +/** + * @ClassName: DefaultIndexController + * @Description:TODO(默认首页) + * @author: zy + * @date: 2018年3月14日 下午6:24:24 + * + * @Copyright: 2018 Inc. All rights reserved. + * 注意:本内容仅限深圳科信南方技术有限公司内部传阅,禁止外泄以及用于其他的商业目的 + */ +@Controller +@RequestMapping(value = "${adminPath}/defaultIndex/defaultIndex") +public class DefaultIndexController extends BaseController { + + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private InfoDutyScheduleService infoDutyScheduleService; + @Autowired + private InfoVersionService infoVersionService; + + @Autowired + private SystemService systemService; + + @Autowired + private InfoFlightService infoFlightService; + + @Autowired + private InfoAcTypeService infoAcTypeService; + + @Autowired + private InfoParameterComputedService infoParameterComputedService; + + private static String static_acType_C900 = "AC700"; + private static String static_acType_B737 = "AC737"; + private static String static_acType_A320 = "AC320"; + private static String static_acType_B777 = "AC777"; + private static String static_acType_A330 = "AC330"; + + + /** + * @Title: initAcType + * @Description: TODO(初始化机型) + * @param: @param acTypeListByAcTypeNo + * @return: void + * @throws + */ + public void initAcType(List> acTypeListByAcTypeNo){ + for (int i = 0; i < acTypeListByAcTypeNo.size(); i++) { + Map map = acTypeListByAcTypeNo.get(i); + if("1".equals(map.get("ac_type_no"))){ + static_acType_C900 = map.get("ac_tpye"); + } + if("2".equals(map.get("ac_type_no"))){ + static_acType_B737 = map.get("ac_tpye"); + } + if("3".equals(map.get("ac_type_no"))){ + static_acType_A320 = map.get("ac_tpye"); + } + if("4".equals(map.get("ac_type_no"))){ + static_acType_B777 = map.get("ac_tpye"); + } + if("5".equals(map.get("ac_type_no"))){ + static_acType_A330 = map.get("ac_tpye"); + } + } + } + + @RequiresPermissions("defaultIndex:defaultIndex:view") + @RequestMapping(value = {"list", ""}) + public String list(HttpServletRequest request, HttpServletResponse response, Model model) { + //机型列表 + List> acTypeListByAcTypeNo = infoAcTypeService.findacTpyeMapList(); + //初始化机型 + initAcType(acTypeListByAcTypeNo); + + List> infoDutyScheduleList_CRJ900 = infoDutyScheduleService.findInfoDutyScheduleMapList(static_acType_C900); + List> infoDutyScheduleList_B737 = infoDutyScheduleService.findInfoDutyScheduleMapList(static_acType_B737); + List> infoDutyScheduleList_A320 = infoDutyScheduleService.findInfoDutyScheduleMapList(static_acType_A320); + List> infoDutyScheduleList_B777 = infoDutyScheduleService.findInfoDutyScheduleMapList(static_acType_B777); + List> infoDutyScheduleList_A330 = infoDutyScheduleService.findInfoDutyScheduleMapList(static_acType_A330); + + + + InfoVersion infoVersion = new InfoVersion(); + List versionList = infoVersionService.findList(infoVersion); + + model.addAttribute("infoDutyScheduleList_CRJ900", infoDutyScheduleList_CRJ900); + model.addAttribute("infoDutyScheduleList_B737", infoDutyScheduleList_B737); + model.addAttribute("infoDutyScheduleList_A320", infoDutyScheduleList_A320); + model.addAttribute("infoDutyScheduleList_B777", infoDutyScheduleList_B777); + model.addAttribute("infoDutyScheduleList_A330", infoDutyScheduleList_A330); + + + //qar数量 + String qarCount = infoFlightService.findFlightCount(); + model.addAttribute("qarCount", qarCount); + + //qar数量 + String modelCount = infoParameterComputedService.findModelCount(); + model.addAttribute("modelCount", modelCount); + + //任务数量 + String jobCount = infoDutyScheduleService.findJobCount(); + model.addAttribute("jobCount", jobCount); + + model.addAttribute("versionList", versionList); + + //登录管理员名 + String login_admin = UserUtils.getUser().getLoginName(); + User currLoginUser = systemService.getUserByLoginName(login_admin); + //是否显示首页图表“设置”选项权限 + String isShowAdminSettingFlag = "0"; + if("1".equals(currLoginUser.getUserType())){ + isShowAdminSettingFlag = "1"; + } + model.addAttribute("isShowAdminSettingFlag", isShowAdminSettingFlag); + + //查询第一页的任务,top10 + List> infoDutyScheduleMapListTop10 = infoDutyScheduleService.findInfoDutyScheduleMapListTop10(); + JSONArray infoDutyScheduleMapListTop10JsonArr = JSONArray.parseArray(JSONObject.toJSONString(infoDutyScheduleMapListTop10)); + model.addAttribute("jobsTop10JsonArr", infoDutyScheduleMapListTop10JsonArr); + + //任务列表url + PropertiesLoader propertiesLoader = new PropertiesLoader("/defaultIndexConfig.properties"); + String marquee_scroll_text_url = propertiesLoader.getProperty("marquee_scroll_text_url"); + model.addAttribute("marquee_scroll_text_url", marquee_scroll_text_url); + + PropertiesLoader config = new PropertiesLoader("numberone.properties"); + String config_debug = config.getProperty("local.debug"); + if(config_debug.trim().equals("1")) + { + model.addAttribute("local_debug", "1"); + } + else { + model.addAttribute("local_debug", "0"); + } + + //model.addAttribute("acTypeListByAcTypeNo", acTypeListByAcTypeNo); + String acTypeListByAcTypeNoStr = ""; + acTypeListByAcTypeNoStr = static_acType_C900+","+static_acType_B737+","+static_acType_A320+","+static_acType_B777+","+static_acType_A330; + + model.addAttribute("acType_row1", static_acType_C900); + model.addAttribute("acType_row2", static_acType_B737); + model.addAttribute("acType_row3", static_acType_A320); + model.addAttribute("acType_row4", static_acType_B777); + model.addAttribute("acType_row5", static_acType_A330); + + model.addAttribute("acTypeListByAcTypeNoStr", acTypeListByAcTypeNoStr); + return "modules/defaultIndex/defaultIndexList"; + } + + + @RequiresPermissions("defaultIndex:defaultIndex:view") + @RequestMapping(value = {"infoDutyScheduleList", ""}) + public String infoDutyScheduleList(InfoDutySchedule infoDutySchedule, HttpServletRequest request, HttpServletResponse response, Model model) { + String userName = UserUtils.getUser().getLoginName(); + //按创建人排序,当前用户优先 + String orderBy = "(case when a.create_by='" + userName + "' then 1 ELSE IFNULL(a.create_by,2) END),a.update_date DESC"; + Page page = new Page(request, response); + page.setOrderBy(orderBy); + page = infoDutyScheduleService.findPage(page, infoDutySchedule); + InfoVersion infoVersion = new InfoVersion(); + List versionList = infoVersionService.findList(infoVersion); + model.addAttribute("versionList", versionList); + model.addAttribute("page", page); + HttpReqUriUtils httpReqUriUtils = new HttpReqUriUtils(); + httpReqUriUtils.setGetJobs_Status_Uri(); + model.addAttribute("getJobs_Status_Uri", httpReqUriUtils.getGetJobs_Status_Uri()); + return "modules/defaultIndex/defaultIndex_infoDutyScheduleList"; + } + + /*public List getAcTypeByAcTypeNo(){ + + }*/ + +}